changeset 14071:c1fcfafa8d1a v8.1.0053

patch 8.1.0053: first argument of 'completefunc' has inconsistent type commit https://github.com/vim/vim/commit/ffa9684150f5441e84d492e7184ef73587bd6c6c Author: Bram Moolenaar <Bram@vim.org> 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)
author Christian Brabandt <cb@256bit.org>
date Tue, 12 Jun 2018 22:15:06 +0200
parents e5b1d05b7b77
children da680e50bcde
files src/edit.c src/eval.c src/ex_getln.c src/mbyte.c src/normal.c src/proto/eval.pro src/testdir/test_ins_complete.vim src/version.c
diffstat 8 files changed, 88 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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)
--- 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;
 }
 
--- 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);
 }
 
--- 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
--- 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);
--- 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\<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 )
   if a:findstart
     return 0
--- 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,