From 41aa5ce3eb49705d26137ac2b34f5ad7cd43f2cf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 21:05:34 +0800 Subject: vim-patch:9.0.1246: code is indented more than necessary (#22006) Problem: Code is indented more than necessary. Solution: Use an early return where it makes sense. (Yegappan Lakshmanan, closes vim/vim#11887) https://github.com/vim/vim/commit/142ed77898facf8f423fee2717efee1749c55f9a Omit function_using_block_scopes(): only affects Vim9 script. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/userfunc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 22c5b1954d..6c6dc3fa43 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -760,13 +760,12 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) static bool func_remove(ufunc_T *fp) { hashitem_T *hi = hash_find(&func_hashtab, (char *)UF2HIKEY(fp)); - - if (!HASHITEM_EMPTY(hi)) { - hash_remove(&func_hashtab, hi); - return true; + if (HASHITEM_EMPTY(hi)) { + return false; } - return false; + hash_remove(&func_hashtab, hi); + return true; } static void func_clear_items(ufunc_T *fp) -- cgit From 30b29a36e80bfeed50bb6ea618401fe35100490f Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 9 Feb 2023 20:56:30 +0100 Subject: refactor(ui): remove some superfluous ui_flush() calls - mapping has no business saving and restoring the low-level UI cursor. The cursor will be put in a reasonable position after input is processed, chill out. - TUI handles output needed for suspend - vgetc() family of function does flushing --- src/nvim/eval/userfunc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 6c6dc3fa43..957733ecd5 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2150,8 +2150,7 @@ void ex_function(exarg_T *eap) } } msg_prt_line(FUNCLINE(fp, j), false); - ui_flush(); // show a line at a time - os_breakcheck(); + line_breakcheck(); // show multiple lines at a time! } if (!got_int) { msg_putchar('\n'); -- cgit From 4be6c6cf0ddf5e31d4103cb5df06651ba6f4897b Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 11:05:57 +0100 Subject: refactor: replace char_u with char (#21901) refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/eval/userfunc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 957733ecd5..2496cbc430 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -880,7 +880,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett fc->rettv = rettv; fc->level = ex_nesting_level; // Check if this function has a breakpoint. - fc->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, (linenr_T)0); + fc->breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0); fc->dbg_tick = debug_tick; // Set up fields for closure. @@ -1075,7 +1075,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett bool func_not_yet_profiling_but_should = do_profiling_yes - && !fp->uf_profiling && has_profiling(false, (char *)fp->uf_name, NULL); + && !fp->uf_profiling && has_profiling(false, fp->uf_name, NULL); if (func_not_yet_profiling_but_should) { started_profiling = true; @@ -1669,7 +1669,7 @@ static void list_func_head(ufunc_T *fp, int indent, bool force) if (fp->uf_name_exp != NULL) { msg_puts((const char *)fp->uf_name_exp); } else { - msg_puts((const char *)fp->uf_name); + msg_puts(fp->uf_name); } msg_putchar('('); int j; @@ -1999,10 +1999,10 @@ static void list_functions(regmatch_T *regmatch) todo--; if ((fp->uf_flags & FC_DEAD) == 0 && (regmatch == NULL - ? (!message_filtered((char *)fp->uf_name) + ? (!message_filtered(fp->uf_name) && !func_name_refcount(fp->uf_name)) : (!isdigit((uint8_t)(*fp->uf_name)) - && vim_regexec(regmatch, (char *)fp->uf_name, 0)))) { + && vim_regexec(regmatch, fp->uf_name, 0)))) { list_func_head(fp, false, false); if (changed != func_hashtab.ht_changed) { emsg(_("E454: function list was modified")); @@ -2194,7 +2194,7 @@ void ex_function(exarg_T *eap) j++; } if (arg[j] != NUL) { - emsg_funcname((char *)e_invarg2, arg); + emsg_funcname(e_invarg2, arg); } } // Disallow using the g: dict. @@ -2748,7 +2748,7 @@ char *get_user_func_name(expand_T *xp, int idx) } if (strlen(fp->uf_name) + 4 >= IOSIZE) { - return (char *)fp->uf_name; // Prevent overflow. + return fp->uf_name; // Prevent overflow. } cat_func_name(IObuff, fp); @@ -3228,7 +3228,7 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) // If breakpoints have been added/deleted need to check for it. if (fcp->dbg_tick != debug_tick) { - fcp->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, SOURCING_LNUM); + fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); fcp->dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { @@ -3258,9 +3258,9 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) // Did we encounter a breakpoint? if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM) { - dbg_breakpoint((char *)fp->uf_name, SOURCING_LNUM); + dbg_breakpoint(fp->uf_name, SOURCING_LNUM); // Find next breakpoint. - fcp->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, SOURCING_LNUM); + fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); fcp->dbg_tick = debug_tick; } -- cgit From 27177e581902967dcf4f2f426464da1b636ca420 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 14:14:24 +0100 Subject: refactor: reduce scope of locals as per the style guide (#22211) --- src/nvim/eval/userfunc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 2496cbc430..3c4cc34464 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -729,7 +729,6 @@ static void cleanup_function_call(funccall_T *fc) /// @param[in] force When true, we are exiting. static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) { - funccall_T **pfc; int i; if (fc == NULL) { @@ -738,7 +737,7 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) fc->fc_refcount--; if (force ? fc->fc_refcount <= 0 : !fc_referenced(fc)) { - for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) { + for (funccall_T **pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) { if (fc == *pfc) { *pfc = fc->caller; free_funccal_contents(fc); @@ -3289,7 +3288,6 @@ int func_has_abort(void *cookie) /// Changes "rettv" in-place. void make_partial(dict_T *const selfdict, typval_T *const rettv) { - char *fname; char *tofree = NULL; ufunc_T *fp; char fname_buf[FLEN_FIXED + 1]; @@ -3298,7 +3296,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL) { fp = rettv->vval.v_partial->pt_func; } else { - fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING + char *fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING ? rettv->vval.v_string : rettv->vval.v_partial->pt_name; // Translate "s:func" to the stored function name. @@ -3319,7 +3317,6 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) pt->pt_name = rettv->vval.v_string; } else { partial_T *ret_pt = rettv->vval.v_partial; - int i; // Partial: copy the function name, use selfdict and copy // args. Can't take over name or args, the partial might @@ -3335,7 +3332,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) size_t arg_size = sizeof(typval_T) * (size_t)ret_pt->pt_argc; pt->pt_argv = (typval_T *)xmalloc(arg_size); pt->pt_argc = ret_pt->pt_argc; - for (i = 0; i < pt->pt_argc; i++) { + for (int i = 0; i < pt->pt_argc; i++) { tv_copy(&ret_pt->pt_argv[i], &pt->pt_argv[i]); } } @@ -3641,14 +3638,13 @@ bool set_ref_in_func(char *name, ufunc_T *fp_in, int copyID) int error = FCERR_NONE; char fname_buf[FLEN_FIXED + 1]; char *tofree = NULL; - char *fname; bool abort = false; if (name == NULL && fp_in == NULL) { return false; } if (fp_in == NULL) { - fname = fname_trans_sid(name, fname_buf, &tofree, &error); + char *fname = fname_trans_sid(name, fname_buf, &tofree, &error); fp = find_func(fname); } if (fp != NULL) { -- cgit From 3ad845882413944a8d6ed3bd9da68c6b4cee0afb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 9 Mar 2023 13:47:01 +0800 Subject: vim-patch:8.2.1067: expression "!expr->func()" does not work (#22585) Problem: Expression "!expr->func()" does not work. Solution: Apply plus and minus earlier. (closes vim/vim#6348) https://github.com/vim/vim/commit/0b1cd52ff6bf690388f892be686a91721a082e55 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 3c4cc34464..13779f4173 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3075,8 +3075,7 @@ void ex_call(exarg_T *eap) } // Handle a function returning a Funcref, Dictionary or List. - if (handle_subscript((const char **)&arg, &rettv, true, true, - (const char *)name, (const char **)&name) + if (handle_subscript((const char **)&arg, &rettv, true, true) == FAIL) { failed = true; break; -- cgit From d510bfbc8e447b1a60d5ec7faaa8f440eb4ef56f Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 2 Apr 2023 10:11:42 +0200 Subject: refactor: remove char_u (#22829) Closes https://github.com/neovim/neovim/issues/459 --- src/nvim/eval/userfunc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 13779f4173..40bca9acc1 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -90,7 +90,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int * bool mustend = false; char *arg = *argp; char *p = arg; - char_u c; + uint8_t c; int i; if (newargs != NULL) { @@ -128,7 +128,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int * } if (newargs != NULL) { ga_grow(newargs, 1); - c = (char_u)(*p); + c = (uint8_t)(*p); *p = NUL; arg = xstrdup(arg); @@ -159,7 +159,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int * while (p > expr && ascii_iswhite(p[-1])) { p--; } - c = (char_u)(*p); + c = (uint8_t)(*p); *p = NUL; expr = xstrdup(expr); ((char **)(default_args->ga_data))[default_args->ga_len] = expr; -- cgit From 371823d407d7d7519735131bcad4670c62a731a7 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:13:53 +0200 Subject: refactor: make error message definitions const message.c functions now take const char * as a format. Error message definitions can be made const. --- src/nvim/eval/userfunc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 40bca9acc1..9f5d964075 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -65,11 +65,11 @@ static funccall_T *current_funccal = NULL; // item in it is still being used. static funccall_T *previous_funccal = NULL; -static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it"); -static char *e_funcdict = N_("E717: Dictionary entry already exists"); -static char *e_funcref = N_("E718: Funcref required"); -static char *e_nofunc = N_("E130: Unknown function: %s"); -static char e_no_white_space_allowed_before_str_str[] +static const char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it"); +static const char *e_funcdict = N_("E717: Dictionary entry already exists"); +static const char *e_funcref = N_("E718: Funcref required"); +static const char *e_nofunc = N_("E130: Unknown function: %s"); +static const char e_no_white_space_allowed_before_str_str[] = N_("E1068: No white space allowed before '%s': %s"); void func_init(void) @@ -421,9 +421,9 @@ char *deref_func_name(const char *name, int *lenp, partial_T **const partialp, b /// Give an error message with a function name. Handle things. /// -/// @param ermsg must be passed without translation (use N_() instead of _()). +/// @param errmsg must be passed without translation (use N_() instead of _()). /// @param name function name -void emsg_funcname(char *ermsg, const char *name) +void emsg_funcname(const char *errmsg, const char *name) { char *p; @@ -433,7 +433,7 @@ void emsg_funcname(char *ermsg, const char *name) p = (char *)name; } - semsg(_(ermsg), p); + semsg(_(errmsg), p); if (p != name) { xfree(p); -- cgit From 9408f2dcf7cade2631688300e9b58eed6bc5219a Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:40:57 +0200 Subject: refactor: remove redundant const char * casts --- src/nvim/eval/userfunc.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 9f5d964075..99e8859ae9 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1575,7 +1575,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t XFREE_CLEAR(name); funcname = "v:lua"; } - } else if (fp != NULL || !builtin_function((const char *)rfname, -1)) { + } else if (fp != NULL || !builtin_function(rfname, -1)) { // User defined function. if (fp == NULL) { fp = find_func(rfname); @@ -1589,8 +1589,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t fp = find_func(rfname); } // Try loading a package. - if (fp == NULL && script_autoload((const char *)rfname, strlen(rfname), - true) && !aborting()) { + if (fp == NULL && script_autoload(rfname, strlen(rfname), true) && !aborting()) { // Loaded a package, search for the function again. fp = find_func(rfname); } @@ -1666,7 +1665,7 @@ static void list_func_head(ufunc_T *fp, int indent, bool force) } msg_puts(force ? "function! " : "function "); if (fp->uf_name_exp != NULL) { - msg_puts((const char *)fp->uf_name_exp); + msg_puts(fp->uf_name_exp); } else { msg_puts(fp->uf_name); } @@ -1676,7 +1675,7 @@ static void list_func_head(ufunc_T *fp, int indent, bool force) if (j) { msg_puts(", "); } - msg_puts((const char *)FUNCARG(fp, j)); + msg_puts(FUNCARG(fp, j)); if (j >= fp->uf_args.ga_len - fp->uf_def_args.ga_len) { msg_puts(" = "); msg_puts(((char **)(fp->uf_def_args.ga_data)) @@ -1828,7 +1827,7 @@ char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, part len = (int)strlen(lv.ll_exp_name); name = deref_func_name(lv.ll_exp_name, &len, partial, flags & TFN_NO_AUTOLOAD); - if ((const char *)name == lv.ll_exp_name) { + if (name == lv.ll_exp_name) { name = NULL; } } else if (!(flags & TFN_NO_DEREF)) { @@ -1881,8 +1880,7 @@ char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, part lead = 0; // do nothing } else if (lead > 0) { lead = 3; - if ((lv.ll_exp_name != NULL && eval_fname_sid(lv.ll_exp_name)) - || eval_fname_sid((const char *)(*pp))) { + if ((lv.ll_exp_name != NULL && eval_fname_sid(lv.ll_exp_name)) || eval_fname_sid(*pp)) { // It's "s:" or "". if (current_sctx.sc_sid <= 0) { emsg(_(e_usingsid)); @@ -2209,7 +2207,7 @@ void ex_function(exarg_T *eap) if (KeyTyped && ui_has(kUICmdline)) { show_block = true; - ui_ext_cmdline_block_append(0, (const char *)eap->cmd); + ui_ext_cmdline_block_append(0, eap->cmd); } // find extra arguments "range", "dict", "abort" and "closure" @@ -2308,7 +2306,7 @@ void ex_function(exarg_T *eap) } if (show_block) { assert(indent >= 0); - ui_ext_cmdline_block_append((size_t)indent, (const char *)theline); + ui_ext_cmdline_block_append((size_t)indent, theline); } // Detect line continuation: SOURCING_LNUM increased more than one. @@ -2390,7 +2388,7 @@ void ex_function(exarg_T *eap) if (*p == '!') { p = skipwhite(p + 1); } - p += eval_fname_script((const char *)p); + p += eval_fname_script(p); xfree(trans_function_name(&p, true, 0, NULL, NULL)); if (*skipwhite(p) == '(') { if (nesting == MAX_FUNC_NESTING - 1) { @@ -2501,7 +2499,7 @@ void ex_function(exarg_T *eap) // If there are no errors, add the function if (fudi.fd_dict == NULL) { - v = find_var((const char *)name, strlen(name), &ht, false); + v = find_var(name, strlen(name), &ht, false); if (v != NULL && v->di_tv.v_type == VAR_FUNC) { emsg_funcname(N_("E707: Function name conflicts with variable: %s"), name); goto erret; @@ -2548,13 +2546,11 @@ void ex_function(exarg_T *eap) goto erret; } if (fudi.fd_di == NULL) { - if (value_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg, - TV_CSTRING)) { + if (value_check_lock(fudi.fd_dict->dv_lock, eap->arg, TV_CSTRING)) { // Can't add a function to a locked dictionary goto erret; } - } else if (value_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg, - TV_CSTRING)) { + } else if (value_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, TV_CSTRING)) { // Can't change an existing function if it is locked goto erret; } @@ -2595,7 +2591,7 @@ void ex_function(exarg_T *eap) if (fudi.fd_dict != NULL) { if (fudi.fd_di == NULL) { // Add new dict entry - fudi.fd_di = tv_dict_item_alloc((const char *)fudi.fd_newkey); + fudi.fd_di = tv_dict_item_alloc(fudi.fd_newkey); if (tv_dict_add(fudi.fd_dict, fudi.fd_di) == FAIL) { xfree(fudi.fd_di); xfree(fp); -- cgit From 04933b1ea968f958d2541dd65fd33ebb503caac3 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:08:16 +0200 Subject: refactor: remove redundant casts --- src/nvim/eval/userfunc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 99e8859ae9..9c1e8230a3 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -611,7 +611,7 @@ static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr) STRCPY(v->di_key, name); #endif v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; - hash_add(&dp->dv_hashtab, (char *)v->di_key); + hash_add(&dp->dv_hashtab, v->di_key); v->di_tv.v_type = VAR_NUMBER; v->di_tv.v_lock = VAR_FIXED; v->di_tv.vval.v_number = nr; @@ -2612,7 +2612,7 @@ void ex_function(exarg_T *eap) set_ufunc_name(fp, name); if (overwrite) { hi = hash_find(&func_hashtab, name); - hi->hi_key = (char *)UF2HIKEY(fp); + hi->hi_key = UF2HIKEY(fp); } else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) { xfree(fp); goto erret; @@ -2681,7 +2681,7 @@ int eval_fname_script(const char *const p) bool translated_function_exists(const char *name) { if (builtin_function(name, -1)) { - return find_internal_func((char *)name) != NULL; + return find_internal_func(name) != NULL; } return find_func(name) != NULL; } -- cgit From 2d78e656b715119ca11d131a1a932f22f1b4ad36 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:43:00 +0200 Subject: refactor: remove redundant casts --- src/nvim/eval/userfunc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 9c1e8230a3..f09da6b79b 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -758,7 +758,7 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) /// @return true if the entry was deleted, false if it wasn't found. static bool func_remove(ufunc_T *fp) { - hashitem_T *hi = hash_find(&func_hashtab, (char *)UF2HIKEY(fp)); + hashitem_T *hi = hash_find(&func_hashtab, UF2HIKEY(fp)); if (HASHITEM_EMPTY(hi)) { return false; } @@ -905,7 +905,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett STRCPY(name, "self"); #endif v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; - hash_add(&fc->l_vars.dv_hashtab, (char *)v->di_key); + hash_add(&fc->l_vars.dv_hashtab, v->di_key); v->di_tv.v_type = VAR_DICT; v->di_tv.v_lock = VAR_UNLOCKED; v->di_tv.vval.v_dict = selfdict; @@ -931,7 +931,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett STRCPY(name, "000"); #endif v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; - hash_add(&fc->l_avars.dv_hashtab, (char *)v->di_key); + hash_add(&fc->l_avars.dv_hashtab, v->di_key); v->di_tv.v_type = VAR_LIST; v->di_tv.v_lock = VAR_FIXED; v->di_tv.vval.v_list = &fc->l_varlist; @@ -1009,9 +1009,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // Named arguments can be accessed without the "a:" prefix in lambda // expressions. Add to the l: dict. tv_copy(&v->di_tv, &v->di_tv); - hash_add(&fc->l_vars.dv_hashtab, (char *)v->di_key); + hash_add(&fc->l_vars.dv_hashtab, v->di_key); } else { - hash_add(&fc->l_avars.dv_hashtab, (char *)v->di_key); + hash_add(&fc->l_avars.dv_hashtab, v->di_key); } if (ai >= 0 && ai < MAX_FUNC_ARGS) { @@ -1770,7 +1770,7 @@ char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, part semsg(_(e_invarg2), start); } } else { - *pp = (char *)find_name_end((char *)start, NULL, NULL, FNE_INCL_BR); + *pp = (char *)find_name_end(start, NULL, NULL, FNE_INCL_BR); } goto theend; } -- cgit From 8f69c5ed450337b9f77c50f9ee0d3eb32f649ca6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 07:11:59 +0800 Subject: vim-patch:8.2.{0695,0725,0734,0753,0818,0819,0822} (#23075) vim-patch:8.2.0695: Vim9: cannot define a function inside a function Problem: Vim9: cannot define a function inside a function. Solution: Initial support for :def inside :def. https://github.com/vim/vim/commit/04b12697838b232b8b17c553ccc74cf1f1bdb81c vim-patch:8.2.0725: Vim9: cannot call a function declared later in Vim9 script Problem: Vim9: cannot call a function declared later in Vim9 script. Solution: Make two passes through the script file. https://github.com/vim/vim/commit/09689a02840be40fa7bb10b1921fb5bc5b2908f1 vim-patch:8.2.0734: Vim9: leaking memory when using :finish Problem: Vim9: leaking memory when using :finish. Solution: Do not check for next line in third pass. https://github.com/vim/vim/commit/04816717dfea6e2469ff4c9d40f68b59aaf03724 vim-patch:8.2.0753: Vim9: expressions are evaluated in the discovery phase Problem: Vim9: expressions are evaluated in the discovery phase. Solution: Bail out if an expression is not a constant. Require a type for declared constants. https://github.com/vim/vim/commit/32e351179eacfc84f64cd5029e221582d400bb38 vim-patch:8.2.0818: Vim9: using a discovery phase doesn't work well Problem: Vim9: using a discovery phase doesn't work well. Solution: Remove the discovery phase, instead compile a function only when it is used. Add :defcompile to compile def functions earlier. https://github.com/vim/vim/commit/822ba24743af9ee1b5e7f656a7a61a38f3638bca vim-patch:8.2.0819: compiler warning for unused variable Problem: Compiler warning for unused variable. Solution: Remove the variable. https://github.com/vim/vim/commit/f40e51a880a95f94dbbbecc9476559506c2cc345 vim-patch:8.2.0822: Vim9: code left over from discovery phase Problem: Vim9: code left over from discovery phase. Solution: Remove the dead code. https://github.com/vim/vim/commit/2eec37926db6d31beb36f162ac00357a30c093c8 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f09da6b79b..f82ab08d2d 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -152,7 +152,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int * p = skipwhite(p) + 1; p = skipwhite(p); char *expr = p; - if (eval1(&p, &rettv, false) != FAIL) { + if (eval1(&p, &rettv, 0) != FAIL) { ga_grow(default_args, 1); // trim trailing whitespace @@ -463,7 +463,8 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_ if (*argp == ')' || *argp == ',' || *argp == NUL) { break; } - if (eval1(&argp, &argvars[argcount], funcexe->fe_evaluate) == FAIL) { + if (eval1(&argp, &argvars[argcount], + funcexe->fe_evaluate ? EVAL_EVALUATE : 0) == FAIL) { ret = FAIL; break; } @@ -972,7 +973,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett default_expr = ((char **)(fp->uf_def_args.ga_data)) [ai + fp->uf_def_args.ga_len]; - if (eval1(&default_expr, &def_rettv, true) == FAIL) { + if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL) { default_arg_err = true; break; } @@ -1109,7 +1110,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // A Lambda always has the command "return {expr}". It is much faster // to evaluate {expr} directly. ex_nesting_level++; - (void)eval1(&p, rettv, true); + (void)eval1(&p, rettv, EVAL_EVALUATE); ex_nesting_level--; } else { // call do_cmdline() to execute the lines @@ -2953,7 +2954,7 @@ void ex_return(exarg_T *eap) eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') - && eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) { + && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) != FAIL) { if (!eap->skip) { returning = do_return(eap, false, true, &rettv); } else { @@ -3004,7 +3005,7 @@ void ex_call(exarg_T *eap) // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif. emsg_skip++; - if (eval0(eap->arg, &rettv, &eap->nextcmd, false) != FAIL) { + if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL) { tv_clear(&rettv); } emsg_skip--; @@ -3071,7 +3072,7 @@ void ex_call(exarg_T *eap) } // Handle a function returning a Funcref, Dictionary or List. - if (handle_subscript((const char **)&arg, &rettv, true, true) + if (handle_subscript((const char **)&arg, &rettv, EVAL_EVALUATE, true) == FAIL) { failed = true; break; -- cgit From bd83b587b18bb6f2ac555a992fa5b7d907de7e79 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 07:22:01 +0800 Subject: vim-patch:8.2.1047: Vim9: script cannot use line continuation like :def function Problem: Vim9: script cannot use line continuation like in a :def function. Solution: Pass the getline function pointer to the eval() functions. Use it for addition and multiplication operators. https://github.com/vim/vim/commit/5409f5d8c95007216ae1190565a7a8ee9ebd7100 Omit source_nextline() and eval_next_non_blank(): Vim9 script only. N/A patches for version.c: vim-patch:8.2.1048: build failure without the eval feature Problem: Build failure without the eval feature. Solution: Add dummy typedef. https://github.com/vim/vim/commit/9d40c63c7dc8c3eb3886c58dcd334bc7f37eceba vim-patch:8.2.1052: build failure with older compilers Problem: Build failure with older compilers. Solution: Move declaration to start of block. https://github.com/vim/vim/commit/7acde51832f383f9a6d2e740cd0420b433ea841a Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f82ab08d2d..d994a31039 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -152,7 +152,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int * p = skipwhite(p) + 1; p = skipwhite(p); char *expr = p; - if (eval1(&p, &rettv, 0) != FAIL) { + if (eval1(&p, &rettv, NULL) != FAIL) { ga_grow(default_args, 1); // trim trailing whitespace @@ -455,6 +455,8 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_ typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments int argcount = 0; // number of arguments found + evalarg_T evalarg = { .eval_flags = funcexe->fe_evaluate ? EVAL_EVALUATE : 0 }; + // Get the arguments. argp = *arg; while (argcount < MAX_FUNC_ARGS @@ -463,8 +465,7 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_ if (*argp == ')' || *argp == ',' || *argp == NUL) { break; } - if (eval1(&argp, &argvars[argcount], - funcexe->fe_evaluate ? EVAL_EVALUATE : 0) == FAIL) { + if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) { ret = FAIL; break; } @@ -973,7 +974,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett default_expr = ((char **)(fp->uf_def_args.ga_data)) [ai + fp->uf_def_args.ga_len]; - if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL) { + if (eval1(&default_expr, &def_rettv, &EVALARG_EVALUATE) == FAIL) { default_arg_err = true; break; } @@ -1110,7 +1111,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // A Lambda always has the command "return {expr}". It is much faster // to evaluate {expr} directly. ex_nesting_level++; - (void)eval1(&p, rettv, EVAL_EVALUATE); + (void)eval1(&p, rettv, &EVALARG_EVALUATE); ex_nesting_level--; } else { // call do_cmdline() to execute the lines @@ -2948,13 +2949,15 @@ void ex_return(exarg_T *eap) return; } + evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE }; + if (eap->skip) { emsg_skip++; } eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') - && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) != FAIL) { + && eval0(arg, &rettv, &eap->nextcmd, &evalarg) != FAIL) { if (!eap->skip) { returning = do_return(eap, false, true, &rettv); } else { @@ -3005,7 +3008,7 @@ void ex_call(exarg_T *eap) // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif. emsg_skip++; - if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL) { + if (eval0(eap->arg, &rettv, &eap->nextcmd, NULL) != FAIL) { tv_clear(&rettv); } emsg_skip--; -- cgit From 8e2903d2fe810cfa3be41fc1e7a4d8394c84cf11 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 09:11:37 +0800 Subject: vim-patch:8.2.1049: Vim9: leaking memory when using continuation line Problem: Vim9: leaking memory when using continuation line. Solution: Keep a pointer to the continuation line in evalarg_T. Centralize checking for a next command. https://github.com/vim/vim/commit/b171fb179053fa631fec74911b5fb9374cb6a8a1 Omit eval_next_line(): Vim9 script only. vim-patch:8.2.1050: missing change in struct Problem: Missing change in struct. Solution: Add missing change. https://github.com/vim/vim/commit/65a8ed37f7bc61fbe5c612a7b0eb0dfc16ad3e11 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index d994a31039..fe0249ea3a 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2957,7 +2957,7 @@ void ex_return(exarg_T *eap) eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') - && eval0(arg, &rettv, &eap->nextcmd, &evalarg) != FAIL) { + && eval0(arg, &rettv, eap, &evalarg) != FAIL) { if (!eap->skip) { returning = do_return(eap, false, true, &rettv); } else { @@ -3008,7 +3008,7 @@ void ex_call(exarg_T *eap) // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif. emsg_skip++; - if (eval0(eap->arg, &rettv, &eap->nextcmd, NULL) != FAIL) { + if (eval0(eap->arg, &rettv, eap, NULL) != FAIL) { tv_clear(&rettv); } emsg_skip--; -- cgit From d927128fccad1c234e4b87321ff0d6392b9d69d5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:03:04 +0800 Subject: vim-patch:8.2.1071: Vim9: no line break allowed inside a lambda Problem: Vim9: no line break allowed inside a lambda. Solution: Handle line break inside a lambda in Vim9 script. https://github.com/vim/vim/commit/e40fbc2ca9fda07332a4da5af1fcaba91bed865b Omit skip_expr_concatenate(). Apply the change to skip_expr() instead. Omit eval_ga: Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index fe0249ea3a..b1cb53fec2 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -252,8 +252,9 @@ static void set_ufunc_name(ufunc_T *fp, char *name) /// Parse a lambda expression and get a Funcref from "*arg". /// /// @return OK or FAIL. Returns NOTDONE for dict or {expr}. -int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) +int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) { + const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE); garray_T newargs = GA_EMPTY_INIT_VALUE; garray_T *pnewargs; ufunc_T *fp = NULL; @@ -264,6 +265,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) char *s, *e; bool *old_eval_lavars = eval_lavars_used; bool eval_lavars = false; + char *tofree = NULL; // First, check if this is a lambda expression. "->" must exists. ret = get_function_args(&start, '-', NULL, NULL, NULL, true); @@ -291,10 +293,16 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) // Get the start and the end of the expression. *arg = skipwhite((*arg) + 1); s = *arg; - ret = skip_expr(arg); + ret = skip_expr(arg, evalarg); if (ret == FAIL) { goto errret; } + if (evalarg != NULL) { + // avoid that the expression gets freed when another line break follows + tofree = evalarg->eval_tofree; + evalarg->eval_tofree = NULL; + } + e = *arg; *arg = skipwhite(*arg); if (**arg != '}') { @@ -359,12 +367,14 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) } eval_lavars_used = old_eval_lavars; + xfree(tofree); return OK; errret: ga_clear_strings(&newargs); xfree(fp); xfree(pt); + xfree(tofree); eval_lavars_used = old_eval_lavars; return FAIL; } @@ -3075,8 +3085,7 @@ void ex_call(exarg_T *eap) } // Handle a function returning a Funcref, Dictionary or List. - if (handle_subscript((const char **)&arg, &rettv, EVAL_EVALUATE, true) - == FAIL) { + if (handle_subscript((const char **)&arg, &rettv, &EVALARG_EVALUATE, true) == FAIL) { failed = true; break; } -- cgit From 8729c41f44de3b164ad8d01bb3558c6400e27952 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:49:28 +0800 Subject: vim-patch:8.2.1080: Vim9: no line break allowed in a for loop Problem: Vim9: no line break allowed in a for loop. Solution: Skip line breaks in for command. https://github.com/vim/vim/commit/b7a78f7a6713f07d2fcad0b27dea22925c7b1cdf Omit *_break_count and skip_for_lines(): Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index b1cb53fec2..1f25b7fb36 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2996,6 +2996,7 @@ void ex_return(exarg_T *eap) if (eap->skip) { emsg_skip--; } + clear_evalarg(&evalarg, eap); } /// ":1,25call func(arg1, arg2)" function call. -- cgit From cf37630d1b1443427c13e0a35e0a12b39e1415db Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:24:50 +0800 Subject: vim-patch:8.2.1110: Vim9: line continuation does not work in function arguments Problem: Vim9: line continuation does not work in function arguments. Solution: Pass "evalarg" to get_func_tv(). Fix seeing double quoted string as comment. https://github.com/vim/vim/commit/e6b5324e3a3d354363f3c48e784c42ce3e77453f Omit skipwhite_and_linebreak_keep_string(): Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 1f25b7fb36..3fc34471bf 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -458,15 +458,14 @@ void emsg_funcname(const char *errmsg, const char *name) /// @param funcexe various values /// /// @return OK or FAIL. -int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_T *funcexe) +int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, evalarg_T *const evalarg, + funcexe_T *funcexe) { char *argp; int ret = OK; typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments int argcount = 0; // number of arguments found - evalarg_T evalarg = { .eval_flags = funcexe->fe_evaluate ? EVAL_EVALUATE : 0 }; - // Get the arguments. argp = *arg; while (argcount < MAX_FUNC_ARGS @@ -475,7 +474,7 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_ if (*argp == ')' || *argp == ',' || *argp == NUL) { break; } - if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) { + if (eval1(&argp, &argvars[argcount], evalarg) == FAIL) { ret = FAIL; break; } @@ -3013,16 +3012,19 @@ void ex_call(exarg_T *eap) bool failed = false; funcdict_T fudi; partial_T *partial = NULL; + evalarg_T evalarg; + fill_evalarg_from_eap(&evalarg, eap, eap->skip); if (eap->skip) { // trans_function_name() doesn't work well when skipping, use eval0() // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif. emsg_skip++; - if (eval0(eap->arg, &rettv, eap, NULL) != FAIL) { + if (eval0(eap->arg, &rettv, eap, &evalarg) != FAIL) { tv_clear(&rettv); } emsg_skip--; + clear_evalarg(&evalarg, eap); return; } @@ -3080,7 +3082,7 @@ void ex_call(exarg_T *eap) funcexe.fe_evaluate = true; funcexe.fe_partial = partial; funcexe.fe_selfdict = fudi.fd_dict; - if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL) { + if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) { failed = true; break; } @@ -3118,6 +3120,7 @@ void ex_call(exarg_T *eap) eap->nextcmd = check_nextcmd(arg); } } + clear_evalarg(&evalarg, eap); end: tv_dict_unref(fudi.fd_dict); -- cgit From cc7a50a9ae9384167bd0fc2ee2eb7f1b31842f27 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 15:05:12 +0800 Subject: vim-patch:8.2.1161: Vim9: using freed memory Problem: Vim9: using freed memory. Solution: Put pointer back in evalarg instead of freeing it. https://github.com/vim/vim/commit/8e2730a315b8b06192f5fc822dc218dbb3cff7ae Omit eval_tofree_lambda: Vim9 script only. N/A patches for version.c: vim-patch:8.2.1163: build error Problem: Build error. Solution: Add missing change to globals. https://github.com/vim/vim/commit/6e13530ca03dd9cad245221177dd65f712211448 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 3fc34471bf..9440ceb36e 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -261,15 +261,14 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) partial_T *pt = NULL; int varargs; int ret; - char *start = skipwhite(*arg + 1); - char *s, *e; bool *old_eval_lavars = eval_lavars_used; bool eval_lavars = false; char *tofree = NULL; // First, check if this is a lambda expression. "->" must exists. - ret = get_function_args(&start, '-', NULL, NULL, NULL, true); - if (ret == FAIL || *start != '>') { + char *s = skipwhite(*arg + 1); + ret = get_function_args(&s, '-', NULL, NULL, NULL, true); + if (ret == FAIL || *s != '>') { return NOTDONE; } @@ -292,8 +291,9 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) // Get the start and the end of the expression. *arg = skipwhite((*arg) + 1); - s = *arg; + char *start = *arg; ret = skip_expr(arg, evalarg); + char *end = *arg; if (ret == FAIL) { goto errret; } @@ -303,7 +303,6 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) evalarg->eval_tofree = NULL; } - e = *arg; *arg = skipwhite(*arg); if (**arg != '}') { semsg(_("E451: Expected }: %s"), *arg); @@ -325,11 +324,11 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) ga_grow(&newlines, 1); // Add "return " before the expression. - size_t len = (size_t)(7 + e - s + 1); + size_t len = (size_t)(7 + end - start + 1); p = xmalloc(len); ((char **)(newlines.ga_data))[newlines.ga_len++] = p; STRCPY(p, "return "); - xstrlcpy(p + 7, s, (size_t)(e - s) + 1); + xstrlcpy(p + 7, start, (size_t)(end - start) + 1); if (strstr(p + 7, "a:") == NULL) { // No a: variables are used for sure. flags |= FC_NOARGS; @@ -367,14 +366,22 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) } eval_lavars_used = old_eval_lavars; - xfree(tofree); + if (evalarg->eval_tofree == NULL) { + evalarg->eval_tofree = tofree; + } else { + xfree(tofree); + } return OK; errret: ga_clear_strings(&newargs); xfree(fp); xfree(pt); - xfree(tofree); + if (evalarg->eval_tofree == NULL) { + evalarg->eval_tofree = tofree; + } else { + xfree(tofree); + } eval_lavars_used = old_eval_lavars; return FAIL; } -- cgit From c804c7df0cf3259b4ee3e286293b43529c9e42d6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 15:24:57 +0800 Subject: vim-patch:8.2.1162: crash when using a lambda Problem: Crash when using a lambda. Solution: Check for evalarg to be NULL. https://github.com/vim/vim/commit/efaaaa683b7b0cebc128be5c0c257b9d6578ac96 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 9440ceb36e..f73d22243d 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -366,7 +366,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) } eval_lavars_used = old_eval_lavars; - if (evalarg->eval_tofree == NULL) { + if (evalarg != NULL && evalarg->eval_tofree == NULL) { evalarg->eval_tofree = tofree; } else { xfree(tofree); @@ -377,7 +377,7 @@ errret: ga_clear_strings(&newargs); xfree(fp); xfree(pt); - if (evalarg->eval_tofree == NULL) { + if (evalarg != NULL && evalarg->eval_tofree == NULL) { evalarg->eval_tofree = tofree; } else { xfree(tofree); -- cgit From e36806666fe3c5792c39f0f9127e6637a6ceb7f2 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 20:35:46 +0800 Subject: vim-patch:8.2.2138: Vim9: "exit_cb" causes Vim to exit (#23087) Problem: Vim9: "exit_cb" causes Vim to exit. Solution: Require white space after a command in Vim9 script. (closes vim/vim#7467) Also fix that Vim9 style heredoc was not always recognized. https://github.com/vim/vim/commit/b5b9480ee936ef4cd0e350c468ef8c5f42fa398b Omit EX_NONWHITE_OK, E1143, E1144: Vim9 script only. Cherry-pick test_vimscript.vim changes from patch 8.2.2141. Cherry-pick E1145 tag from Vim runtime. N/A patches for version.c: vim-patch:8.2.2140: build failure with tiny features Problem: Build failure with tiny features. Solution: Add #ifdef. https://github.com/vim/vim/commit/2a3cd3af455973d678f70303ebdd486f3478bc0d Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f73d22243d..178f9fd6b6 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -71,6 +71,8 @@ static const char *e_funcref = N_("E718: Funcref required"); static const char *e_nofunc = N_("E130: Unknown function: %s"); static const char e_no_white_space_allowed_before_str_str[] = N_("E1068: No white space allowed before '%s': %s"); +static const char e_missing_heredoc_end_marker_str[] + = N_("E1145: Missing heredoc end marker: %s"); void func_init(void) { @@ -2319,7 +2321,11 @@ void ex_function(exarg_T *eap) lines_left = Rows - 1; } if (theline == NULL) { - emsg(_("E126: Missing :endfunction")); + if (skip_until != NULL) { + semsg(_(e_missing_heredoc_end_marker_str), skip_until); + } else { + emsg(_("E126: Missing :endfunction")); + } goto erret; } if (show_block) { -- cgit From ae9654dd7336e263e18ca7da4a40a25ec684002d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 21:56:13 +0800 Subject: vim-patch:8.2.4055: Vim9: line break in expression causes v:errmsg to be fillec (#23090) Problem: Vim9: line break in expression causes v:errmsg to be filled. (Yegappan Lakshmanan) Solution: Do not give an error when skipping over an expression. https://github.com/vim/vim/commit/5e6b9882fe0218ae4878f6ad0561c8654a2277d8 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 178f9fd6b6..67c73924c8 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -474,6 +474,7 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, evalarg_ int ret = OK; typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments int argcount = 0; // number of arguments found + const bool evaluate = evalarg == NULL ? false : (evalarg->eval_flags & EVAL_EVALUATE); // Get the arguments. argp = *arg; @@ -515,7 +516,7 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, evalarg_ ret = call_func(name, len, rettv, argcount, argvars, funcexe); funcargs.ga_len -= i; - } else if (!aborting()) { + } else if (!aborting() && evaluate) { if (argcount == MAX_FUNC_ARGS) { emsg_funcname(N_("E740: Too many arguments for function %s"), name); } else { -- cgit From 3ad8c08acc506555667a070cf83c410ac9334f1e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 19:45:54 +0800 Subject: vim-patch:8.2.4770: cannot easily mix expression and heredoc Problem: Cannot easily mix expression and heredoc. Solution: Support in heredoc. (Yegappan Lakshmanan, closes vim/vim#10138) https://github.com/vim/vim/commit/efbfa867a146fcd93fdec2435597aa4ae7f1325c Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/userfunc.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 67c73924c8..67b1e53a35 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2483,10 +2483,19 @@ void ex_function(exarg_T *eap) && (!ASCII_ISALNUM(p[2]) || (p[2] == 't' && !ASCII_ISALNUM(p[3]))))) { p = skipwhite(arg + 3); - if (strncmp(p, "trim", 4) == 0) { - // Ignore leading white space. - p = skipwhite(p + 4); - heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline)); + while (true) { + if (strncmp(p, "trim", 4) == 0) { + // Ignore leading white space. + p = skipwhite(p + 4); + heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline)); + continue; + } + if (strncmp(p, "eval", 4) == 0) { + // Ignore leading white space. + p = skipwhite(p + 4); + continue; + } + break; } skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p)); do_concat = false; -- cgit From 9770dcf96d77d734e2b88fc693c0f4fa0a17ef74 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 15 Apr 2023 21:05:55 +0800 Subject: refactor: remove FC_DEAD It's for Vim9 script only. --- src/nvim/eval/userfunc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 67b1e53a35..9705bc93db 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2015,12 +2015,11 @@ static void list_functions(regmatch_T *regmatch) if (!HASHITEM_EMPTY(hi)) { ufunc_T *fp = HI2UF(hi); todo--; - if ((fp->uf_flags & FC_DEAD) == 0 - && (regmatch == NULL - ? (!message_filtered(fp->uf_name) - && !func_name_refcount(fp->uf_name)) - : (!isdigit((uint8_t)(*fp->uf_name)) - && vim_regexec(regmatch, fp->uf_name, 0)))) { + if (regmatch == NULL + ? (!message_filtered(fp->uf_name) + && !func_name_refcount(fp->uf_name)) + : (!isdigit((uint8_t)(*fp->uf_name)) + && vim_regexec(regmatch, fp->uf_name, 0))) { list_func_head(fp, false, false); if (changed != func_hashtab.ht_changed) { emsg(_("E454: function list was modified")); -- cgit From 68ca16c376bd8786ffc0c7ce7619b9a0ce5657e8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 08:54:07 +0800 Subject: vim-patch:8.2.3783: confusing error for using a variable as a function Problem: Confusing error for using a variable as a function. Solution: If a function is not found but there is a variable, give a more useful error. (issue vim/vim#9310) https://github.com/vim/vim/commit/2ef9156b4284e4a52613c36e3d4667245273a28d Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 9705bc93db..a348588106 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -65,6 +65,7 @@ static funccall_T *current_funccal = NULL; // item in it is still being used. static funccall_T *previous_funccal = NULL; +static const char *e_unknownfunc = N_("E117: Unknown function: %s"); static const char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it"); static const char *e_funcdict = N_("E717: Dictionary entry already exists"); static const char *e_funcref = N_("E718: Funcref required"); @@ -401,9 +402,11 @@ errret: /// is not needed. /// @param[in] no_autoload If true, do not source autoload scripts if function /// was not found. +/// @param[out] found_var If not NULL and a variable was found set it to true. /// /// @return name of the function. -char *deref_func_name(const char *name, int *lenp, partial_T **const partialp, bool no_autoload) +char *deref_func_name(const char *name, int *lenp, partial_T **const partialp, bool no_autoload, + bool *found_var) FUNC_ATTR_NONNULL_ARG(1, 2) { if (partialp != NULL) { @@ -411,18 +414,25 @@ char *deref_func_name(const char *name, int *lenp, partial_T **const partialp, b } dictitem_T *const v = find_var(name, (size_t)(*lenp), NULL, no_autoload); - if (v != NULL && v->di_tv.v_type == VAR_FUNC) { - if (v->di_tv.vval.v_string == NULL) { // just in case + if (v == NULL) { + return (char *)name; + } + typval_T *const tv = &v->di_tv; + if (found_var != NULL) { + *found_var = true; + } + + if (tv->v_type == VAR_FUNC) { + if (tv->vval.v_string == NULL) { // just in case *lenp = 0; return ""; } - *lenp = (int)strlen(v->di_tv.vval.v_string); - return v->di_tv.vval.v_string; + *lenp = (int)strlen(tv->vval.v_string); + return tv->vval.v_string; } - if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) { - partial_T *const pt = v->di_tv.vval.v_partial; - + if (tv->v_type == VAR_PARTIAL) { + partial_T *const pt = tv->vval.v_partial; if (pt == NULL) { // just in case *lenp = 0; return ""; @@ -1454,12 +1464,16 @@ varnumber_T callback_call_retnr(Callback *callback, int argcount, typval_T *argv /// Give an error message for the result of a function. /// Nothing if "error" is FCERR_NONE. -static void user_func_error(int error, const char *name) +static void user_func_error(int error, const char *name, funcexe_T *funcexe) FUNC_ATTR_NONNULL_ALL { switch (error) { case FCERR_UNKNOWN: - emsg_funcname(N_("E117: Unknown function: %s"), name); + if (funcexe->fe_found_var) { + semsg(_(e_not_callable_type_str), name); + } else { + emsg_funcname(e_unknownfunc, name); + } break; case FCERR_NOTMETHOD: emsg_funcname(N_("E276: Cannot use function as a method: %s"), name); @@ -1654,7 +1668,7 @@ theend: // Report an error unless the argument evaluation or function call has been // cancelled due to an aborting error, an interrupt, or an exception. if (!aborting()) { - user_func_error(error, (name != NULL) ? name : funcname); + user_func_error(error, (name != NULL) ? name : funcname, funcexe); } // clear the copies made from the partial @@ -1846,14 +1860,13 @@ char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, part // Check if the name is a Funcref. If so, use the value. if (lv.ll_exp_name != NULL) { len = (int)strlen(lv.ll_exp_name); - name = deref_func_name(lv.ll_exp_name, &len, partial, - flags & TFN_NO_AUTOLOAD); + name = deref_func_name(lv.ll_exp_name, &len, partial, flags & TFN_NO_AUTOLOAD, NULL); if (name == lv.ll_exp_name) { name = NULL; } } else if (!(flags & TFN_NO_DEREF)) { len = (int)(end - *pp); - name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD); + name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD, NULL); if (name == *pp) { name = NULL; } @@ -3070,7 +3083,8 @@ void ex_call(exarg_T *eap) // contents. For VAR_PARTIAL get its partial, unless we already have one // from trans_function_name(). len = (int)strlen(tofree); - name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, false); + bool found_var = false; + name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, false, &found_var); // Skip white space to allow ":call func ()". Not good, but required for // backward compatibility. @@ -3104,6 +3118,7 @@ void ex_call(exarg_T *eap) funcexe.fe_evaluate = true; funcexe.fe_partial = partial; funcexe.fe_selfdict = fudi.fd_dict; + funcexe.fe_found_var = found_var; if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) { failed = true; break; -- cgit From b75634e55ee4cdfee7917b29f39e3ca1307cb059 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 07:50:18 +0800 Subject: vim-patch:9.0.0370: cleaning up afterwards can make a function messy Problem: Cleaning up afterwards can make a function messy. Solution: Add the :defer command. https://github.com/vim/vim/commit/1d84f7608f1e41dad03b8cc7925895437775f7c0 Omit EX_EXPR_ARG: Vim9 script only. Make :def throw E319 to avoid confusing behavior. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 228 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 163 insertions(+), 65 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index a348588106..9853622ee0 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -53,6 +53,13 @@ # include "eval/userfunc.c.generated.h" #endif +/// structure used as item in "fc_defer" +typedef struct { + char *dr_name; ///< function name, allocated + typval_T dr_argvars[MAX_FUNC_ARGS + 1]; + int dr_argcount; +} defer_T; + static hashtab_T func_hashtab; // Used by get_func_tv() @@ -469,45 +476,62 @@ void emsg_funcname(const char *errmsg, const char *name) } } -/// Allocate a variable for the result of a function. -/// -/// @param name name of the function -/// @param len length of "name" or -1 to use strlen() -/// @param arg argument, pointing to the '(' -/// @param funcexe various values -/// -/// @return OK or FAIL. -int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, evalarg_T *const evalarg, - funcexe_T *funcexe) +/// Get function arguments at "*arg" and advance it. +/// Return them in "*argvars[MAX_FUNC_ARGS + 1]" and the count in "argcount". +static int get_func_arguments(char **arg, evalarg_T *const evalarg, int partial_argc, + typval_T *argvars, int *argcount) { - char *argp; + char *argp = *arg; int ret = OK; - typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments - int argcount = 0; // number of arguments found - const bool evaluate = evalarg == NULL ? false : (evalarg->eval_flags & EVAL_EVALUATE); // Get the arguments. - argp = *arg; - while (argcount < MAX_FUNC_ARGS - - (funcexe->fe_partial == NULL ? 0 : funcexe->fe_partial->pt_argc)) { + while (*argcount < MAX_FUNC_ARGS - partial_argc) { argp = skipwhite(argp + 1); // skip the '(' or ',' + if (*argp == ')' || *argp == ',' || *argp == NUL) { break; } - if (eval1(&argp, &argvars[argcount], evalarg) == FAIL) { + if (eval1(&argp, &argvars[*argcount], evalarg) == FAIL) { ret = FAIL; break; } - argcount++; + (*argcount)++; if (*argp != ',') { break; } } + + argp = skipwhite(argp); if (*argp == ')') { argp++; } else { ret = FAIL; } + *arg = argp; + return ret; +} + +/// Call a function and put the result in "rettv". +/// +/// @param name name of the function +/// @param len length of "name" or -1 to use strlen() +/// @param arg argument, pointing to the '(' +/// @param funcexe various values +/// +/// @return OK or FAIL. +int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, evalarg_T *const evalarg, + funcexe_T *funcexe) +{ + typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments + int argcount = 0; // number of arguments found + const bool evaluate = evalarg == NULL ? false : (evalarg->eval_flags & EVAL_EVALUATE); + + char *argp = *arg; + int ret = get_func_arguments(&argp, evalarg, + (funcexe->fe_partial == NULL + ? 0 + : funcexe->fe_partial->pt_argc), + argvars, &argcount); if (ret == OK) { int i = 0; @@ -1148,6 +1172,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); } + // Invoke functions added with ":defer". + handle_defer(); + RedrawingDisabled--; // when the function was aborted because of an error, return -1 @@ -1544,7 +1571,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t int argv_base = 0; partial_T *partial = funcexe->fe_partial; - // Initialize rettv so that it is safe for caller to invoke clear_tv(rettv) + // Initialize rettv so that it is safe for caller to invoke tv_clear(rettv) // even when call_func() returns FAIL. rettv->v_type = VAR_UNKNOWN; @@ -3033,7 +3060,115 @@ void ex_return(exarg_T *eap) clear_evalarg(&evalarg, eap); } +static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg, + funcexe_T *funcexe_init, evalarg_T *const evalarg) +{ + bool doesrange; + bool failed = false; + + for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { + if (eap->addr_count > 0) { // -V560 + if (lnum > curbuf->b_ml.ml_line_count) { + // If the function deleted lines or switched to another buffer + // the line number may become invalid. + emsg(_(e_invrange)); + break; + } + curwin->w_cursor.lnum = lnum; + curwin->w_cursor.col = 0; + curwin->w_cursor.coladd = 0; + } + *arg = startarg; + + funcexe_T funcexe = *funcexe_init; + funcexe.fe_doesrange = &doesrange; + typval_T rettv; + rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this + if (get_func_tv(name, -1, &rettv, arg, evalarg, &funcexe) == FAIL) { + failed = true; + break; + } + + // Handle a function returning a Funcref, Dictionary or List. + if (handle_subscript((const char **)arg, &rettv, &EVALARG_EVALUATE, true) == FAIL) { + failed = true; + break; + } + + tv_clear(&rettv); + if (doesrange) { + break; + } + + // Stop when immediately aborting on error, or when an interrupt + // occurred or an exception was thrown but not caught. + // get_func_tv() returned OK, so that the check for trailing + // characters below is executed. + if (aborting()) { + break; + } + } + + return failed; +} + +/// Core part of ":defer func(arg)". "arg" points to the "(" and is advanced. +/// +/// @return FAIL or OK. +static int ex_defer_inner(char *name, char **arg, evalarg_T *const evalarg) +{ + typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments + int argcount = 0; // number of arguments found + int ret = FAIL; + + if (current_funccal == NULL) { + semsg(_(e_str_not_inside_function), "defer"); + return FAIL; + } + if (get_func_arguments(arg, evalarg, false, argvars, &argcount) == FAIL) { + goto theend; + } + char *saved_name = xstrdup(name); + + if (current_funccal->fc_defer.ga_itemsize == 0) { + ga_init(¤t_funccal->fc_defer, sizeof(defer_T), 10); + } + defer_T *dr = GA_APPEND_VIA_PTR(defer_T, ¤t_funccal->fc_defer); + dr->dr_name = saved_name; + dr->dr_argcount = argcount; + while (argcount > 0) { + argcount--; + dr->dr_argvars[argcount] = argvars[argcount]; + } + ret = OK; + +theend: + while (--argcount >= 0) { + tv_clear(&argvars[argcount]); + } + return ret; +} + +/// Invoked after a function has finished: invoke ":defer" functions. +static void handle_defer(void) +{ + for (int idx = current_funccal->fc_defer.ga_len - 1; idx >= 0; idx--) { + defer_T *dr = ((defer_T *)current_funccal->fc_defer.ga_data) + idx; + funcexe_T funcexe = { .fe_evaluate = true }; + typval_T rettv; + rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this + call_func(dr->dr_name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe); + tv_clear(&rettv); + xfree(dr->dr_name); + for (int i = dr->dr_argcount - 1; i >= 0; i--) { + tv_clear(&dr->dr_argvars[i]); + } + } + ga_clear(¤t_funccal->fc_defer); +} + /// ":1,25call func(arg1, arg2)" function call. +/// ":defer func(arg1, arg2)" deferred function call. void ex_call(exarg_T *eap) { char *arg = eap->arg; @@ -3041,9 +3176,6 @@ void ex_call(exarg_T *eap) char *name; char *tofree; int len; - typval_T rettv; - linenr_T lnum; - bool doesrange; bool failed = false; funcdict_T fudi; partial_T *partial = NULL; @@ -3051,6 +3183,7 @@ void ex_call(exarg_T *eap) fill_evalarg_from_eap(&evalarg, eap, eap->skip); if (eap->skip) { + typval_T rettv; // trans_function_name() doesn't work well when skipping, use eval0() // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif. @@ -3089,59 +3222,24 @@ void ex_call(exarg_T *eap) // Skip white space to allow ":call func ()". Not good, but required for // backward compatibility. startarg = skipwhite(arg); - rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this. if (*startarg != '(') { semsg(_(e_missingparen), eap->arg); goto end; } - lnum = eap->line1; - for (; lnum <= eap->line2; lnum++) { - if (eap->addr_count > 0) { // -V560 - if (lnum > curbuf->b_ml.ml_line_count) { - // If the function deleted lines or switched to another buffer - // the line number may become invalid. - emsg(_(e_invrange)); - break; - } - curwin->w_cursor.lnum = lnum; - curwin->w_cursor.col = 0; - curwin->w_cursor.coladd = 0; - } + if (eap->cmdidx == CMD_defer) { arg = startarg; - + failed = ex_defer_inner(name, &arg, &evalarg) == FAIL; + } else { funcexe_T funcexe = FUNCEXE_INIT; - funcexe.fe_firstline = eap->line1; - funcexe.fe_lastline = eap->line2; - funcexe.fe_doesrange = &doesrange; - funcexe.fe_evaluate = true; funcexe.fe_partial = partial; funcexe.fe_selfdict = fudi.fd_dict; + funcexe.fe_firstline = eap->line1; + funcexe.fe_lastline = eap->line2; funcexe.fe_found_var = found_var; - if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) { - failed = true; - break; - } - - // Handle a function returning a Funcref, Dictionary or List. - if (handle_subscript((const char **)&arg, &rettv, &EVALARG_EVALUATE, true) == FAIL) { - failed = true; - break; - } - - tv_clear(&rettv); - if (doesrange) { - break; - } - - // Stop when immediately aborting on error, or when an interrupt - // occurred or an exception was thrown but not caught. - // get_func_tv() returned OK, so that the check for trailing - // characters below is executed. - if (aborting()) { - break; - } + funcexe.fe_evaluate = true; + failed = ex_call_inner(eap, name, &arg, startarg, &funcexe, &evalarg); } // When inside :try we need to check for following "| catch" or "| endtry". -- cgit From 0167649ce4071e60d985b65f3f9408ffb21cb58c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 11:07:48 +0800 Subject: vim-patch:9.0.0379: cleaning up after writefile() is a hassle Problem: Cleaning up after writefile() is a hassle. Solution: Add the 'D' flag to defer deleting the written file. Very useful in tests. https://github.com/vim/vim/commit/806a273f3c84ecd475913d901890bb1929be9a0a Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 9853622ee0..4b9bc1fdec 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -478,6 +478,7 @@ void emsg_funcname(const char *errmsg, const char *name) /// Get function arguments at "*arg" and advance it. /// Return them in "*argvars[MAX_FUNC_ARGS + 1]" and the count in "argcount". +/// On failure FAIL is returned but the "argvars[argcount]" are still set. static int get_func_arguments(char **arg, evalarg_T *const evalarg, int partial_argc, typval_T *argvars, int *argcount) { @@ -3119,16 +3120,28 @@ static int ex_defer_inner(char *name, char **arg, evalarg_T *const evalarg) { typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments int argcount = 0; // number of arguments found - int ret = FAIL; if (current_funccal == NULL) { semsg(_(e_str_not_inside_function), "defer"); return FAIL; } if (get_func_arguments(arg, evalarg, false, argvars, &argcount) == FAIL) { - goto theend; + while (--argcount >= 0) { + tv_clear(&argvars[argcount]); + } + return FAIL; } + add_defer(name, argcount, argvars); + return OK; +} + +/// Add a deferred call for "name" with arguments "argvars[argcount]". +/// Consumes "argvars[]". +/// Caller must check that current_funccal is not NULL. +void add_defer(char *name, int argcount_arg, typval_T *argvars) +{ char *saved_name = xstrdup(name); + int argcount = argcount_arg; if (current_funccal->fc_defer.ga_itemsize == 0) { ga_init(¤t_funccal->fc_defer, sizeof(defer_T), 10); @@ -3140,13 +3153,6 @@ static int ex_defer_inner(char *name, char **arg, evalarg_T *const evalarg) argcount--; dr->dr_argvars[argcount] = argvars[argcount]; } - ret = OK; - -theend: - while (--argcount >= 0) { - tv_clear(&argvars[argcount]); - } - return ret; } /// Invoked after a function has finished: invoke ":defer" functions. -- cgit From 335bef0c211dc962499814d248670ff17758a642 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 10:51:27 +0800 Subject: vim-patch:9.0.0390: cannot use a partial with :defer Problem: Cannot use a partial with :defer. Solution: Add the partial arguments before the other arguments. Disallow using a dictionary. https://github.com/vim/vim/commit/86d87256c4005c6215da5af2597fbf6f6304421f Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 4b9bc1fdec..e9e780747a 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -81,6 +81,8 @@ static const char e_no_white_space_allowed_before_str_str[] = N_("E1068: No white space allowed before '%s': %s"); static const char e_missing_heredoc_end_marker_str[] = N_("E1145: Missing heredoc end marker: %s"); +static const char e_cannot_use_partial_with_dictionary_for_defer[] + = N_("E1300: Cannot use a partial with dictionary for :defer"); void func_init(void) { @@ -3062,7 +3064,7 @@ void ex_return(exarg_T *eap) } static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg, - funcexe_T *funcexe_init, evalarg_T *const evalarg) + const funcexe_T *const funcexe_init, evalarg_T *const evalarg) { bool doesrange; bool failed = false; @@ -3116,16 +3118,32 @@ static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg, /// Core part of ":defer func(arg)". "arg" points to the "(" and is advanced. /// /// @return FAIL or OK. -static int ex_defer_inner(char *name, char **arg, evalarg_T *const evalarg) +static int ex_defer_inner(char *name, char **arg, const partial_T *const partial, + evalarg_T *const evalarg) { typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments + int partial_argc = 0; // number of partial arguments int argcount = 0; // number of arguments found if (current_funccal == NULL) { semsg(_(e_str_not_inside_function), "defer"); return FAIL; } - if (get_func_arguments(arg, evalarg, false, argvars, &argcount) == FAIL) { + if (partial != NULL) { + if (partial->pt_dict != NULL) { + emsg(_(e_cannot_use_partial_with_dictionary_for_defer)); + return FAIL; + } + if (partial->pt_argc > 0) { + partial_argc = partial->pt_argc; + for (int i = 0; i < partial_argc; i++) { + tv_copy(&partial->pt_argv[i], &argvars[i]); + } + } + } + int r = get_func_arguments(arg, evalarg, false, argvars + partial_argc, &argcount); + argcount += partial_argc; + if (r == FAIL) { while (--argcount >= 0) { tv_clear(&argvars[argcount]); } @@ -3236,7 +3254,7 @@ void ex_call(exarg_T *eap) if (eap->cmdidx == CMD_defer) { arg = startarg; - failed = ex_defer_inner(name, &arg, &evalarg) == FAIL; + failed = ex_defer_inner(name, &arg, partial, &evalarg) == FAIL; } else { funcexe_T funcexe = FUNCEXE_INIT; funcexe.fe_partial = partial; -- cgit From 7b05ddbb72717f995fedc81583d73f82c78c881d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 11:37:41 +0800 Subject: vim-patch:9.0.0397: :defer not tested with exceptions and ":qa!" Problem: :defer not tested with exceptions and ":qa!". Solution: Test :defer works when exceptions are thrown and when ":qa!" is used. Invoke the deferred calls on exit. https://github.com/vim/vim/commit/58779858fb5a82a3233af5d4237a3cece88c10d4 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index e9e780747a..0a8e5c349a 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1176,7 +1176,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett } // Invoke functions added with ":defer". - handle_defer(); + handle_defer_one(current_funccal); RedrawingDisabled--; @@ -3174,10 +3174,10 @@ void add_defer(char *name, int argcount_arg, typval_T *argvars) } /// Invoked after a function has finished: invoke ":defer" functions. -static void handle_defer(void) +static void handle_defer_one(funccall_T *funccal) { - for (int idx = current_funccal->fc_defer.ga_len - 1; idx >= 0; idx--) { - defer_T *dr = ((defer_T *)current_funccal->fc_defer.ga_data) + idx; + for (int idx = funccal->fc_defer.ga_len - 1; idx >= 0; idx--) { + defer_T *dr = ((defer_T *)funccal->fc_defer.ga_data) + idx; funcexe_T funcexe = { .fe_evaluate = true }; typval_T rettv; rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this @@ -3188,7 +3188,15 @@ static void handle_defer(void) tv_clear(&dr->dr_argvars[i]); } } - ga_clear(¤t_funccal->fc_defer); + ga_clear(&funccal->fc_defer); +} + +/// Called when exiting: call all defer functions. +void invoke_all_defer(void) +{ + for (funccall_T *funccal = current_funccal; funccal != NULL; funccal = funccal->caller) { + handle_defer_one(funccal); + } } /// ":1,25call func(arg1, arg2)" function call. -- cgit From f39b33ee491a4a8d4b08425e582dd0dd53617edf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 11:46:17 +0800 Subject: vim-patch:9.0.0411: only created files can be cleaned up with one call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Only created files can be cleaned up with one call. Solution: Add flags to mkdir() to delete with a deferred function. Expand the writefile() name to a full path to handle changing directory. https://github.com/vim/vim/commit/6f14da15ac900589f2f413d77898b9bff3b31ece vim-patch:8.2.3742: dec mouse test fails without gnome terminfo entry Problem: Dec mouse test fails without gnome terminfo entry. Solution: Check if there is a gnome entry. Also fix 'acd' test on MS-Windows. (Dominique Pellé, closes vim/vim#9282) https://github.com/vim/vim/commit/f589fd3e1047cdf90566b68aaf9a13389e54d26a Cherry-pick test_autochdir.vim changes from patch 9.0.0313. Cherry-pick test_autocmd.vim changes from patch 9.0.0323. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 0a8e5c349a..808fb316fe 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3153,6 +3153,17 @@ static int ex_defer_inner(char *name, char **arg, const partial_T *const partial return OK; } +/// Return true if currently inside a function call. +/// Give an error message and return FALSE when not. +bool can_add_defer(void) +{ + if (get_current_funccal() == NULL) { + semsg(_(e_str_not_inside_function), "defer"); + return false; + } + return true; +} + /// Add a deferred call for "name" with arguments "argvars[argcount]". /// Consumes "argvars[]". /// Caller must check that current_funccal is not NULL. -- cgit From b1a341a48a59bf489ffe492d69cfaeb94b87fd78 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 10:59:59 +0800 Subject: vim-patch:9.0.1446: unnecessary checks for the "skip" flag when skipping Problem: Unnecessary checks for the "skip" flag when skipping. Solution: Remove the unnecessary checks. (closes vim/vim#12254) https://github.com/vim/vim/commit/5299c0933f942c61bfd48064c91365e518fa868c --- src/nvim/eval/userfunc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 808fb316fe..f91962ac09 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3063,6 +3063,7 @@ void ex_return(exarg_T *eap) clear_evalarg(&evalarg, eap); } +/// Lower level implementation of "call". Only called when not skipping. static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg, const funcexe_T *const funcexe_init, evalarg_T *const evalarg) { @@ -3070,7 +3071,7 @@ static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg, bool failed = false; for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { - if (eap->addr_count > 0) { // -V560 + if (eap->addr_count > 0) { if (lnum > curbuf->b_ml.ml_line_count) { // If the function deleted lines or switched to another buffer // the line number may become invalid. -- cgit From 42e55ba009ecc14afa1b519c8de02cb30c0d1671 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 16:57:25 +0800 Subject: vim-patch:9.0.0398: members of funccall_T are inconsistently named (#23123) Problem: Members of funccall_T are inconsistently named. Solution: Use the "fc_" prefix for all members. https://github.com/vim/vim/commit/ca16c60f337ed33d5dd66a6e90aaf95b619c5e47 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 256 +++++++++++++++++++++++------------------------ 1 file changed, 128 insertions(+), 128 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f91962ac09..734a6655bb 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -235,9 +235,9 @@ static void register_closure(ufunc_T *fp) funccal_unref(fp->uf_scoped, fp, false); fp->uf_scoped = current_funccal; current_funccal->fc_refcount++; - ga_grow(¤t_funccal->fc_funcs, 1); - ((ufunc_T **)current_funccal->fc_funcs.ga_data) - [current_funccal->fc_funcs.ga_len++] = fp; + ga_grow(¤t_funccal->fc_ufuncs, 1); + ((ufunc_T **)current_funccal->fc_ufuncs.ga_data) + [current_funccal->fc_ufuncs.ga_len++] = fp; } /// @return a name for a lambda. Returned in static memory. @@ -678,8 +678,8 @@ static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr) /// Free "fc" static void free_funccal(funccall_T *fc) { - for (int i = 0; i < fc->fc_funcs.ga_len; i++) { - ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i]; + for (int i = 0; i < fc->fc_ufuncs.ga_len; i++) { + ufunc_T *fp = ((ufunc_T **)(fc->fc_ufuncs.ga_data))[i]; // When garbage collecting a funccall_T may be freed before the // function that references it, clear its uf_scoped field. @@ -689,9 +689,9 @@ static void free_funccal(funccall_T *fc) fp->uf_scoped = NULL; } } - ga_clear(&fc->fc_funcs); + ga_clear(&fc->fc_ufuncs); - func_ptr_unref(fc->func); + func_ptr_unref(fc->fc_func); xfree(fc); } @@ -701,13 +701,13 @@ static void free_funccal(funccall_T *fc) static void free_funccal_contents(funccall_T *fc) { // Free all l: variables. - vars_clear(&fc->l_vars.dv_hashtab); + vars_clear(&fc->fc_l_vars.dv_hashtab); // Free all a: variables. - vars_clear(&fc->l_avars.dv_hashtab); + vars_clear(&fc->fc_l_avars.dv_hashtab); // Free the a:000 variables. - TV_LIST_ITER(&fc->l_varlist, li, { + TV_LIST_ITER(&fc->fc_l_varlist, li, { tv_clear(TV_LIST_ITEM_TV(li)); }); @@ -721,11 +721,11 @@ static void cleanup_function_call(funccall_T *fc) bool may_free_fc = fc->fc_refcount <= 0; bool free_fc = true; - current_funccal = fc->caller; + current_funccal = fc->fc_caller; // Free all l: variables if not referred. - if (may_free_fc && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT) { - vars_clear(&fc->l_vars.dv_hashtab); + if (may_free_fc && fc->fc_l_vars.dv_refcount == DO_NOT_FREE_CNT) { + vars_clear(&fc->fc_l_vars.dv_hashtab); } else { free_fc = false; } @@ -733,25 +733,25 @@ static void cleanup_function_call(funccall_T *fc) // If the a:000 list and the l: and a: dicts are not referenced and // there is no closure using it, we can free the funccall_T and what's // in it. - if (may_free_fc && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) { - vars_clear_ext(&fc->l_avars.dv_hashtab, false); + if (may_free_fc && fc->fc_l_avars.dv_refcount == DO_NOT_FREE_CNT) { + vars_clear_ext(&fc->fc_l_avars.dv_hashtab, false); } else { free_fc = false; // Make a copy of the a: variables, since we didn't do that above. - TV_DICT_ITER(&fc->l_avars, di, { + TV_DICT_ITER(&fc->fc_l_avars, di, { tv_copy(&di->di_tv, &di->di_tv); }); } - if (may_free_fc && fc->l_varlist.lv_refcount // NOLINT(runtime/deprecated) + if (may_free_fc && fc->fc_l_varlist.lv_refcount // NOLINT(runtime/deprecated) == DO_NOT_FREE_CNT) { - fc->l_varlist.lv_first = NULL; // NOLINT(runtime/deprecated) + fc->fc_l_varlist.lv_first = NULL; // NOLINT(runtime/deprecated) } else { free_fc = false; // Make a copy of the a:000 items, since we didn't do that above. - TV_LIST_ITER(&fc->l_varlist, li, { + TV_LIST_ITER(&fc->fc_l_varlist, li, { tv_copy(TV_LIST_ITEM_TV(li), TV_LIST_ITEM_TV(li)); }); } @@ -764,7 +764,7 @@ static void cleanup_function_call(funccall_T *fc) // "fc" is still in use. This can happen when returning "a:000", // assigning "l:" to a global variable or defining a closure. // Link "fc" in the list for garbage collection later. - fc->caller = previous_funccal; + fc->fc_caller = previous_funccal; previous_funccal = fc; if (want_garbage_collect) { @@ -795,17 +795,17 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) fc->fc_refcount--; if (force ? fc->fc_refcount <= 0 : !fc_referenced(fc)) { - for (funccall_T **pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) { + for (funccall_T **pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->fc_caller) { if (fc == *pfc) { - *pfc = fc->caller; + *pfc = fc->fc_caller; free_funccal_contents(fc); return; } } } - for (i = 0; i < fc->fc_funcs.ga_len; i++) { - if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp) { - ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL; + for (i = 0; i < fc->fc_ufuncs.ga_len; i++) { + if (((ufunc_T **)(fc->fc_ufuncs.ga_data))[i] == fp) { + ((ufunc_T **)(fc->fc_ufuncs.ga_data))[i] = NULL; } } } @@ -899,7 +899,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett int save_did_emsg; static int depth = 0; dictitem_T *v; - int fixvar_idx = 0; // index in fixvar[] + int fixvar_idx = 0; // index in fc_fixvar[] int ai; bool islambda = false; char numbuf[NUMBUFLEN]; @@ -931,39 +931,39 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett line_breakcheck(); // prepare the funccall_T structure fc = xcalloc(1, sizeof(funccall_T)); - fc->caller = current_funccal; + fc->fc_caller = current_funccal; current_funccal = fc; - fc->func = fp; - fc->rettv = rettv; - fc->level = ex_nesting_level; + fc->fc_func = fp; + fc->fc_rettv = rettv; + fc->fc_level = ex_nesting_level; // Check if this function has a breakpoint. - fc->breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0); - fc->dbg_tick = debug_tick; + fc->fc_breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0); + fc->fc_dbg_tick = debug_tick; // Set up fields for closure. - ga_init(&fc->fc_funcs, sizeof(ufunc_T *), 1); + ga_init(&fc->fc_ufuncs, sizeof(ufunc_T *), 1); func_ptr_ref(fp); if (strncmp(fp->uf_name, "", 8) == 0) { islambda = true; } - // Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables + // Note about using fc->fc_fixvar[]: This is an array of FIXVAR_CNT variables // with names up to VAR_SHORT_LEN long. This avoids having to alloc/free // each argument variable and saves a lot of time. // // Init l: variables. - init_var_dict(&fc->l_vars, &fc->l_vars_var, VAR_DEF_SCOPE); + init_var_dict(&fc->fc_l_vars, &fc->fc_l_vars_var, VAR_DEF_SCOPE); if (selfdict != NULL) { // Set l:self to "selfdict". Use "name" to avoid a warning from // some compiler that checks the destination size. - v = (dictitem_T *)&fc->fixvar[fixvar_idx++]; + v = (dictitem_T *)&fc->fc_fixvar[fixvar_idx++]; #ifndef __clang_analyzer__ name = (char *)v->di_key; STRCPY(name, "self"); #endif v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; - hash_add(&fc->l_vars.dv_hashtab, v->di_key); + hash_add(&fc->fc_l_vars.dv_hashtab, v->di_key); v->di_tv.v_type = VAR_DICT; v->di_tv.v_lock = VAR_UNLOCKED; v->di_tv.vval.v_dict = selfdict; @@ -973,38 +973,38 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // Init a: variables, unless none found (in lambda). // Set a:0 to "argcount" less number of named arguments, if >= 0. // Set a:000 to a list with room for the "..." arguments. - init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE); + init_var_dict(&fc->fc_l_avars, &fc->fc_l_avars_var, VAR_SCOPE); if ((fp->uf_flags & FC_NOARGS) == 0) { - add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], "0", + add_nr_var(&fc->fc_l_avars, (dictitem_T *)&fc->fc_fixvar[fixvar_idx++], "0", (varnumber_T)(argcount >= fp->uf_args.ga_len ? argcount - fp->uf_args.ga_len : 0)); } - fc->l_avars.dv_lock = VAR_FIXED; + fc->fc_l_avars.dv_lock = VAR_FIXED; if ((fp->uf_flags & FC_NOARGS) == 0) { // Use "name" to avoid a warning from some compiler that checks the // destination size. - v = (dictitem_T *)&fc->fixvar[fixvar_idx++]; + v = (dictitem_T *)&fc->fc_fixvar[fixvar_idx++]; #ifndef __clang_analyzer__ name = (char *)v->di_key; STRCPY(name, "000"); #endif v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; - hash_add(&fc->l_avars.dv_hashtab, v->di_key); + hash_add(&fc->fc_l_avars.dv_hashtab, v->di_key); v->di_tv.v_type = VAR_LIST; v->di_tv.v_lock = VAR_FIXED; - v->di_tv.vval.v_list = &fc->l_varlist; + v->di_tv.vval.v_list = &fc->fc_l_varlist; } - tv_list_init_static(&fc->l_varlist); - tv_list_set_lock(&fc->l_varlist, VAR_FIXED); + tv_list_init_static(&fc->fc_l_varlist); + tv_list_set_lock(&fc->fc_l_varlist, VAR_FIXED); // Set a:firstline to "firstline" and a:lastline to "lastline". // Set a:name to named arguments. // Set a:N to the "..." arguments. // Skipped when no a: variables used (in lambda). if ((fp->uf_flags & FC_NOARGS) == 0) { - add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], + add_nr_var(&fc->fc_l_avars, (dictitem_T *)&fc->fc_fixvar[fixvar_idx++], "firstline", (varnumber_T)firstline); - add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], + add_nr_var(&fc->fc_l_avars, (dictitem_T *)&fc->fc_fixvar[fixvar_idx++], "lastline", (varnumber_T)lastline); } bool default_arg_err = false; @@ -1045,7 +1045,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett name = numbuf; } if (fixvar_idx < FIXVAR_CNT && strlen(name) <= VAR_SHORT_LEN) { - v = (dictitem_T *)&fc->fixvar[fixvar_idx++]; + v = (dictitem_T *)&fc->fc_fixvar[fixvar_idx++]; v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; } else { v = xmalloc(sizeof(dictitem_T) + strlen(name)); @@ -1067,17 +1067,17 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // Named arguments can be accessed without the "a:" prefix in lambda // expressions. Add to the l: dict. tv_copy(&v->di_tv, &v->di_tv); - hash_add(&fc->l_vars.dv_hashtab, v->di_key); + hash_add(&fc->fc_l_vars.dv_hashtab, v->di_key); } else { - hash_add(&fc->l_avars.dv_hashtab, v->di_key); + hash_add(&fc->fc_l_avars.dv_hashtab, v->di_key); } if (ai >= 0 && ai < MAX_FUNC_ARGS) { - listitem_T *li = &fc->l_listitems[ai]; + listitem_T *li = &fc->fc_l_listitems[ai]; *TV_LIST_ITEM_TV(li) = argvars[i]; TV_LIST_ITEM_TV(li)->v_lock = VAR_FIXED; - tv_list_append(&fc->l_varlist, li); + tv_list_append(&fc->fc_l_varlist, li); } } @@ -1142,7 +1142,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett bool func_or_func_caller_profiling = do_profiling_yes && (fp->uf_profiling - || (fc->caller != NULL && fc->caller->func->uf_profiling)); + || (fc->fc_caller != NULL && fc->fc_caller->fc_func->uf_profiling)); if (func_or_func_caller_profiling) { fp->uf_tm_count++; @@ -1194,11 +1194,11 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett fp->uf_tm_total = profile_add(fp->uf_tm_total, call_start); fp->uf_tm_self = profile_self(fp->uf_tm_self, call_start, fp->uf_tm_children); - if (fc->caller != NULL && fc->caller->func->uf_profiling) { - fc->caller->func->uf_tm_children = - profile_add(fc->caller->func->uf_tm_children, call_start); - fc->caller->func->uf_tml_children = - profile_add(fc->caller->func->uf_tml_children, call_start); + if (fc->fc_caller != NULL && fc->fc_caller->fc_func->uf_profiling) { + fc->fc_caller->fc_func->uf_tm_children = + profile_add(fc->fc_caller->fc_func->uf_tm_children, call_start); + fc->fc_caller->fc_func->uf_tml_children = + profile_add(fc->fc_caller->fc_func->uf_tml_children, call_start); } if (started_profiling) { // make a ":profdel func" stop profiling the function @@ -1213,9 +1213,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett if (aborting()) { smsg(_("%s aborted"), SOURCING_NAME); - } else if (fc->rettv->v_type == VAR_NUMBER) { + } else if (fc->fc_rettv->v_type == VAR_NUMBER) { smsg(_("%s returning #%" PRId64 ""), - SOURCING_NAME, (int64_t)fc->rettv->vval.v_number); + SOURCING_NAME, (int64_t)fc->fc_rettv->vval.v_number); } else { char buf[MSG_BUF_LEN]; @@ -1223,7 +1223,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // have some idea how it starts and ends. smsg() would always // truncate it at the end. Don't want errors such as E724 here. emsg_off++; - char *s = encode_tv2string(fc->rettv, NULL); + char *s = encode_tv2string(fc->fc_rettv, NULL); char *tofree = s; emsg_off--; if (s != NULL) { @@ -1361,7 +1361,7 @@ void free_all_functions(void) // Clean up the current_funccal chain and the funccal stack. while (current_funccal != NULL) { - tv_clear(current_funccal->rettv); + tv_clear(current_funccal->fc_rettv); cleanup_function_call(current_funccal); // -V595 if (current_funccal == NULL && funccal_stack != NULL) { restore_funccal(); @@ -2994,10 +2994,10 @@ static inline bool fc_referenced(const funccall_T *const fc) FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - return ((fc->l_varlist.lv_refcount // NOLINT(runtime/deprecated) + return ((fc->fc_l_varlist.lv_refcount // NOLINT(runtime/deprecated) != DO_NOT_FREE_CNT) - || fc->l_vars.dv_refcount != DO_NOT_FREE_CNT - || fc->l_avars.dv_refcount != DO_NOT_FREE_CNT + || fc->fc_l_vars.dv_refcount != DO_NOT_FREE_CNT + || fc->fc_l_avars.dv_refcount != DO_NOT_FREE_CNT || fc->fc_refcount > 0); } @@ -3005,9 +3005,9 @@ static inline bool fc_referenced(const funccall_T *const fc) /// referenced from anywhere that is in use. static int can_free_funccal(funccall_T *fc, int copyID) { - return fc->l_varlist.lv_copyID != copyID - && fc->l_vars.dv_copyID != copyID - && fc->l_avars.dv_copyID != copyID + return fc->fc_l_varlist.lv_copyID != copyID + && fc->fc_l_vars.dv_copyID != copyID + && fc->fc_l_avars.dv_copyID != copyID && fc->fc_copyID != copyID; } @@ -3206,7 +3206,7 @@ static void handle_defer_one(funccall_T *funccal) /// Called when exiting: call all defer functions. void invoke_all_defer(void) { - for (funccall_T *funccal = current_funccal; funccal != NULL; funccal = funccal->caller) { + for (funccall_T *funccal = current_funccal; funccal != NULL; funccal = funccal->fc_caller) { handle_defer_one(funccal); } } @@ -3323,7 +3323,7 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) if (reanimate) { // Undo the return. - current_funccal->returned = false; + current_funccal->fc_returned = false; } // Cleanup (and deactivate) conditionals, but stop when a try conditional @@ -3343,8 +3343,8 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) // When undoing a return in order to make it pending, get the stored // return rettv. if (reanimate) { - assert(current_funccal->rettv); - rettv = current_funccal->rettv; + assert(current_funccal->fc_rettv); + rettv = current_funccal->fc_rettv; } if (rettv != NULL) { @@ -3359,20 +3359,20 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) // The pending return value could be overwritten by a ":return" // without argument in a finally clause; reset the default // return value. - current_funccal->rettv->v_type = VAR_NUMBER; - current_funccal->rettv->vval.v_number = 0; + current_funccal->fc_rettv->v_type = VAR_NUMBER; + current_funccal->fc_rettv->vval.v_number = 0; } } report_make_pending(CSTP_RETURN, rettv); } else { - current_funccal->returned = true; + current_funccal->fc_returned = true; // If the return is carried out now, store the return value. For // a return immediately after reanimation, the value is already // there. if (!reanimate && rettv != NULL) { - tv_clear(current_funccal->rettv); - *current_funccal->rettv = *(typval_T *)rettv; + tv_clear(current_funccal->fc_rettv); + *current_funccal->fc_rettv = *(typval_T *)rettv; if (!is_cmd) { xfree(rettv); } @@ -3412,14 +3412,14 @@ char *get_return_cmd(void *rettv) char *get_func_line(int c, void *cookie, int indent, bool do_concat) { funccall_T *fcp = (funccall_T *)cookie; - ufunc_T *fp = fcp->func; + ufunc_T *fp = fcp->fc_func; char *retval; garray_T *gap; // growarray with function lines // If breakpoints have been added/deleted need to check for it. - if (fcp->dbg_tick != debug_tick) { - fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); - fcp->dbg_tick = debug_tick; + if (fcp->fc_dbg_tick != debug_tick) { + fcp->fc_breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); + fcp->fc_dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { func_line_end(cookie); @@ -3427,19 +3427,19 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) gap = &fp->uf_lines; if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) - || fcp->returned) { + || fcp->fc_returned) { retval = NULL; } else { // Skip NULL lines (continuation lines). - while (fcp->linenr < gap->ga_len - && ((char **)(gap->ga_data))[fcp->linenr] == NULL) { - fcp->linenr++; + while (fcp->fc_linenr < gap->ga_len + && ((char **)(gap->ga_data))[fcp->fc_linenr] == NULL) { + fcp->fc_linenr++; } - if (fcp->linenr >= gap->ga_len) { + if (fcp->fc_linenr >= gap->ga_len) { retval = NULL; } else { - retval = xstrdup(((char **)(gap->ga_data))[fcp->linenr++]); - SOURCING_LNUM = fcp->linenr; + retval = xstrdup(((char **)(gap->ga_data))[fcp->fc_linenr++]); + SOURCING_LNUM = fcp->fc_linenr; if (do_profiling == PROF_YES) { func_line_start(cookie); } @@ -3447,11 +3447,11 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) } // Did we encounter a breakpoint? - if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM) { + if (fcp->fc_breakpoint != 0 && fcp->fc_breakpoint <= SOURCING_LNUM) { dbg_breakpoint(fp->uf_name, SOURCING_LNUM); // Find next breakpoint. - fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); - fcp->dbg_tick = debug_tick; + fcp->fc_breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); + fcp->fc_dbg_tick = debug_tick; } return retval; @@ -3465,14 +3465,14 @@ int func_has_ended(void *cookie) // Ignore the "abort" flag if the abortion behavior has been changed due to // an error inside a try conditional. - return ((fcp->func->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) - || fcp->returned; + return ((fcp->fc_func->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) + || fcp->fc_returned; } /// @return true if cookie indicates a function which "abort"s on errors. int func_has_abort(void *cookie) { - return ((funccall_T *)cookie)->func->uf_flags & FC_ABORT; + return ((funccall_T *)cookie)->fc_func->uf_flags & FC_ABORT; } /// Turn "dict.Func" into a partial for "Func" bound to "dict". @@ -3537,31 +3537,31 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) /// @return the name of the executed function. char *func_name(void *cookie) { - return ((funccall_T *)cookie)->func->uf_name; + return ((funccall_T *)cookie)->fc_func->uf_name; } /// @return the address holding the next breakpoint line for a funccall cookie. linenr_T *func_breakpoint(void *cookie) { - return &((funccall_T *)cookie)->breakpoint; + return &((funccall_T *)cookie)->fc_breakpoint; } /// @return the address holding the debug tick for a funccall cookie. int *func_dbg_tick(void *cookie) { - return &((funccall_T *)cookie)->dbg_tick; + return &((funccall_T *)cookie)->fc_dbg_tick; } /// @return the nesting level for a funccall cookie. int func_level(void *cookie) { - return ((funccall_T *)cookie)->level; + return ((funccall_T *)cookie)->fc_level; } /// @return true when a function was ended by a ":return" command. int current_func_returned(void) { - return current_funccal->returned; + return current_funccal->fc_returned; } bool free_unref_funccal(int copyID, int testing) @@ -3572,12 +3572,12 @@ bool free_unref_funccal(int copyID, int testing) for (funccall_T **pfc = &previous_funccal; *pfc != NULL;) { if (can_free_funccal(*pfc, copyID)) { funccall_T *fc = *pfc; - *pfc = fc->caller; + *pfc = fc->fc_caller; free_funccal_contents(fc); did_free = true; did_free_funccal = true; } else { - pfc = &(*pfc)->caller; + pfc = &(*pfc)->fc_caller; } } if (did_free_funccal) { @@ -3594,7 +3594,7 @@ funccall_T *get_funccal(void) funccall_T *funccal = current_funccal; if (debug_backtrace_level > 0) { for (int i = 0; i < debug_backtrace_level; i++) { - funccall_T *temp_funccal = funccal->caller; + funccall_T *temp_funccal = funccal->fc_caller; if (temp_funccal) { funccal = temp_funccal; } else { @@ -3614,7 +3614,7 @@ hashtab_T *get_funccal_local_ht(void) if (current_funccal == NULL) { return NULL; } - return &get_funccal()->l_vars.dv_hashtab; + return &get_funccal()->fc_l_vars.dv_hashtab; } /// @return the l: scope variable or @@ -3624,7 +3624,7 @@ dictitem_T *get_funccal_local_var(void) if (current_funccal == NULL) { return NULL; } - return (dictitem_T *)&get_funccal()->l_vars_var; + return (dictitem_T *)&get_funccal()->fc_l_vars_var; } /// @return the hashtable used for argument in the current funccal or @@ -3634,7 +3634,7 @@ hashtab_T *get_funccal_args_ht(void) if (current_funccal == NULL) { return NULL; } - return &get_funccal()->l_avars.dv_hashtab; + return &get_funccal()->fc_l_avars.dv_hashtab; } /// @return the a: scope variable or @@ -3644,14 +3644,14 @@ dictitem_T *get_funccal_args_var(void) if (current_funccal == NULL) { return NULL; } - return (dictitem_T *)¤t_funccal->l_avars_var; + return (dictitem_T *)¤t_funccal->fc_l_avars_var; } /// List function variables, if there is a function. void list_func_vars(int *first) { if (current_funccal != NULL) { - list_hashtable_vars(¤t_funccal->l_vars.dv_hashtab, "l:", false, + list_hashtable_vars(¤t_funccal->fc_l_vars.dv_hashtab, "l:", false, first); } } @@ -3660,8 +3660,8 @@ void list_func_vars(int *first) /// funccal, return the dict that contains it. Otherwise return NULL. dict_T *get_current_funccal_dict(hashtab_T *ht) { - if (current_funccal != NULL && ht == ¤t_funccal->l_vars.dv_hashtab) { - return ¤t_funccal->l_vars; + if (current_funccal != NULL && ht == ¤t_funccal->fc_l_vars.dv_hashtab) { + return ¤t_funccal->fc_l_vars; } return NULL; } @@ -3669,7 +3669,7 @@ dict_T *get_current_funccal_dict(hashtab_T *ht) /// Search hashitem in parent scope. hashitem_T *find_hi_in_scoped_ht(const char *name, hashtab_T **pht) { - if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) { + if (current_funccal == NULL || current_funccal->fc_func->uf_scoped == NULL) { return NULL; } @@ -3679,7 +3679,7 @@ hashitem_T *find_hi_in_scoped_ht(const char *name, hashtab_T **pht) const char *varname; // Search in parent scope which is possible to reference from lambda - current_funccal = current_funccal->func->uf_scoped; + current_funccal = current_funccal->fc_func->uf_scoped; while (current_funccal != NULL) { hashtab_T *ht = find_var_ht(name, namelen, &varname); if (ht != NULL && *varname != NUL) { @@ -3689,10 +3689,10 @@ hashitem_T *find_hi_in_scoped_ht(const char *name, hashtab_T **pht) break; } } - if (current_funccal == current_funccal->func->uf_scoped) { + if (current_funccal == current_funccal->fc_func->uf_scoped) { break; } - current_funccal = current_funccal->func->uf_scoped; + current_funccal = current_funccal->fc_func->uf_scoped; } current_funccal = old_current_funccal; @@ -3702,7 +3702,7 @@ hashitem_T *find_hi_in_scoped_ht(const char *name, hashtab_T **pht) /// Search variable in parent scope. dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen, int no_autoload) { - if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) { + if (current_funccal == NULL || current_funccal->fc_func->uf_scoped == NULL) { return NULL; } @@ -3711,7 +3711,7 @@ dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen, int no const char *varname; // Search in parent scope which is possible to reference from lambda - current_funccal = current_funccal->func->uf_scoped; + current_funccal = current_funccal->fc_func->uf_scoped; while (current_funccal) { hashtab_T *ht = find_var_ht(name, namelen, &varname); if (ht != NULL && *varname != NUL) { @@ -3721,10 +3721,10 @@ dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen, int no break; } } - if (current_funccal == current_funccal->func->uf_scoped) { + if (current_funccal == current_funccal->fc_func->uf_scoped) { break; } - current_funccal = current_funccal->func->uf_scoped; + current_funccal = current_funccal->fc_func->uf_scoped; } current_funccal = old_current_funccal; @@ -3735,11 +3735,11 @@ dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen, int no bool set_ref_in_previous_funccal(int copyID) { for (funccall_T *fc = previous_funccal; fc != NULL; - fc = fc->caller) { + fc = fc->fc_caller) { fc->fc_copyID = copyID + 1; - if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL) - || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL) - || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL)) { + if (set_ref_in_ht(&fc->fc_l_vars.dv_hashtab, copyID + 1, NULL) + || set_ref_in_ht(&fc->fc_l_avars.dv_hashtab, copyID + 1, NULL) + || set_ref_in_list(&fc->fc_l_varlist, copyID + 1, NULL)) { return true; } } @@ -3750,10 +3750,10 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID) { if (fc->fc_copyID != copyID) { fc->fc_copyID = copyID; - if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL) - || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL) - || set_ref_in_list(&fc->l_varlist, copyID, NULL) - || set_ref_in_func(NULL, fc->func, copyID)) { + if (set_ref_in_ht(&fc->fc_l_vars.dv_hashtab, copyID, NULL) + || set_ref_in_ht(&fc->fc_l_avars.dv_hashtab, copyID, NULL) + || set_ref_in_list(&fc->fc_l_varlist, copyID, NULL) + || set_ref_in_func(NULL, fc->fc_func, copyID)) { return true; } } @@ -3764,7 +3764,7 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID) bool set_ref_in_call_stack(int copyID) { for (funccall_T *fc = current_funccal; fc != NULL; - fc = fc->caller) { + fc = fc->fc_caller) { if (set_ref_in_funccal(fc, copyID)) { return true; } @@ -3774,7 +3774,7 @@ bool set_ref_in_call_stack(int copyID) for (funccal_entry_T *entry = funccal_stack; entry != NULL; entry = entry->next) { for (funccall_T *fc = entry->top_funccal; fc != NULL; - fc = fc->caller) { + fc = fc->fc_caller) { if (set_ref_in_funccal(fc, copyID)) { return true; } @@ -3839,7 +3839,7 @@ bool set_ref_in_func(char *name, ufunc_T *fp_in, int copyID) fp = find_func(fname); } if (fp != NULL) { - for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped) { + for (fc = fp->uf_scoped; fc != NULL; fc = fc->fc_func->uf_scoped) { abort = abort || set_ref_in_funccal(fc, copyID); } } -- cgit From 78535664bd29e6f2bd4b64c20cb29ef40f9bccd4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 17 Apr 2023 09:07:30 +0800 Subject: vim-patch:8.2.2172: Vim9: number of arguments is not always checked (#23142) Problem: Vim9: number of arguments is not always checked. (Yegappan Lakshmanan) Solution: Check number of arguments when calling function by name. https://github.com/vim/vim/commit/5082471f91dd42ed8c35e0f649d0a6572e6fe3fc Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 734a6655bb..6016ad0646 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1290,6 +1290,21 @@ static bool func_name_refcount(const char *name) return isdigit((uint8_t)(*name)) || *name == '<'; } +/// Check the argument count for user function "fp". +/// @return FCERR_UNKNOWN if OK, FCERR_TOOFEW or FCERR_TOOMANY otherwise. +static int check_user_func_argcount(ufunc_T *fp, int argcount) + FUNC_ATTR_NONNULL_ALL +{ + const int regular_args = fp->uf_args.ga_len; + + if (argcount < regular_args - fp->uf_def_args.ga_len) { + return FCERR_TOOFEW; + } else if (!fp->uf_varargs && argcount > regular_args) { + return FCERR_TOOMANY; + } + return FCERR_UNKNOWN; +} + /// Call a user function after checking the arguments. static int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict) @@ -1302,12 +1317,11 @@ static int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, ty if ((fp->uf_flags & FC_RANGE) && funcexe->fe_doesrange != NULL) { *funcexe->fe_doesrange = true; } - int error; - if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) { - error = FCERR_TOOFEW; - } else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) { - error = FCERR_TOOMANY; - } else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) { + int error = check_user_func_argcount(fp, argcount); + if (error != FCERR_UNKNOWN) { + return error; + } + if ((fp->uf_flags & FC_DICT) && selfdict == NULL) { error = FCERR_DICT; } else { // Call the user function. -- cgit From 6bfba3660c5fbb22104cd87bd66a1381007fca22 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 17 Apr 2023 08:56:23 +0800 Subject: vim-patch:9.0.0406: deferred functions not invoked when partial func exits Problem: Deferred functions not invoked when partial func exits. Solution: Create a funccall_T when calling a :def function. https://github.com/vim/vim/commit/9667b2c888351b04751bdb43cba0d4ffc8c13ab1 The remove_funccal() function is currently unused, but it will be used in patch 9.0.0618. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 6016ad0646..32f9f9182c 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -881,6 +881,27 @@ static void func_clear_free(ufunc_T *fp, bool force) func_free(fp); } +/// Allocate a funccall_T, link it in current_funccal and fill in "fp" and "rettv". +/// Must be followed by one call to remove_funccal() or cleanup_function_call(). +funccall_T *create_funccal(ufunc_T *fp, typval_T *rettv) +{ + funccall_T *fc = xcalloc(1, sizeof(funccall_T)); + fc->fc_caller = current_funccal; + current_funccal = fc; + fc->fc_func = fp; + func_ptr_ref(fp); + fc->fc_rettv = rettv; + return fc; +} + +/// Restore current_funccal. +void remove_funccal(void) +{ + funccall_T *fc = current_funccal; + current_funccal = fc->fc_caller; + free_funccal(fc); +} + /// Call a user function /// /// @param fp Function to call. @@ -895,7 +916,6 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett FUNC_ATTR_NONNULL_ARG(1, 3, 4) { bool using_sandbox = false; - funccall_T *fc; int save_did_emsg; static int depth = 0; dictitem_T *v; @@ -930,19 +950,13 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // check for CTRL-C hit line_breakcheck(); // prepare the funccall_T structure - fc = xcalloc(1, sizeof(funccall_T)); - fc->fc_caller = current_funccal; - current_funccal = fc; - fc->fc_func = fp; - fc->fc_rettv = rettv; + funccall_T *fc = create_funccal(fp, rettv); fc->fc_level = ex_nesting_level; // Check if this function has a breakpoint. fc->fc_breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0); fc->fc_dbg_tick = debug_tick; - // Set up fields for closure. ga_init(&fc->fc_ufuncs, sizeof(ufunc_T *), 1); - func_ptr_ref(fp); if (strncmp(fp->uf_name, "", 8) == 0) { islambda = true; -- cgit From 7a3f86481e96e5c30db5af74760e475bac8cc403 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 17 Apr 2023 09:08:25 +0800 Subject: vim-patch:9.0.0419: the :defer command does not check the function arguments Problem: The :defer command does not check the function argument count and types. Solution: Check the function arguments when adding a deferred function. https://github.com/vim/vim/commit/169003289fb4b2ad18fd7f5807e0d05efff0be85 Cherry-pick check_internal_func() from Vim, but use EvalFuncDef pointer as first argument. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 32f9f9182c..65918ba2bf 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -72,7 +72,7 @@ static funccall_T *current_funccal = NULL; // item in it is still being used. static funccall_T *previous_funccal = NULL; -static const char *e_unknownfunc = N_("E117: Unknown function: %s"); +static const char *e_unknown_function_str = N_("E117: Unknown function: %s"); static const char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it"); static const char *e_funcdict = N_("E717: Dictionary entry already exists"); static const char *e_funcref = N_("E718: Funcref required"); @@ -1523,14 +1523,14 @@ varnumber_T callback_call_retnr(Callback *callback, int argcount, typval_T *argv /// Give an error message for the result of a function. /// Nothing if "error" is FCERR_NONE. static void user_func_error(int error, const char *name, funcexe_T *funcexe) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ARG(2) { switch (error) { case FCERR_UNKNOWN: if (funcexe->fe_found_var) { semsg(_(e_not_callable_type_str), name); } else { - emsg_funcname(e_unknownfunc, name); + emsg_funcname(e_unknown_function_str, name); } break; case FCERR_NOTMETHOD: @@ -1543,7 +1543,7 @@ static void user_func_error(int error, const char *name, funcexe_T *funcexe) emsg_funcname(_(e_toomanyarg), name); break; case FCERR_TOOFEW: - emsg_funcname(N_("E119: Not enough arguments for function: %s"), name); + emsg_funcname(_(e_toofewarg), name); break; case FCERR_SCRIPT: emsg_funcname(N_("E120: Using not in a script context: %s"), name); @@ -3172,6 +3172,29 @@ static int ex_defer_inner(char *name, char **arg, const partial_T *const partial } int r = get_func_arguments(arg, evalarg, false, argvars + partial_argc, &argcount); argcount += partial_argc; + + if (r == OK) { + if (builtin_function(name, -1)) { + const EvalFuncDef *const fdef = find_internal_func(name); + if (fdef == NULL) { + emsg_funcname(e_unknown_function_str, name); + r = FAIL; + } else if (check_internal_func(fdef, argcount) == -1) { + r = FAIL; + } + } else { + ufunc_T *ufunc = find_func(name); + // we tolerate an unknown function here, it might be defined later + if (ufunc != NULL) { + int error = check_user_func_argcount(ufunc, argcount); + if (error != FCERR_UNKNOWN) { + user_func_error(error, name, NULL); + r = FAIL; + } + } + } + } + if (r == FAIL) { while (--argcount >= 0) { tv_clear(&argvars[argcount]); -- cgit From e83682e652ff68cf9a05f0076bb088e9231d2059 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 17 Apr 2023 19:22:55 +0800 Subject: refactor: suppress clang false positives (#23154) --- src/nvim/eval/userfunc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 65918ba2bf..e138c50b6a 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -536,6 +536,7 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, evalarg_ : funcexe->fe_partial->pt_argc), argvars, &argcount); + assert(ret == OK || ret == FAIL); // suppress clang false positive if (ret == OK) { int i = 0; -- cgit From 9180c18c462a4945657899b732189da6f2ea2eaf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 18 Apr 2023 14:31:40 +0800 Subject: vim-patch:9.0.0864: crash when using "!!" without a previous shell command Problem: Crash when using "!!" without a previous shell command. Solution: Check "prevcmd" is not NULL. (closes vim/vim#11487) https://github.com/vim/vim/commit/6600447c7b0a1be3a64d07a318bacdfaae0cac4b Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index e138c50b6a..63d5f94f11 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3207,7 +3207,7 @@ static int ex_defer_inner(char *name, char **arg, const partial_T *const partial } /// Return true if currently inside a function call. -/// Give an error message and return FALSE when not. +/// Give an error message and return false when not. bool can_add_defer(void) { if (get_current_funccal() == NULL) { -- cgit From 8e0ad6e261b81e9e2649bdba103904867b7ff6ef Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 19 Apr 2023 07:52:53 +0800 Subject: vim-patch:9.0.1462: recursively calling :defer function if it does :qa Problem: Recursively calling :defer function if it does :qa. Solution: Clear the defer entry before calling the function. (closes vim/vim#12266) https://github.com/vim/vim/commit/42994bf678f46dc9ca66e49f512261da8864fff6 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 63d5f94f11..e8b50d8c94 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3242,12 +3242,24 @@ static void handle_defer_one(funccall_T *funccal) { for (int idx = funccal->fc_defer.ga_len - 1; idx >= 0; idx--) { defer_T *dr = ((defer_T *)funccal->fc_defer.ga_data) + idx; + + if (dr->dr_name == NULL) { + // already being called, can happen if function does ":qa" + continue; + } + funcexe_T funcexe = { .fe_evaluate = true }; + typval_T rettv; rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this - call_func(dr->dr_name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe); + + char *name = dr->dr_name; + dr->dr_name = NULL; + + call_func(name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe); + tv_clear(&rettv); - xfree(dr->dr_name); + xfree(name); for (int i = dr->dr_argcount - 1; i >= 0; i--) { tv_clear(&dr->dr_argvars[i]); } -- cgit From a0c982671ee2f4c4e87a6480d2ea4d23ba807273 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 19 Apr 2023 07:59:35 +0800 Subject: vim-patch:9.0.1469: deferred functions not called from autocommands Problem: Deferred functions not called from autocommands. Solution: Also go through the funccal_stack. (closes vim/vim#12267) https://github.com/vim/vim/commit/960cf9119e3f4922ca9719feb5e0c0bc5e3b9840 --- src/nvim/eval/userfunc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index e8b50d8c94..4cb2f9bd2b 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3270,8 +3270,14 @@ static void handle_defer_one(funccall_T *funccal) /// Called when exiting: call all defer functions. void invoke_all_defer(void) { - for (funccall_T *funccal = current_funccal; funccal != NULL; funccal = funccal->fc_caller) { - handle_defer_one(funccal); + for (funccal_entry_T *fce = funccal_stack; fce != NULL; fce = fce->next) { + for (funccall_T *fc = fce->top_funccal; fc != NULL; fc = fc->fc_caller) { + handle_defer_one(fc); + } + } + + for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->fc_caller) { + handle_defer_one(fc); } } -- cgit From 0d7bed34a29ef1add5d225a6809882fa6dce49d9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 19 Apr 2023 22:09:48 +0800 Subject: vim-patch:9.0.1470: deferred functions invoked in unexpected order (#23199) Problem: Deferred functions invoked in unexpected order when using :qa and autocommands. Solution: Call deferred functions for the current funccal before using the stack. (closes vim/vim#12278) https://github.com/vim/vim/commit/1be4b81bfb3d7edf0e2ae41711d429e8fa5e0555 --- src/nvim/eval/userfunc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 4cb2f9bd2b..51e109fdfb 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3270,15 +3270,15 @@ static void handle_defer_one(funccall_T *funccal) /// Called when exiting: call all defer functions. void invoke_all_defer(void) { + for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->fc_caller) { + handle_defer_one(fc); + } + for (funccal_entry_T *fce = funccal_stack; fce != NULL; fce = fce->next) { for (funccall_T *fc = fce->top_funccal; fc != NULL; fc = fc->fc_caller) { handle_defer_one(fc); } } - - for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->fc_caller) { - handle_defer_one(fc); - } } /// ":1,25call func(arg1, arg2)" function call. -- cgit From 9802de933484cc0a69ee328f3e4e6efbb83c308e Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Fri, 21 Apr 2023 11:07:56 +0200 Subject: fix(userfunc): fix possible out of bound access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In file included from /usr/include/string.h:535, from gsrc/nvim/eval/userfunc.c:11: In function ‘strcpy’, inlined from ‘cat_func_name’ at gsrc/nvim/eval/userfunc.c:662:5, inlined from ‘get_user_func_name’ at gsrc/nvim/eval/userfunc.c:2854:5: /usr/include/bits/string_fortified.h:79:10: warning: ‘__builtin___strcpy_chk’ offset 0 from the object at ‘’ is out of the bounds of referenced subobject ‘uf_name’ with ty pe ‘char[]’ at offset 0 [-Warray-bounds=] 79 | return __builtin___strcpy_chk (__dest, __src, __glibc_objsize (__dest)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from gsrc/nvim/eval/typval.h:10, from gsrc/nvim/buffer_defs.h:20, from gsrc/nvim/autocmd.h:8, from gsrc/nvim/eval/userfunc.c:15: gsrc/nvim/eval/typval_defs.h: In function ‘get_user_func_name’: gsrc/nvim/eval/typval_defs.h:342:8: note: subobject ‘uf_name’ declared here 342 | char uf_name[]; ///< Name of function (actual size equals name); | ^~~~~~~ --- src/nvim/eval/userfunc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 51e109fdfb..b71e6c9cff 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -653,14 +653,20 @@ ufunc_T *find_func(const char *name) /// Copy the function name of "fp" to buffer "buf". /// "buf" must be able to hold the function name plus three bytes. /// Takes care of script-local function names. -static void cat_func_name(char *buf, ufunc_T *fp) +static void cat_func_name(char *buf, size_t buflen, ufunc_T *fp) { - if ((uint8_t)fp->uf_name[0] == K_SPECIAL) { - STRCPY(buf, ""); - STRCAT(buf, fp->uf_name + 3); + int len = -1; + size_t uflen = strlen(fp->uf_name); + assert(uflen > 0); + + if ((uint8_t)fp->uf_name[0] == K_SPECIAL && uflen > 3) { + len = snprintf(buf, buflen, "%s", fp->uf_name + 3); } else { - STRCPY(buf, fp->uf_name); + len = snprintf(buf, buflen, "%s", fp->uf_name); } + + (void)len; // Avoid unused warning on release builds + assert(len > 0); } /// Add a number variable "name" to dict "dp" with value "nr". @@ -2851,7 +2857,7 @@ char *get_user_func_name(expand_T *xp, int idx) return fp->uf_name; // Prevent overflow. } - cat_func_name(IObuff, fp); + cat_func_name(IObuff, IOSIZE, fp); if (xp->xp_context != EXPAND_USER_FUNC) { STRCAT(IObuff, "("); if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args)) { -- cgit From ac9f8669a8e4bd0cf13468d316d1746be65d3cdc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 25 Apr 2023 23:19:00 +0800 Subject: vim-patch:9.0.0875: using freed memory when executing delfunc at more prompt (#23314) Problem: Using freed memory when executing delfunc at the more prompt. Solution: Check function list not changed in another place. (closes vim/vim#11437) https://github.com/vim/vim/commit/398a26f7fcd58fbc6e2329f892edbb7479a971bb Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 80 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 23 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index b71e6c9cff..854a0732ab 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -77,6 +77,8 @@ static const char *e_funcexts = N_("E122: Function %s already exists, add ! to r static const char *e_funcdict = N_("E717: Dictionary entry already exists"); static const char *e_funcref = N_("E718: Funcref required"); static const char *e_nofunc = N_("E130: Unknown function: %s"); +static const char e_function_list_was_modified[] + = N_("E454: Function list was modified"); static const char e_no_white_space_allowed_before_str_str[] = N_("E1068: No white space allowed before '%s': %s"); static const char e_missing_heredoc_end_marker_str[] @@ -1752,14 +1754,33 @@ char *printable_func_name(ufunc_T *fp) return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name; } +/// When "prev_ht_changed" does not equal "ht_changed" give an error and return +/// true. Otherwise return false. +static int function_list_modified(const int prev_ht_changed) +{ + if (prev_ht_changed != func_hashtab.ht_changed) { + emsg(_(e_function_list_was_modified)); + return true; + } + return false; +} + /// List the head of the function: "name(arg1, arg2)". /// /// @param[in] fp Function pointer. /// @param[in] indent Indent line. /// @param[in] force Include bang "!" (i.e.: "function!"). -static void list_func_head(ufunc_T *fp, int indent, bool force) +static int list_func_head(ufunc_T *fp, bool indent, bool force) { + const int prev_ht_changed = func_hashtab.ht_changed; + msg_start(); + + // a callback at the more prompt may have deleted the function + if (function_list_modified(prev_ht_changed)) { + return FAIL; + } + if (indent) { msg_puts(" "); } @@ -1805,6 +1826,8 @@ static void list_func_head(ufunc_T *fp, int indent, bool force) if (p_verbose > 0) { last_set_msg(fp->uf_script_ctx); } + + return OK; } /// Get a function name, translating "" and "". @@ -2085,7 +2108,7 @@ char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi) /// Otherwise functions matching "regmatch". static void list_functions(regmatch_T *regmatch) { - const int changed = func_hashtab.ht_changed; + const int prev_ht_changed = func_hashtab.ht_changed; size_t todo = func_hashtab.ht_used; const hashitem_T *const ht_array = func_hashtab.ht_array; @@ -2098,9 +2121,10 @@ static void list_functions(regmatch_T *regmatch) && !func_name_refcount(fp->uf_name)) : (!isdigit((uint8_t)(*fp->uf_name)) && vim_regexec(regmatch, fp->uf_name, 0))) { - list_func_head(fp, false, false); - if (changed != func_hashtab.ht_changed) { - emsg(_("E454: function list was modified")); + if (list_func_head(fp, false, false) == FAIL) { + return; + } + if (function_list_modified(prev_ht_changed)) { return; } } @@ -2229,27 +2253,37 @@ void ex_function(exarg_T *eap) if (!eap->skip && !got_int) { fp = find_func(name); if (fp != NULL) { - list_func_head(fp, !eap->forceit, eap->forceit); - for (int j = 0; j < fp->uf_lines.ga_len && !got_int; j++) { - if (FUNCLINE(fp, j) == NULL) { - continue; - } - msg_putchar('\n'); - if (!eap->forceit) { - msg_outnum((long)j + 1); - if (j < 9) { - msg_putchar(' '); + // Check no function was added or removed from a callback, e.g. at + // the more prompt. "fp" may then be invalid. + const int prev_ht_changed = func_hashtab.ht_changed; + + if (list_func_head(fp, !eap->forceit, eap->forceit) == OK) { + for (int j = 0; j < fp->uf_lines.ga_len && !got_int; j++) { + if (FUNCLINE(fp, j) == NULL) { + continue; } - if (j < 99) { - msg_putchar(' '); + msg_putchar('\n'); + if (!eap->forceit) { + msg_outnum((long)j + 1); + if (j < 9) { + msg_putchar(' '); + } + if (j < 99) { + msg_putchar(' '); + } + if (function_list_modified(prev_ht_changed)) { + break; + } + } + msg_prt_line(FUNCLINE(fp, j), false); + line_breakcheck(); // show multiple lines at a time! + } + if (!got_int) { + msg_putchar('\n'); + if (!function_list_modified(prev_ht_changed)) { + msg_puts(eap->forceit ? "endfunction" : " endfunction"); } } - msg_prt_line(FUNCLINE(fp, j), false); - line_breakcheck(); // show multiple lines at a time! - } - if (!got_int) { - msg_putchar('\n'); - msg_puts(eap->forceit ? "endfunction" : " endfunction"); } } else { emsg_funcname(N_("E123: Undefined function: %s"), name); -- cgit From 3b0df1780e2c8526bda5dead18ee7cc45925caba Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 26 Apr 2023 23:23:44 +0200 Subject: refactor: uncrustify Notable changes: replace all infinite loops to `while(true)` and remove `int` from `unsigned int`. --- src/nvim/eval/userfunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 854a0732ab..0e22cf54cf 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2343,7 +2343,7 @@ void ex_function(exarg_T *eap) } // find extra arguments "range", "dict", "abort" and "closure" - for (;;) { + while (true) { p = skipwhite(p); if (strncmp(p, "range", 5) == 0) { flags |= FC_RANGE; @@ -2403,7 +2403,7 @@ void ex_function(exarg_T *eap) indent = 2; nesting = 0; - for (;;) { + while (true) { if (KeyTyped) { msg_scroll = true; saved_wait_return = false; -- cgit From 4bcf8c15b3079ca72d6557890b50b35565fcd577 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 29 Apr 2023 08:12:32 +0800 Subject: vim-patch:8.2.0578: heredoc for interfaces does not support "trim" Problem: Heredoc for interfaces does not support "trim". Solution: Update the script heredoc support to be same as the :let command. (Yegappan Lakshmanan, closes vim/vim#5916) https://github.com/vim/vim/commit/6c2b7b8055b96463f78abb70f58c4c6d6d4b9d55 --- src/nvim/eval/userfunc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 0e22cf54cf..1f5a6eaec4 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2571,11 +2571,18 @@ void ex_function(exarg_T *eap) && (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) { // ":python <<" continues until a dot, like ":append" p = skipwhite(arg + 2); + if (strncmp(p, "trim", 4) == 0) { + // Ignore leading white space. + p = skipwhite(p + 4); + heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline)); + } if (*p == NUL) { skip_until = xstrdup("."); } else { - skip_until = xstrdup(p); + skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p)); } + do_concat = false; + is_heredoc = true; } // Check for ":let v =<< [trim] EOF" -- cgit From bff3f4fa8bbadf7494bcf3098eee8da39cc2c436 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 3 May 2023 00:05:46 +0800 Subject: vim-patch:9.0.1505: error when heredoc content looks like heredoc (#23446) Problem: Error when heredoc content looks like heredoc. Solution: Handle curly expressions. (closes vim/vim#12325) https://github.com/vim/vim/commit/a93d9cdc74f70ca2c85781496ffae4ca738fcd88 --- src/nvim/eval/userfunc.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 1f5a6eaec4..bfda2c4b9b 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2587,19 +2587,13 @@ void ex_function(exarg_T *eap) // Check for ":let v =<< [trim] EOF" // and ":let [a, b] =<< [trim] EOF" - arg = skipwhite(skiptowhite(p)); - if (*arg == '[') { - arg = vim_strchr(arg, ']'); - } - if (arg != NULL) { - arg = skipwhite(skiptowhite(arg)); - if (arg[0] == '=' - && arg[1] == '<' - && arg[2] == '<' - && (p[0] == 'l' - && p[1] == 'e' - && (!ASCII_ISALNUM(p[2]) - || (p[2] == 't' && !ASCII_ISALNUM(p[3]))))) { + arg = p; + if (checkforcmd(&arg, "let", 2)) { + while (vim_strchr("$@&", *arg) != NULL) { + arg++; + } + arg = skipwhite(find_name_end(arg, NULL, NULL, FNE_INCL_BR)); + if (arg[0] == '=' && arg[1] == '<' && arg[2] == '<') { p = skipwhite(arg + 3); while (true) { if (strncmp(p, "trim", 4) == 0) { -- cgit From b16729f8162ce21a52f079c3849f5011b768d0ce Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 4 May 2023 23:17:43 +0800 Subject: vim-patch:8.2.1697: inconsistent capitalization of error messages (#23476) Problem: Inconsistent capitalization of error messages. Solution: Always start with a capital. https://github.com/vim/vim/commit/7707228aace9aff16434edf5377a354c6ad07316 Most of these errors are Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index bfda2c4b9b..fbb5e8d10c 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -79,6 +79,8 @@ static const char *e_funcref = N_("E718: Funcref required"); static const char *e_nofunc = N_("E130: Unknown function: %s"); static const char e_function_list_was_modified[] = N_("E454: Function list was modified"); +static const char e_function_nesting_too_deep[] + = N_("E1058: Function nesting too deep"); static const char e_no_white_space_allowed_before_str_str[] = N_("E1068: No white space allowed before '%s': %s"); static const char e_missing_heredoc_end_marker_str[] @@ -2528,7 +2530,7 @@ void ex_function(exarg_T *eap) xfree(trans_function_name(&p, true, 0, NULL, NULL)); if (*skipwhite(p) == '(') { if (nesting == MAX_FUNC_NESTING - 1) { - emsg(_("E1058: function nesting too deep")); + emsg(_(e_function_nesting_too_deep)); } else { nesting++; indent += 2; -- cgit From c2441a8fb950b23088f08db4ceb10c0d25e613d6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 8 May 2023 10:24:44 +0800 Subject: vim-patch:8.2.4073: Coverity warns for using NULL pointer Problem: Coverity warns for using NULL pointer. Solution: Bail out when running out of memory. Check for running over end of a string. https://github.com/vim/vim/commit/54598066ca4cfaf0761aedf47e4ba9844674791e Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index fbb5e8d10c..11ed537210 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -467,12 +467,10 @@ char *deref_func_name(const char *name, int *lenp, partial_T **const partialp, b /// @param name function name void emsg_funcname(const char *errmsg, const char *name) { - char *p; + char *p = (char *)name; - if ((uint8_t)(*name) == K_SPECIAL) { + if ((uint8_t)name[0] == K_SPECIAL && name[1] != NUL && name[2] != NUL) { p = concat_str("", name + 3); - } else { - p = (char *)name; } semsg(_(errmsg), p); @@ -1863,8 +1861,7 @@ char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, part // Check for hard coded : already translated function ID (from a user // command). - if ((unsigned char)(*pp)[0] == K_SPECIAL && (unsigned char)(*pp)[1] == KS_EXTRA - && (*pp)[2] == KE_SNR) { + if ((uint8_t)(*pp)[0] == K_SPECIAL && (uint8_t)(*pp)[1] == KS_EXTRA && (*pp)[2] == KE_SNR) { *pp += 3; len = get_id_len((const char **)pp) + 3; return xmemdupz(start, (size_t)len); @@ -2232,6 +2229,10 @@ void ex_function(exarg_T *eap) eap->skip = true; } + if (name == NULL) { + goto ret_free; + } + // An error in a function call during evaluation of an expression in magic // braces should not cause the function not to be defined. saved_did_emsg = did_emsg; -- cgit From 03828536fa14cbbc39e3e3a182ad9b7901da5da7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 8 May 2023 11:10:13 +0800 Subject: vim-patch:8.2.4075: test failures Problem: Test failures. Solution: Change check for NULL pointer. https://github.com/vim/vim/commit/78a70533c3707aa50cbf998c7807221945aa9787 :export is N/A. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 11ed537210..7e20a298dd 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2137,7 +2137,6 @@ void ex_function(exarg_T *eap) char *theline; char *line_to_free = NULL; char c; - int saved_did_emsg; bool saved_wait_return = need_wait_return; char *name = NULL; char *p; @@ -2229,13 +2228,9 @@ void ex_function(exarg_T *eap) eap->skip = true; } - if (name == NULL) { - goto ret_free; - } - // An error in a function call during evaluation of an expression in magic // braces should not cause the function not to be defined. - saved_did_emsg = did_emsg; + const int saved_did_emsg = did_emsg; did_emsg = false; // -- cgit From d36dd2bae8e899b40cc21603e600a5046213bc36 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Tue, 16 May 2023 05:33:03 +0200 Subject: refactor: use xstrl{cpy,cat} on IObuff (#23648) Replace usage of STR{CPY,CAT} with xstrl{cpy,cat} when using on IObuff Co-authored-by: ii14 --- src/nvim/eval/userfunc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 7e20a298dd..a52b8d3f18 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2892,9 +2892,9 @@ char *get_user_func_name(expand_T *xp, int idx) cat_func_name(IObuff, IOSIZE, fp); if (xp->xp_context != EXPAND_USER_FUNC) { - STRCAT(IObuff, "("); + xstrlcat(IObuff, "(", IOSIZE); if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args)) { - STRCAT(IObuff, ")"); + xstrlcat(IObuff, ")", IOSIZE); } } return IObuff; @@ -3505,7 +3505,7 @@ char *get_return_cmd(void *rettv) s = ""; } - STRCPY(IObuff, ":return "); + xstrlcpy(IObuff, ":return ", IOSIZE); xstrlcpy(IObuff + 8, s, IOSIZE - 8); if (strlen(s) + 8 >= IOSIZE) { STRCPY(IObuff + IOSIZE - 4, "..."); -- cgit From a1bec02c1e105eb9f49d577e04bdbeadd5a05e38 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 13 Aug 2023 10:29:43 +0100 Subject: fix: use snprintf instead of sprintf Clang 14 now reports sprintf as deprecated. --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index a52b8d3f18..a5d7ed2758 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2702,7 +2702,7 @@ void ex_function(exarg_T *eap) // Give the function a sequential number. Can only be used with a // Funcref! xfree(name); - sprintf(numbuf, "%d", ++func_nr); // NOLINT(runtime/printf) + snprintf(numbuf, sizeof(numbuf), "%d", ++func_nr); name = xstrdup(numbuf); } -- cgit From bc13bc154aa574e0bb58a50f2e0ca4570efa57c3 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 29 Sep 2023 16:10:54 +0200 Subject: refactor(message): smsg_attr -> smsg --- src/nvim/eval/userfunc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index a5d7ed2758..0fe2396f8a 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1117,7 +1117,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett no_wait_return++; verbose_enter_scroll(); - smsg(_("calling %s"), SOURCING_NAME); + smsg(0, _("calling %s"), SOURCING_NAME); if (p_verbose >= 14) { msg_puts("("); for (int i = 0; i < argcount; i++) { @@ -1235,9 +1235,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett verbose_enter_scroll(); if (aborting()) { - smsg(_("%s aborted"), SOURCING_NAME); + smsg(0, _("%s aborted"), SOURCING_NAME); } else if (fc->fc_rettv->v_type == VAR_NUMBER) { - smsg(_("%s returning #%" PRId64 ""), + smsg(0, _("%s returning #%" PRId64 ""), SOURCING_NAME, (int64_t)fc->fc_rettv->vval.v_number); } else { char buf[MSG_BUF_LEN]; @@ -1254,7 +1254,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN); s = buf; } - smsg(_("%s returning %s"), SOURCING_NAME, s); + smsg(0, _("%s returning %s"), SOURCING_NAME, s); xfree(tofree); } } @@ -1277,7 +1277,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett no_wait_return++; verbose_enter_scroll(); - smsg(_("continuing in %s"), SOURCING_NAME); + smsg(0, _("continuing in %s"), SOURCING_NAME); msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); -- cgit From cf8b2c0e74fd5e723b0c15c2ce84e6900fd322d3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 12:05:28 +0800 Subject: build(iwyu): add a few more _defs.h mappings (#25435) --- src/nvim/eval/userfunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 0fe2396f8a..f525bcbd45 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -13,7 +13,6 @@ #include "lauxlib.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" -#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/debugger.h" #include "nvim/eval.h" @@ -26,15 +25,16 @@ #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" +#include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" +#include "nvim/hashtab.h" #include "nvim/insexpand.h" #include "nvim/keycodes.h" #include "nvim/lua/executor.h" #include "nvim/macros.h" #include "nvim/mbyte.h" -#include "nvim/memline_defs.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/option_defs.h" -- cgit From dc6d0d2daf69e2fdadda81feb97906dbc962a239 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 14:41:34 +0800 Subject: refactor: reorganize option header files (#25437) - Move vimoption_T to option.h - option_defs.h is for option-related types - option_vars.h corresponds to Vim's option.h - option_defs.h and option_vars.h don't include each other --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f525bcbd45..8d85c55e15 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -37,7 +37,7 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" -#include "nvim/option_defs.h" +#include "nvim/option_vars.h" #include "nvim/os/input.h" #include "nvim/path.h" #include "nvim/profile.h" -- cgit From 09a17f91d0d362c6e58bfdbe3ccdeacffb0b44b9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 2 Oct 2023 10:45:33 +0800 Subject: refactor: move cmdline completion types to cmdexpand_defs.h (#25465) --- src/nvim/eval/userfunc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 8d85c55e15..6b9801b805 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -14,6 +14,7 @@ #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/charset.h" +#include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" -- cgit From e72b546354cd90bf0cd8ee6dd045538d713009ad Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 29 Sep 2023 14:58:48 +0200 Subject: refactor: the long goodbye long is 32 bits on windows, while it is 64 bits on other architectures. This makes the type suboptimal for a codebase meant to be cross-platform. Replace it with more appropriate integer types. --- src/nvim/eval/userfunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 6b9801b805..e4adf9f340 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1126,7 +1126,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett msg_puts(", "); } if (argvars[i].v_type == VAR_NUMBER) { - msg_outnum((long)argvars[i].vval.v_number); + msg_outnum((int)argvars[i].vval.v_number); } else { // Do not want errors such as E724 here. emsg_off++; @@ -2263,7 +2263,7 @@ void ex_function(exarg_T *eap) } msg_putchar('\n'); if (!eap->forceit) { - msg_outnum((long)j + 1); + msg_outnum(j + 1); if (j < 9) { msg_putchar(' '); } -- cgit From 29fe883aa9166bdbcae3f935523c75a8aa56fe45 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 4 Oct 2023 06:31:25 -0700 Subject: feat: ignore swapfile for running Nvim processes #25336 Problem: The swapfile "E325: ATTENTION" dialog is displayed when editing a file already open in another (running) Nvim. Usually this behavior is annoying and irrelevant: - "Recover" and the other options ("Open readonly", "Quit", "Abort") are almost never wanted. - swapfiles are less relevant for "multi-Nvim" since 'autoread' is enabled by default. - Even less relevant if user enables 'autowrite'. Solution: Define a default SwapExists handler which does the following: 1. If the swapfile is owned by a running Nvim process, automatically chooses "(E)dit anyway" (caveat: this creates a new, extra swapfile, which is mostly harmless and ignored except by `:recover` or `nvim -r`. 2. Shows a 1-line "ignoring swapfile..." message. 3. Users can disable the default SwapExists handler via `autocmd! nvim_swapfile`. --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index e4adf9f340..ca98aad6bc 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2491,7 +2491,7 @@ void ex_function(exarg_T *eap) } else if (line_arg != NULL && *skipwhite(line_arg) != NUL) { nextcmd = line_arg; } else if (*p != NUL && *p != '"' && p_verbose > 0) { - give_warning2(_("W22: Text found after :endfunction: %s"), p, true); + swmsg(true, _("W22: Text found after :endfunction: %s"), p); } if (nextcmd != NULL) { // Another command follows. If the line came from "eap" we -- cgit From 9e3640a7797bcc5f6015548842572a6ce951a861 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 18 Oct 2023 18:27:50 +0800 Subject: vim-patch:9.0.2044: Vim9: exceptions confuse defered functions Problem: Vim9: exceptions confuse defered functions Solution: save and restore exception state when calling defered functions closes: vim/vim#13364 closes: vim/vim#13372 https://github.com/vim/vim/commit/0672595fd50e9ae668676a40e28ebf66d7f52392 Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/userfunc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index ca98aad6bc..f789c53870 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3296,8 +3296,23 @@ static void handle_defer_one(funccall_T *funccal) char *name = dr->dr_name; dr->dr_name = NULL; + // If the deferred function is called after an exception, then only the + // first statement in the function will be executed. Save and restore + // the try/catch/throw exception state. + const int save_trylevel = trylevel; + const bool save_did_throw = did_throw; + const bool save_need_rethrow = need_rethrow; + + trylevel = 0; + did_throw = false; + need_rethrow = false; + call_func(name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe); + trylevel = save_trylevel; + did_throw = save_did_throw; + need_rethrow = save_need_rethrow; + tv_clear(&rettv); xfree(name); for (int i = dr->dr_argcount - 1; i >= 0; i--) { -- cgit From a0961659770ca41edcb5a6dcf28e7c7492eb60f0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 19 Oct 2023 18:34:48 +0800 Subject: vim-patch:9.0.2050: Vim9: crash with deferred function call and exception (#25715) Problem: Vim9: crash with deferred function call and exception Solution: Save and restore exception state Crash when a deferred function is called after an exception and another exception is thrown closes: vim/vim#13376 closes: vim/vim#13377 https://github.com/vim/vim/commit/c59c1e0d88651a71ece7366e418f1253abbe2a28 The change in check_due_timer() is N/A as Nvim calls timer callbacks on the main loop. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/userfunc.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f789c53870..ff86f74338 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3297,21 +3297,16 @@ static void handle_defer_one(funccall_T *funccal) dr->dr_name = NULL; // If the deferred function is called after an exception, then only the - // first statement in the function will be executed. Save and restore - // the try/catch/throw exception state. - const int save_trylevel = trylevel; - const bool save_did_throw = did_throw; - const bool save_need_rethrow = need_rethrow; - - trylevel = 0; - did_throw = false; - need_rethrow = false; + // first statement in the function will be executed (because of the + // exception). So save and restore the try/catch/throw exception + // state. + exception_state_T estate; + exception_state_save(&estate); + exception_state_clear(); call_func(name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe); - trylevel = save_trylevel; - did_throw = save_did_throw; - need_rethrow = save_need_rethrow; + exception_state_restore(&estate); tv_clear(&rettv); xfree(name); -- cgit From acc646ad8fc3ef11fcc63b69f3d8484e4a91accd Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 29 Sep 2023 14:58:48 +0200 Subject: refactor: the long goodbye long is 32 bits on windows, while it is 64 bits on other architectures. This makes the type suboptimal for a codebase meant to be cross-platform. Replace it with more appropriate integer types. --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index ff86f74338..6e7b1e4d67 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2422,7 +2422,7 @@ void ex_function(exarg_T *eap) } else { xfree(line_to_free); if (eap->getline == NULL) { - theline = getcmdline(':', 0L, indent, do_concat); + theline = getcmdline(':', 0, indent, do_concat); } else { theline = eap->getline(':', eap->cookie, indent, do_concat); } -- cgit From cd63a9addd6e1114c3524fa041ece560550cfe7b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 10 Nov 2023 08:39:21 +0800 Subject: refactor: change some xstrndup() and xstrnsave() to xmemdupz() (#25959) When the given length is exactly the number of bytes to copy, xmemdupz() makes the intention clearer. --- src/nvim/eval/userfunc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 6e7b1e4d67..4b50710649 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1625,7 +1625,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t if (fp == NULL) { // Make a copy of the name, if it comes from a funcref variable it could // be changed or deleted in the called function. - name = xstrnsave(funcname, (size_t)len); + name = xmemdupz(funcname, (size_t)len); fname = fname_trans_sid(name, fname_buf, &tofree, &error); } @@ -2089,7 +2089,7 @@ char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi) if (strncmp(p, "", 8) == 0) { p += 8; (void)getdigits(&p, false, 0); - saved = xstrndup(*name, (size_t)(p - *name)); + saved = xmemdupz(*name, (size_t)(p - *name)); if (fudi != NULL) { CLEAR_POINTER(fudi); } @@ -2573,12 +2573,12 @@ void ex_function(exarg_T *eap) if (strncmp(p, "trim", 4) == 0) { // Ignore leading white space. p = skipwhite(p + 4); - heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline)); + heredoc_trimmed = xmemdupz(theline, (size_t)(skipwhite(theline) - theline)); } if (*p == NUL) { skip_until = xstrdup("."); } else { - skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p)); + skip_until = xmemdupz(p, (size_t)(skiptowhite(p) - p)); } do_concat = false; is_heredoc = true; @@ -2598,7 +2598,7 @@ void ex_function(exarg_T *eap) if (strncmp(p, "trim", 4) == 0) { // Ignore leading white space. p = skipwhite(p + 4); - heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline)); + heredoc_trimmed = xmemdupz(theline, (size_t)(skipwhite(theline) - theline)); continue; } if (strncmp(p, "eval", 4) == 0) { @@ -2608,7 +2608,7 @@ void ex_function(exarg_T *eap) } break; } - skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p)); + skip_until = xmemdupz(p, (size_t)(skiptowhite(p) - p)); do_concat = false; is_heredoc = true; } -- cgit From 8e58d37f2e15ac8540377148e55ed08a039aadb6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 11 Nov 2023 11:20:08 +0100 Subject: refactor: remove redundant casts --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 4b50710649..aff4f1de62 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -963,7 +963,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett funccall_T *fc = create_funccal(fp, rettv); fc->fc_level = ex_nesting_level; // Check if this function has a breakpoint. - fc->fc_breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0); + fc->fc_breakpoint = dbg_find_breakpoint(false, fp->uf_name, 0); fc->fc_dbg_tick = debug_tick; // Set up fields for closure. ga_init(&fc->fc_ufuncs, sizeof(ufunc_T *), 1); -- cgit From 353a4be7e84fdc101318215bdcc8a7e780d737fe Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 12 Nov 2023 13:13:58 +0100 Subject: build: remove PVS We already have an extensive suite of static analysis tools we use, which causes a fair bit of redundancy as we get duplicate warnings. PVS is also prone to give false warnings which creates a lot of work to identify and disable. --- src/nvim/eval/userfunc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index aff4f1de62..959dabafb5 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // User defined function support #include @@ -1214,7 +1211,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett if (func_or_func_caller_profiling) { call_start = profile_end(call_start); - call_start = profile_sub_wait(wait_start, call_start); // -V614 + call_start = profile_sub_wait(wait_start, call_start); fp->uf_tm_total = profile_add(fp->uf_tm_total, call_start); fp->uf_tm_self = profile_self(fp->uf_tm_self, call_start, fp->uf_tm_children); @@ -1400,7 +1397,7 @@ void free_all_functions(void) // Clean up the current_funccal chain and the funccal stack. while (current_funccal != NULL) { tv_clear(current_funccal->fc_rettv); - cleanup_function_call(current_funccal); // -V595 + cleanup_function_call(current_funccal); if (current_funccal == NULL && funccal_stack != NULL) { restore_funccal(); } -- cgit From ac1113ded5f8f09dd99a9894d7a7e795626fb728 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 13 Nov 2023 23:40:37 +0100 Subject: refactor: follow style guide - reduce variable scope - prefer initialization over declaration and assignment --- src/nvim/eval/userfunc.c | 107 ++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 72 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 959dabafb5..822ac4d16a 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -274,14 +274,13 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) ufunc_T *fp = NULL; partial_T *pt = NULL; int varargs; - int ret; bool *old_eval_lavars = eval_lavars_used; bool eval_lavars = false; char *tofree = NULL; // First, check if this is a lambda expression. "->" must exists. char *s = skipwhite(*arg + 1); - ret = get_function_args(&s, '-', NULL, NULL, NULL, true); + int ret = get_function_args(&s, '-', NULL, NULL, NULL, true); if (ret == FAIL || *s != '>') { return NOTDONE; } @@ -794,8 +793,6 @@ static void cleanup_function_call(funccall_T *fc) /// @param[in] force When true, we are exiting. static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) { - int i; - if (fc == NULL) { return; } @@ -810,7 +807,7 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) } } } - for (i = 0; i < fc->fc_ufuncs.ga_len; i++) { + for (int i = 0; i < fc->fc_ufuncs.ga_len; i++) { if (((ufunc_T **)(fc->fc_ufuncs.ga_data))[i] == fp) { ((ufunc_T **)(fc->fc_ufuncs.ga_data))[i] = NULL; } @@ -1846,16 +1843,13 @@ char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, part FUNC_ATTR_NONNULL_ARG(1) { char *name = NULL; - const char *start; - const char *end; - int lead; int len; lval_T lv; if (fdp != NULL) { CLEAR_POINTER(fdp); } - start = *pp; + const char *start = *pp; // Check for hard coded : already translated function ID (from a user // command). @@ -1867,14 +1861,14 @@ char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, part // A name starting with "" or "" is local to a script. But // don't skip over "s:", get_lval() needs it for "s:dict.func". - lead = eval_fname_script(start); + int lead = eval_fname_script(start); if (lead > 2) { start += lead; } // Note that TFN_ flags use the same values as GLV_ flags. - end = get_lval((char *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY, - lead > 2 ? 0 : FNE_CHECK_START); + const char *end = get_lval((char *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY, + lead > 2 ? 0 : FNE_CHECK_START); if (end == start) { if (!skip) { emsg(_("E129: Function name required")); @@ -2134,10 +2128,7 @@ void ex_function(exarg_T *eap) { char *theline; char *line_to_free = NULL; - char c; bool saved_wait_return = need_wait_return; - char *name = NULL; - char *p; char *arg; char *line_arg = NULL; garray_T newargs; @@ -2147,16 +2138,9 @@ void ex_function(exarg_T *eap) int flags = 0; ufunc_T *fp; bool overwrite = false; - int indent; - int nesting; - dictitem_T *v; funcdict_T fudi; static int func_nr = 0; // number for nameless function - int paren; hashtab_T *ht; - hashitem_T *hi; - linenr_T sourcing_lnum_off; - linenr_T sourcing_lnum_top; bool is_heredoc = false; char *skip_until = NULL; char *heredoc_trimmed = NULL; @@ -2174,11 +2158,11 @@ void ex_function(exarg_T *eap) // ":function /pat": list functions matching pattern. if (*eap->arg == '/') { - p = skip_regexp(eap->arg + 1, '/', true); + char *p = skip_regexp(eap->arg + 1, '/', true); if (!eap->skip) { regmatch_T regmatch; - c = *p; + char c = *p; *p = NUL; regmatch.regprog = vim_regcomp(eap->arg + 1, RE_MAGIC); *p = c; @@ -2209,9 +2193,9 @@ void ex_function(exarg_T *eap) // "fudi.fd_di" set, "fudi.fd_newkey" == NULL // s:func script-local function name // g:func global function name, same as "func" - p = eap->arg; - name = save_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi); - paren = (vim_strchr(p, '(') != NULL); + char *p = eap->arg; + char *name = save_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi); + int paren = (vim_strchr(p, '(') != NULL); if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { // Return on an invalid expression in braces, unless the expression // evaluation has been cancelled due to an aborting error, an @@ -2395,10 +2379,10 @@ void ex_function(exarg_T *eap) } // Save the starting line number. - sourcing_lnum_top = SOURCING_LNUM; + linenr_T sourcing_lnum_top = SOURCING_LNUM; - indent = 2; - nesting = 0; + int indent = 2; + int nesting = 0; while (true) { if (KeyTyped) { msg_scroll = true; @@ -2442,7 +2426,7 @@ void ex_function(exarg_T *eap) } // Detect line continuation: SOURCING_LNUM increased more than one. - sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie); + linenr_T sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie); if (SOURCING_LNUM < sourcing_lnum_off) { sourcing_lnum_off -= SOURCING_LNUM; } else { @@ -2641,7 +2625,7 @@ void ex_function(exarg_T *eap) // If there are no errors, add the function if (fudi.fd_dict == NULL) { - v = find_var(name, strlen(name), &ht, false); + dictitem_T *v = find_var(name, strlen(name), &ht, false); if (v != NULL && v->di_tv.v_type == VAR_FUNC) { emsg_funcname(N_("E707: Function name conflicts with variable: %s"), name); goto erret; @@ -2706,16 +2690,13 @@ void ex_function(exarg_T *eap) if (fp == NULL) { if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL) { - int slen, plen; - char *scriptname; - // Check that the autoload name matches the script name. int j = FAIL; if (SOURCING_NAME != NULL) { - scriptname = autoload_name(name, strlen(name)); + char *scriptname = autoload_name(name, strlen(name)); p = vim_strchr(scriptname, '/'); - plen = (int)strlen(p); - slen = (int)strlen(SOURCING_NAME); + int plen = (int)strlen(p); + int slen = (int)strlen(SOURCING_NAME); if (slen > plen && path_fnamecmp(p, SOURCING_NAME + slen - plen) == 0) { j = OK; } @@ -2753,7 +2734,7 @@ void ex_function(exarg_T *eap) // insert the new function in the function list set_ufunc_name(fp, name); if (overwrite) { - hi = hash_find(&func_hashtab, name); + hashitem_T *hi = hash_find(&func_hashtab, name); hi->hi_key = UF2HIKEY(fp); } else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) { xfree(fp); @@ -2862,7 +2843,6 @@ char *get_user_func_name(expand_T *xp, int idx) static size_t done; static int changed; static hashitem_T *hi; - ufunc_T *fp; if (idx == 0) { done = 0; @@ -2877,7 +2857,7 @@ char *get_user_func_name(expand_T *xp, int idx) while (HASHITEM_EMPTY(hi)) { hi++; } - fp = HI2UF(hi); + ufunc_T *fp = HI2UF(hi); if ((fp->uf_flags & FC_DICT) || strncmp(fp->uf_name, "", 8) == 0) { @@ -2904,12 +2884,10 @@ char *get_user_func_name(expand_T *xp, int idx) void ex_delfunction(exarg_T *eap) { ufunc_T *fp = NULL; - char *p; - char *name; funcdict_T fudi; - p = eap->arg; - name = trans_function_name(&p, eap->skip, 0, &fudi, NULL); + char *p = eap->arg; + char *name = trans_function_name(&p, eap->skip, 0, &fudi, NULL); xfree(fudi.fd_newkey); if (name == NULL) { if (fudi.fd_dict != NULL && !eap->skip) { @@ -2986,13 +2964,11 @@ void ex_delfunction(exarg_T *eap) /// becomes zero. void func_unref(char *name) { - ufunc_T *fp = NULL; - if (name == NULL || !func_name_refcount(name)) { return; } - fp = find_func(name); + ufunc_T *fp = find_func(name); if (fp == NULL && isdigit((uint8_t)(*name))) { #ifdef EXITFREE if (!entered_free_all_mem) { @@ -3028,12 +3004,10 @@ void func_ptr_unref(ufunc_T *fp) /// Count a reference to a Function. void func_ref(char *name) { - ufunc_T *fp; - if (name == NULL || !func_name_refcount(name)) { return; } - fp = find_func(name); + ufunc_T *fp = find_func(name); if (fp != NULL) { (fp->uf_refcount)++; } else if (isdigit((uint8_t)(*name))) { @@ -3333,10 +3307,6 @@ void invoke_all_defer(void) void ex_call(exarg_T *eap) { char *arg = eap->arg; - char *startarg; - char *name; - char *tofree; - int len; bool failed = false; funcdict_T fudi; partial_T *partial = NULL; @@ -3357,7 +3327,7 @@ void ex_call(exarg_T *eap) return; } - tofree = trans_function_name(&arg, false, TFN_INT, &fudi, &partial); + char *tofree = trans_function_name(&arg, false, TFN_INT, &fudi, &partial); if (fudi.fd_newkey != NULL) { // Still need to give an error message for missing key. semsg(_(e_dictkey), fudi.fd_newkey); @@ -3376,13 +3346,13 @@ void ex_call(exarg_T *eap) // If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its // contents. For VAR_PARTIAL get its partial, unless we already have one // from trans_function_name(). - len = (int)strlen(tofree); + int len = (int)strlen(tofree); bool found_var = false; - name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, false, &found_var); + char *name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, false, &found_var); // Skip white space to allow ":call func ()". Not good, but required for // backward compatibility. - startarg = skipwhite(arg); + char *startarg = skipwhite(arg); if (*startarg != '(') { semsg(_(e_missingparen), eap->arg); @@ -3435,7 +3405,6 @@ end: /// false when the return gets pending. int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) { - int idx; cstack_T *const cstack = eap->cstack; if (reanimate) { @@ -3447,7 +3416,7 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) // not in its finally clause (which then is to be executed next) is found. // In this case, make the ":return" pending for execution at the ":endtry". // Otherwise, return normally. - idx = cleanup_conditionals(eap->cstack, 0, true); + int idx = cleanup_conditionals(eap->cstack, 0, true); if (idx >= 0) { cstack->cs_pending[idx] = CSTP_RETURN; @@ -3531,7 +3500,6 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->fc_func; char *retval; - garray_T *gap; // growarray with function lines // If breakpoints have been added/deleted need to check for it. if (fcp->fc_dbg_tick != debug_tick) { @@ -3542,7 +3510,7 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) func_line_end(cookie); } - gap = &fp->uf_lines; + garray_T *gap = &fp->uf_lines; // growarray with function lines if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) || fcp->fc_returned) { retval = NULL; @@ -3904,15 +3872,11 @@ bool set_ref_in_call_stack(int copyID) /// Set "copyID" in all functions available by name. bool set_ref_in_functions(int copyID) { - int todo; - hashitem_T *hi = NULL; - ufunc_T *fp; - - todo = (int)func_hashtab.ht_used; - for (hi = func_hashtab.ht_array; todo > 0 && !got_int; hi++) { + int todo = (int)func_hashtab.ht_used; + for (hashitem_T *hi = func_hashtab.ht_array; todo > 0 && !got_int; hi++) { if (!HASHITEM_EMPTY(hi)) { todo--; - fp = HI2UF(hi); + ufunc_T *fp = HI2UF(hi); if (!func_name_refcount(fp->uf_name) && set_ref_in_func(NULL, fp, copyID)) { return true; @@ -3942,7 +3906,6 @@ bool set_ref_in_func_args(int copyID) bool set_ref_in_func(char *name, ufunc_T *fp_in, int copyID) { ufunc_T *fp = fp_in; - funccall_T *fc; int error = FCERR_NONE; char fname_buf[FLEN_FIXED + 1]; char *tofree = NULL; @@ -3956,7 +3919,7 @@ bool set_ref_in_func(char *name, ufunc_T *fp_in, int copyID) fp = find_func(fname); } if (fp != NULL) { - for (fc = fp->uf_scoped; fc != NULL; fc = fc->fc_func->uf_scoped) { + for (funccall_T *fc = fp->uf_scoped; fc != NULL; fc = fc->fc_func->uf_scoped) { abort = abort || set_ref_in_funccal(fc, copyID); } } -- cgit From a6e3d93421ba13c407a96fac9cc01fa41ec7ad98 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 16 Nov 2023 10:59:11 +0100 Subject: refactor: enable formatting for ternaries This requires removing the "Inner expression should be aligned" rule from clint as it prevents essentially any formatting regarding ternary operators. --- src/nvim/eval/userfunc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 822ac4d16a..e15320e391 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2446,7 +2446,7 @@ void ex_function(exarg_T *eap) p = theline; } else if (is_heredoc) { p = skipwhite(theline) == theline - ? theline : theline + strlen(heredoc_trimmed); + ? theline : theline + strlen(heredoc_trimmed); } else { p = theline + strlen(heredoc_trimmed); } @@ -3573,8 +3573,8 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) fp = rettv->vval.v_partial->pt_func; } else { char *fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING - ? rettv->vval.v_string - : rettv->vval.v_partial->pt_name; + ? rettv->vval.v_string + : rettv->vval.v_partial->pt_name; // Translate "s:func" to the stored function name. fname = fname_trans_sid(fname, fname_buf, &tofree, &error); fp = find_func(fname); -- cgit From 76635847086344b1b6e7ac9e9a4d9276852be000 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Wed, 15 Nov 2023 13:49:35 +0100 Subject: refactor: remove __clang_analyzer__ macro It is less intrusive to silence the warning with a comment instead of a macro if needed. --- src/nvim/eval/userfunc.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index e15320e391..c2c4405c31 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -671,9 +671,7 @@ static void cat_func_name(char *buf, size_t buflen, ufunc_T *fp) /// Add a number variable "name" to dict "dp" with value "nr". static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr) { -#ifndef __clang_analyzer__ STRCPY(v->di_key, name); -#endif v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; hash_add(&dp->dv_hashtab, v->di_key); v->di_tv.v_type = VAR_NUMBER; @@ -976,10 +974,8 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // Set l:self to "selfdict". Use "name" to avoid a warning from // some compiler that checks the destination size. v = (dictitem_T *)&fc->fc_fixvar[fixvar_idx++]; -#ifndef __clang_analyzer__ name = (char *)v->di_key; STRCPY(name, "self"); -#endif v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; hash_add(&fc->fc_l_vars.dv_hashtab, v->di_key); v->di_tv.v_type = VAR_DICT; @@ -1002,10 +998,8 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // Use "name" to avoid a warning from some compiler that checks the // destination size. v = (dictitem_T *)&fc->fc_fixvar[fixvar_idx++]; -#ifndef __clang_analyzer__ name = (char *)v->di_key; STRCPY(name, "000"); -#endif v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; hash_add(&fc->fc_l_avars.dv_hashtab, v->di_key); v->di_tv.v_type = VAR_LIST; -- cgit From 6361806aa28edca55ad3316a58bc3e936df9c0eb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Nov 2023 22:58:52 +0800 Subject: refactor: move garray_T to garray_defs.h (#26227) --- src/nvim/eval/userfunc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index c2c4405c31..cd1ee94298 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -24,6 +24,7 @@ #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/garray.h" +#include "nvim/garray_defs.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -- cgit From 574d25642fc9ca65b396633aeab6e2d32778b642 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 17:21:58 +0800 Subject: refactor: move Arena and ArenaMem to memory_defs.h (#26240) --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index cd1ee94298..13d1290fa2 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3,11 +3,11 @@ #include #include #include +#include #include #include #include -#include "lauxlib.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/charset.h" -- cgit From 8b428ca8b79ebb7b36c3e403ff3bcb6924a635a6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 16:00:21 +0100 Subject: build(IWYU): fix includes for func_attr.h --- src/nvim/eval/userfunc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 13d1290fa2..1597f0a524 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -23,6 +23,7 @@ #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" #include "nvim/getchar.h" -- cgit From 6c14ae6bfaf51415b555e9a6b85d1d280976358d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 20:27:32 +0100 Subject: refactor: rename types.h to types_defs.h --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 1597f0a524..c095dace92 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -45,7 +45,7 @@ #include "nvim/runtime.h" #include "nvim/search.h" #include "nvim/strings.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/vim.h" -- cgit From 1a8f60c7d2699826b51f23b040b83b1d96a14930 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 Nov 2023 10:47:22 +0800 Subject: refactor: move hashtab types to hashtab_defs.h (#26262) --- src/nvim/eval/userfunc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index c095dace92..a859b8a94d 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -25,7 +25,6 @@ #include "nvim/ex_getln.h" #include "nvim/func_attr.h" #include "nvim/garray.h" -#include "nvim/garray_defs.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -- cgit From 79b6ff28ad1204fbb4199b9092f5c578d88cb28e Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 28 Nov 2023 20:31:00 +0100 Subject: refactor: fix headers with IWYU --- src/nvim/eval/userfunc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index a859b8a94d..23b3c4e1b2 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -8,7 +8,7 @@ #include #include -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" @@ -32,7 +32,7 @@ #include "nvim/insexpand.h" #include "nvim/keycodes.h" #include "nvim/lua/executor.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" @@ -46,7 +46,7 @@ #include "nvim/strings.h" #include "nvim/types_defs.h" #include "nvim/ui.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/userfunc.c.generated.h" -- cgit