# HG changeset patch # User Christian Brabandt # Date 1528834506 -7200 # Node ID c1fcfafa8d1ab15afce3d624941c23e7d810cc7f # Parent e5b1d05b7b7759a5f6df9c8a90f5ca5e7fb47f83 patch 8.1.0053: first argument of 'completefunc' has inconsistent type commit https://github.com/vim/vim/commit/ffa9684150f5441e84d492e7184ef73587bd6c6c Author: Bram Moolenaar Date: Tue Jun 12 22:05:14 2018 +0200 patch 8.1.0053: first argument of 'completefunc' has inconsistent type Problem: The first argument given to 'completefunc' can be Number or String, depending on the value. Solution: Avoid guessing the type of an argument, use typval_T in the callers of call_vim_function(). (Ozaki Kiichi, closes #2993) diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -4201,7 +4201,7 @@ expand_by_function( { list_T *matchlist = NULL; dict_T *matchdict = NULL; - char_u *args[2]; + typval_T args[3]; char_u *funcname; pos_T pos; win_T *curwin_save; @@ -4213,15 +4213,18 @@ expand_by_function( return; /* Call 'completefunc' to obtain the list of matches. */ - args[0] = (char_u *)"0"; - args[1] = base; + args[0].v_type = VAR_NUMBER; + args[0].vval.v_number = 0; + args[1].v_type = VAR_STRING; + args[1].vval.v_string = base != NULL ? base : (char_u *)""; + args[2].v_type = VAR_UNKNOWN; pos = curwin->w_cursor; curwin_save = curwin; curbuf_save = curbuf; /* Call a function, which returns a list or dict. */ - if (call_vim_function(funcname, 2, args, FALSE, FALSE, &rettv) == OK) + if (call_vim_function(funcname, 2, args, &rettv, FALSE) == OK) { switch (rettv.v_type) { @@ -5528,7 +5531,7 @@ ins_complete(int c, int enable_pum) * Call user defined function 'completefunc' with "a:findstart" * set to 1 to obtain the length of text to use for completion. */ - char_u *args[2]; + typval_T args[3]; int col; char_u *funcname; pos_T pos; @@ -5548,8 +5551,11 @@ ins_complete(int c, int enable_pum) return FAIL; } - args[0] = (char_u *)"1"; - args[1] = NULL; + args[0].v_type = VAR_NUMBER; + args[0].vval.v_number = 1; + args[1].v_type = VAR_STRING; + args[1].vval.v_string = (char_u *)""; + args[2].v_type = VAR_UNKNOWN; pos = curwin->w_cursor; curwin_save = curwin; curbuf_save = curbuf; diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1011,63 +1011,22 @@ eval_expr(char_u *arg, char_u **nextcmd) /* * Call some Vim script function and return the result in "*rettv". - * Uses argv[argc] for the function arguments. Only Number and String - * arguments are currently supported. + * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] + * should have type VAR_UNKNOWN. * Returns OK or FAIL. */ int call_vim_function( char_u *func, int argc, - char_u **argv, - int safe, /* use the sandbox */ - int str_arg_only, /* all arguments are strings */ - typval_T *rettv) -{ - typval_T *argvars; - varnumber_T n; - int len; - int i; + typval_T *argv, + typval_T *rettv, + int safe) /* use the sandbox */ +{ int doesrange; void *save_funccalp = NULL; int ret; - argvars = (typval_T *)alloc((unsigned)((argc + 1) * sizeof(typval_T))); - if (argvars == NULL) - return FAIL; - - for (i = 0; i < argc; i++) - { - /* Pass a NULL or empty argument as an empty string */ - if (argv[i] == NULL || *argv[i] == NUL) - { - argvars[i].v_type = VAR_STRING; - argvars[i].vval.v_string = (char_u *)""; - continue; - } - - if (str_arg_only) - len = 0; - else - { - /* Recognize a number argument, the others must be strings. A dash - * is a string too. */ - vim_str2nr(argv[i], NULL, &len, STR2NR_ALL, &n, NULL, 0); - if (len == 1 && *argv[i] == '-') - len = 0; - } - if (len != 0 && len == (int)STRLEN(argv[i])) - { - argvars[i].v_type = VAR_NUMBER; - argvars[i].vval.v_number = n; - } - else - { - argvars[i].v_type = VAR_STRING; - argvars[i].vval.v_string = argv[i]; - } - } - if (safe) { save_funccalp = save_funccal(); @@ -1075,7 +1034,7 @@ call_vim_function( } rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */ - ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars, NULL, + ret = call_func(func, (int)STRLEN(func), rettv, argc, argv, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum, &doesrange, TRUE, NULL, NULL); if (safe) @@ -1083,7 +1042,6 @@ call_vim_function( --sandbox; restore_funccal(save_funccalp); } - vim_free(argvars); if (ret == FAIL) clear_tv(rettv); @@ -1094,20 +1052,20 @@ call_vim_function( /* * Call Vim script function "func" and return the result as a number. * Returns -1 when calling the function fails. - * Uses argv[argc] for the function arguments. + * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should + * have type VAR_UNKNOWN. */ varnumber_T call_func_retnr( char_u *func, int argc, - char_u **argv, + typval_T *argv, int safe) /* use the sandbox */ { typval_T rettv; varnumber_T retval; - /* All arguments are passed as strings, no conversion to number. */ - if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL) return -1; retval = get_tv_number_chk(&rettv, NULL); @@ -1122,20 +1080,20 @@ call_func_retnr( /* * Call Vim script function "func" and return the result as a string. * Returns NULL when calling the function fails. - * Uses argv[argc] for the function arguments. + * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should + * have type VAR_UNKNOWN. */ void * call_func_retstr( char_u *func, int argc, - char_u **argv, + typval_T *argv, int safe) /* use the sandbox */ { typval_T rettv; char_u *retval; - /* All arguments are passed as strings, no conversion to number. */ - if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL) return NULL; retval = vim_strsave(get_tv_string(&rettv)); @@ -1146,20 +1104,20 @@ call_func_retstr( /* * Call Vim script function "func" and return the result as a List. - * Uses argv[argc] for the function arguments. + * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should + * have type VAR_UNKNOWN. * Returns NULL when there is something wrong. */ void * call_func_retlist( char_u *func, int argc, - char_u **argv, + typval_T *argv, int safe) /* use the sandbox */ { typval_T rettv; - /* All arguments are passed as strings, no conversion to number. */ - if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL) return NULL; if (rettv.v_type != VAR_LIST) diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -5266,7 +5266,7 @@ expand_shellcmd( # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) -static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, char_u **, int), expand_T *xp, int *num_file, char_u ***file); +static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, typval_T *, int), expand_T *xp, int *num_file, char_u ***file); /* * Call "user_expand_func()" to invoke a user defined Vim script function and @@ -5274,15 +5274,15 @@ static void * call_user_expand_func(void */ static void * call_user_expand_func( - void *(*user_expand_func)(char_u *, int, char_u **, int), + void *(*user_expand_func)(char_u *, int, typval_T *, int), expand_T *xp, int *num_file, char_u ***file) { int keep = 0; - char_u num[50]; - char_u *args[3]; + typval_T args[4]; int save_current_SID = current_SID; + char_u *pat = NULL; void *ret; struct cmdline_info save_ccline; @@ -5297,10 +5297,15 @@ call_user_expand_func( ccline.cmdbuff[ccline.cmdlen] = 0; } - args[0] = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len); - args[1] = xp->xp_line; - sprintf((char *)num, "%d", xp->xp_col); - args[2] = num; + pat = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len); + + args[0].v_type = VAR_STRING; + args[0].vval.v_string = pat; + args[1].v_type = VAR_STRING; + args[1].vval.v_string = xp->xp_line; + args[2].v_type = VAR_NUMBER; + args[2].vval.v_number = xp->xp_col; + args[3].v_type = VAR_UNKNOWN; /* Save the cmdline, we don't know what the function may do. */ save_ccline = ccline; @@ -5315,7 +5320,7 @@ call_user_expand_func( if (ccline.cmdbuff != NULL) ccline.cmdbuff[ccline.cmdlen] = keep; - vim_free(args[0]); + vim_free(pat); return ret; } diff --git a/src/mbyte.c b/src/mbyte.c --- a/src/mbyte.c +++ b/src/mbyte.c @@ -4795,12 +4795,11 @@ iconv_end(void) static void call_imactivatefunc(int active) { - char_u *argv[1]; - - if (active) - argv[0] = (char_u *)"1"; - else - argv[0] = (char_u *)"0"; + typval_T argv[2]; + + argv[0].v_type = VAR_NUMBER; + argv[0].vval.v_number = active ? 1 : 0; + argv[1].v_type = VAR_NUMBER; (void)call_func_retnr(p_imaf, 1, argv, FALSE); } diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -2219,7 +2219,7 @@ op_colon(oparg_T *oap) op_function(oparg_T *oap UNUSED) { #ifdef FEAT_EVAL - char_u *(argv[1]); + typval_T argv[2]; # ifdef FEAT_VIRTUALEDIT int save_virtual_op = virtual_op; # endif @@ -2235,12 +2235,14 @@ op_function(oparg_T *oap UNUSED) /* Exclude the end position. */ decl(&curbuf->b_op_end); + argv[0].v_type = VAR_STRING; if (oap->block_mode) - argv[0] = (char_u *)"block"; + argv[0].vval.v_string = (char_u *)"block"; else if (oap->motion_type == MLINE) - argv[0] = (char_u *)"line"; + argv[0].vval.v_string = (char_u *)"line"; else - argv[0] = (char_u *)"char"; + argv[0].vval.v_string = (char_u *)"char"; + argv[1].v_type = VAR_UNKNOWN; # ifdef FEAT_VIRTUALEDIT /* Reset virtual_op so that 'virtualedit' can be changed in the diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -19,10 +19,10 @@ varnumber_T eval_to_number(char_u *expr) list_T *eval_spell_expr(char_u *badword, char_u *expr); int get_spellword(list_T *list, char_u **pp); typval_T *eval_expr(char_u *arg, char_u **nextcmd); -int call_vim_function(char_u *func, int argc, char_u **argv, int safe, int str_arg_only, typval_T *rettv); -varnumber_T call_func_retnr(char_u *func, int argc, char_u **argv, int safe); -void *call_func_retstr(char_u *func, int argc, char_u **argv, int safe); -void *call_func_retlist(char_u *func, int argc, char_u **argv, int safe); +int call_vim_function(char_u *func, int argc, typval_T *argv, typval_T *rettv, int safe); +varnumber_T call_func_retnr(char_u *func, int argc, typval_T *argv, int safe); +void *call_func_retstr(char_u *func, int argc, typval_T *argv, int safe); +void *call_func_retlist(char_u *func, int argc, typval_T *argv, int safe); int eval_foldexpr(char_u *arg, int *cp); void ex_let(exarg_T *eap); void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *first); diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -117,6 +117,31 @@ func Test_omni_dash() set omnifunc= endfunc +func Test_completefunc_args() + let s:args = [] + func! CompleteFunc(findstart, base) + let s:args += [[a:findstart, empty(a:base)]] + endfunc + new + + set completefunc=CompleteFunc + call feedkeys("i\\\", 'x') + call assert_equal(s:args[0], [1, 1]) + call assert_equal(s:args[1][0], 0) + set completefunc= + + let s:args = [] + set omnifunc=CompleteFunc + call feedkeys("i\\\", 'x') + call assert_equal(s:args[0], [1, 1]) + call assert_equal(s:args[1][0], 0) + set omnifunc= + + bwipe! + unlet s:args + delfunc CompleteFunc +endfunc + function! s:CompleteDone_CompleteFuncDict( findstart, base ) if a:findstart return 0 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 53, +/**/ 52, /**/ 51,