0
0
mirror of https://github.com/vim/vim.git synced 2025-07-04 23:07:33 -04:00

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)
This commit is contained in:
Bram Moolenaar 2018-06-12 22:05:14 +02:00
parent 83f4cbd973
commit ffa9684150
8 changed files with 86 additions and 89 deletions

View File

@ -4201,7 +4201,7 @@ expand_by_function(
{ {
list_T *matchlist = NULL; list_T *matchlist = NULL;
dict_T *matchdict = NULL; dict_T *matchdict = NULL;
char_u *args[2]; typval_T args[3];
char_u *funcname; char_u *funcname;
pos_T pos; pos_T pos;
win_T *curwin_save; win_T *curwin_save;
@ -4213,15 +4213,18 @@ expand_by_function(
return; return;
/* Call 'completefunc' to obtain the list of matches. */ /* Call 'completefunc' to obtain the list of matches. */
args[0] = (char_u *)"0"; args[0].v_type = VAR_NUMBER;
args[1] = base; 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; pos = curwin->w_cursor;
curwin_save = curwin; curwin_save = curwin;
curbuf_save = curbuf; curbuf_save = curbuf;
/* Call a function, which returns a list or dict. */ /* 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) switch (rettv.v_type)
{ {
@ -5528,7 +5531,7 @@ ins_complete(int c, int enable_pum)
* Call user defined function 'completefunc' with "a:findstart" * Call user defined function 'completefunc' with "a:findstart"
* set to 1 to obtain the length of text to use for completion. * set to 1 to obtain the length of text to use for completion.
*/ */
char_u *args[2]; typval_T args[3];
int col; int col;
char_u *funcname; char_u *funcname;
pos_T pos; pos_T pos;
@ -5548,8 +5551,11 @@ ins_complete(int c, int enable_pum)
return FAIL; return FAIL;
} }
args[0] = (char_u *)"1"; args[0].v_type = VAR_NUMBER;
args[1] = NULL; 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; pos = curwin->w_cursor;
curwin_save = curwin; curwin_save = curwin;
curbuf_save = curbuf; curbuf_save = curbuf;

View File

@ -1011,63 +1011,22 @@ eval_expr(char_u *arg, char_u **nextcmd)
/* /*
* Call some Vim script function and return the result in "*rettv". * Call some Vim script function and return the result in "*rettv".
* Uses argv[argc] for the function arguments. Only Number and String * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc]
* arguments are currently supported. * should have type VAR_UNKNOWN.
* Returns OK or FAIL. * Returns OK or FAIL.
*/ */
int int
call_vim_function( call_vim_function(
char_u *func, char_u *func,
int argc, int argc,
char_u **argv, typval_T *argv,
int safe, /* use the sandbox */ typval_T *rettv,
int str_arg_only, /* all arguments are strings */ int safe) /* use the sandbox */
typval_T *rettv)
{ {
typval_T *argvars;
varnumber_T n;
int len;
int i;
int doesrange; int doesrange;
void *save_funccalp = NULL; void *save_funccalp = NULL;
int ret; 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) if (safe)
{ {
save_funccalp = save_funccal(); save_funccalp = save_funccal();
@ -1075,7 +1034,7 @@ call_vim_function(
} }
rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */ 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, curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&doesrange, TRUE, NULL, NULL); &doesrange, TRUE, NULL, NULL);
if (safe) if (safe)
@ -1083,7 +1042,6 @@ call_vim_function(
--sandbox; --sandbox;
restore_funccal(save_funccalp); restore_funccal(save_funccalp);
} }
vim_free(argvars);
if (ret == FAIL) if (ret == FAIL)
clear_tv(rettv); clear_tv(rettv);
@ -1094,20 +1052,20 @@ call_vim_function(
/* /*
* Call Vim script function "func" and return the result as a number. * Call Vim script function "func" and return the result as a number.
* Returns -1 when calling the function fails. * 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 varnumber_T
call_func_retnr( call_func_retnr(
char_u *func, char_u *func,
int argc, int argc,
char_u **argv, typval_T *argv,
int safe) /* use the sandbox */ int safe) /* use the sandbox */
{ {
typval_T rettv; typval_T rettv;
varnumber_T retval; varnumber_T retval;
/* All arguments are passed as strings, no conversion to number. */ if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL)
if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
return -1; return -1;
retval = get_tv_number_chk(&rettv, NULL); 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. * Call Vim script function "func" and return the result as a string.
* Returns NULL when calling the function fails. * 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 * void *
call_func_retstr( call_func_retstr(
char_u *func, char_u *func,
int argc, int argc,
char_u **argv, typval_T *argv,
int safe) /* use the sandbox */ int safe) /* use the sandbox */
{ {
typval_T rettv; typval_T rettv;
char_u *retval; char_u *retval;
/* All arguments are passed as strings, no conversion to number. */ if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL)
if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
return NULL; return NULL;
retval = vim_strsave(get_tv_string(&rettv)); 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. * 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. * Returns NULL when there is something wrong.
*/ */
void * void *
call_func_retlist( call_func_retlist(
char_u *func, char_u *func,
int argc, int argc,
char_u **argv, typval_T *argv,
int safe) /* use the sandbox */ int safe) /* use the sandbox */
{ {
typval_T rettv; typval_T rettv;
/* All arguments are passed as strings, no conversion to number. */ if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL)
if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
return NULL; return NULL;
if (rettv.v_type != VAR_LIST) if (rettv.v_type != VAR_LIST)

View File

@ -5266,7 +5266,7 @@ expand_shellcmd(
# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) # 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 * Call "user_expand_func()" to invoke a user defined Vim script function and
@ -5274,15 +5274,15 @@ static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, cha
*/ */
static void * static void *
call_user_expand_func( 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, expand_T *xp,
int *num_file, int *num_file,
char_u ***file) char_u ***file)
{ {
int keep = 0; int keep = 0;
char_u num[50]; typval_T args[4];
char_u *args[3];
int save_current_SID = current_SID; int save_current_SID = current_SID;
char_u *pat = NULL;
void *ret; void *ret;
struct cmdline_info save_ccline; struct cmdline_info save_ccline;
@ -5297,10 +5297,15 @@ call_user_expand_func(
ccline.cmdbuff[ccline.cmdlen] = 0; ccline.cmdbuff[ccline.cmdlen] = 0;
} }
args[0] = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len); pat = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len);
args[1] = xp->xp_line;
sprintf((char *)num, "%d", xp->xp_col); args[0].v_type = VAR_STRING;
args[2] = num; 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 the cmdline, we don't know what the function may do. */
save_ccline = ccline; save_ccline = ccline;
@ -5315,7 +5320,7 @@ call_user_expand_func(
if (ccline.cmdbuff != NULL) if (ccline.cmdbuff != NULL)
ccline.cmdbuff[ccline.cmdlen] = keep; ccline.cmdbuff[ccline.cmdlen] = keep;
vim_free(args[0]); vim_free(pat);
return ret; return ret;
} }

View File

@ -4795,12 +4795,11 @@ iconv_end(void)
static void static void
call_imactivatefunc(int active) call_imactivatefunc(int active)
{ {
char_u *argv[1]; typval_T argv[2];
if (active) argv[0].v_type = VAR_NUMBER;
argv[0] = (char_u *)"1"; argv[0].vval.v_number = active ? 1 : 0;
else argv[1].v_type = VAR_NUMBER;
argv[0] = (char_u *)"0";
(void)call_func_retnr(p_imaf, 1, argv, FALSE); (void)call_func_retnr(p_imaf, 1, argv, FALSE);
} }

View File

@ -2219,7 +2219,7 @@ op_colon(oparg_T *oap)
op_function(oparg_T *oap UNUSED) op_function(oparg_T *oap UNUSED)
{ {
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
char_u *(argv[1]); typval_T argv[2];
# ifdef FEAT_VIRTUALEDIT # ifdef FEAT_VIRTUALEDIT
int save_virtual_op = virtual_op; int save_virtual_op = virtual_op;
# endif # endif
@ -2235,12 +2235,14 @@ op_function(oparg_T *oap UNUSED)
/* Exclude the end position. */ /* Exclude the end position. */
decl(&curbuf->b_op_end); decl(&curbuf->b_op_end);
argv[0].v_type = VAR_STRING;
if (oap->block_mode) if (oap->block_mode)
argv[0] = (char_u *)"block"; argv[0].vval.v_string = (char_u *)"block";
else if (oap->motion_type == MLINE) else if (oap->motion_type == MLINE)
argv[0] = (char_u *)"line"; argv[0].vval.v_string = (char_u *)"line";
else else
argv[0] = (char_u *)"char"; argv[0].vval.v_string = (char_u *)"char";
argv[1].v_type = VAR_UNKNOWN;
# ifdef FEAT_VIRTUALEDIT # ifdef FEAT_VIRTUALEDIT
/* Reset virtual_op so that 'virtualedit' can be changed in the /* Reset virtual_op so that 'virtualedit' can be changed in the

View File

@ -19,10 +19,10 @@ varnumber_T eval_to_number(char_u *expr);
list_T *eval_spell_expr(char_u *badword, char_u *expr); list_T *eval_spell_expr(char_u *badword, char_u *expr);
int get_spellword(list_T *list, char_u **pp); int get_spellword(list_T *list, char_u **pp);
typval_T *eval_expr(char_u *arg, char_u **nextcmd); 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); 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, char_u **argv, 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, char_u **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, char_u **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); int eval_foldexpr(char_u *arg, int *cp);
void ex_let(exarg_T *eap); void ex_let(exarg_T *eap);
void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *first); void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *first);

View File

@ -117,6 +117,31 @@ func Test_omni_dash()
set omnifunc= set omnifunc=
endfunc 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\<C-X>\<C-U>\<Esc>", '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\<C-X>\<C-O>\<Esc>", '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 ) function! s:CompleteDone_CompleteFuncDict( findstart, base )
if a:findstart if a:findstart
return 0 return 0

View File

@ -761,6 +761,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
53,
/**/ /**/
52, 52,
/**/ /**/