]> granicus.if.org Git - vim/commitdiff
patch 8.1.0053: first argument of 'completefunc' has inconsistent type v8.1.0053
authorBram Moolenaar <Bram@vim.org>
Tue, 12 Jun 2018 20:05:14 +0000 (22:05 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 12 Jun 2018 20:05:14 +0000 (22:05 +0200)
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)

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

index 731b9dc7ff21c621ef3822c0aecedfbb178f2a55..92c9d6ad447e202597c22c542972c81cebd0b145 100644 (file)
@@ -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;
index 2ba9e82a80dde7b43f4055adcddc81d1a56de0f5..26aa0e34e71d778620cc69bf9f845c8eed7fe250 100644 (file)
@@ -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   *argv,
+    typval_T   *rettv,
+    int                safe)           /* use the sandbox */
 {
-    typval_T   *argvars;
-    varnumber_T        n;
-    int                len;
-    int                i;
     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)
index c4b9acd75d1da5272973a11dd17aa5cab1d5b8b5..063900a388d3295cf1b671e2233dc0157b28f922 100644 (file)
@@ -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 *(*user_expand_func)(char_u *, int, cha
  */
     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;
 }
 
index b79783527a86f5beb52891b5143e743616b788d2..545a40db0feb26b3f6d365f9a296eaa2195e1ebc 100644 (file)
@@ -4795,12 +4795,11 @@ iconv_end(void)
     static void
 call_imactivatefunc(int active)
 {
-    char_u *argv[1];
+    typval_T argv[2];
 
-    if (active)
-       argv[0] = (char_u *)"1";
-    else
-       argv[0] = (char_u *)"0";
+    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);
 }
 
index a01a434867965181b25f4229dae5a7c6ea2b1a88..4d51c33206b579759510daee37084308ac505c82 100644 (file)
@@ -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
index a096156ae06e6de3dc3edf82fd25a71f87ca1d6f..0906a68d3f77b3c02c5787a3a0952e84ebdad53b 100644 (file)
@@ -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);
index 020e2288201b1f62ee68f2e36a727cf81d1b688a..2b4356ea3821502a07fd859d024e9734da689ca2 100644 (file)
@@ -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
index 3187cf284570c5125a965df0762290990fcbc384..2ea298bc3b4b9fda453d51d9569bf87bbbd9a7a7 100644 (file)
@@ -761,6 +761,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    53,
 /**/
     52,
 /**/