summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-07-31 14:11:58 +0200
committerBram Moolenaar <Bram@vim.org>2016-07-31 14:11:58 +0200
commitb54c3ff3174dbb5dfbfcabdf95200b047beaa644 (patch)
treea230032c07f9373c65ca64e4b9c237e70b4d6a54
parentfc1f2015e833e69b89b994faf4b2c4fc1e09220f (diff)
patch 7.4.2134v7.4.2134
Problem: No error for using function() badly. Solution: Check for passing wrong function name. (Ken Takata)
-rw-r--r--src/eval.c2
-rw-r--r--src/evalfunc.c4
-rw-r--r--src/proto/userfunc.pro2
-rw-r--r--src/testdir/test_expr.vim7
-rw-r--r--src/userfunc.c17
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h1
7 files changed, 25 insertions, 10 deletions
diff --git a/src/eval.c b/src/eval.c
index 956f05cb1f..cf2c771438 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -7813,7 +7813,7 @@ var_check_func_name(
/* Don't allow hiding a function. When "v" is not NULL we might be
* assigning another function to the same var, the type is checked
* below. */
- if (new_var && function_exists(name))
+ if (new_var && function_exists(name, FALSE))
{
EMSG2(_("E705: Variable name conflicts with existing function: %s"),
name);
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 9905d0ba74..13864ea3a7 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -2845,7 +2845,7 @@ f_exists(typval_T *argvars, typval_T *rettv)
}
else if (*p == '*') /* internal or user defined function */
{
- n = function_exists(p + 1);
+ n = function_exists(p + 1, FALSE);
}
else if (*p == ':')
{
@@ -3577,7 +3577,7 @@ f_function(typval_T *argvars, typval_T *rettv)
EMSG2(_(e_invarg2), s);
/* Don't check an autoload name for existence here. */
else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
- && !function_exists(s))
+ && !function_exists(s, TRUE))
EMSG2(_("E700: Unknown function: %s"), s);
else
{
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
index 42c5883d01..bd39604478 100644
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -9,7 +9,7 @@ int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typva
void ex_function(exarg_T *eap);
int eval_fname_script(char_u *p);
int translated_function_exists(char_u *name);
-int function_exists(char_u *name);
+int function_exists(char_u *name, int no_deref);
char_u *get_expanded_name(char_u *name, int check);
void func_dump_profile(FILE *fd);
void prof_child_enter(proftime_T *tm);
diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim
index 8db4d8e5f3..d8abc27523 100644
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -172,3 +172,10 @@ func Test_substitute_expr_arg()
call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
endfunc
+
+func Test_function_with_funcref()
+ let s:f = function('type')
+ let s:fref = function(s:f)
+ call assert_equal(v:t_string, s:fref('x'))
+ call assert_fails("call function('s:f')", 'E700:')
+endfunc
diff --git a/src/userfunc.c b/src/userfunc.c
index 0c6c613e3e..3c6401f7d7 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -295,7 +295,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
if (ret == FAIL || **arg != '>')
goto errret;
- /* Set up dictionaries for checking local variables and arguments. */
+ /* Set up a flag for checking local variables and arguments. */
if (evaluate)
eval_lavars_used = &eval_lavars;
@@ -1504,6 +1504,7 @@ list_func_head(ufunc_T *fp, int indent)
* TFN_INT: internal function name OK
* TFN_QUIET: be quiet
* TFN_NO_AUTOLOAD: do not use script autoloading
+ * TFN_NO_DEREF: do not dereference a Funcref
* Advances "pp" to just after the function name (if no error).
*/
static char_u *
@@ -1618,7 +1619,7 @@ trans_function_name(
if (name == lv.ll_exp_name)
name = NULL;
}
- else
+ else if (!(flags & TFN_NO_DEREF))
{
len = (int)(end - *pp);
name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD);
@@ -1690,7 +1691,7 @@ trans_function_name(
start);
goto theend;
}
- if (!skip && !(flags & TFN_QUIET))
+ if (!skip && !(flags & TFN_QUIET) && !(flags & TFN_NO_DEREF))
{
char_u *cp = vim_strchr(lv.ll_name, ':');
@@ -2381,16 +2382,20 @@ translated_function_exists(char_u *name)
/*
* Return TRUE if a function "name" exists.
+ * If "no_defef" is TRUE, do not dereference a Funcref.
*/
int
-function_exists(char_u *name)
+function_exists(char_u *name, int no_deref)
{
char_u *nm = name;
char_u *p;
int n = FALSE;
+ int flag;
- p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD,
- NULL, NULL);
+ flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
+ if (no_deref)
+ flag |= TFN_NO_DEREF;
+ p = trans_function_name(&nm, FALSE, flag, NULL, NULL);
nm = skipwhite(nm);
/* Only accept "funcname", "funcname ", "funcname (..." and
diff --git a/src/version.c b/src/version.c
index 5808cbc32f..8ef6dec48a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -764,6 +764,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2134,
+/**/
2133,
/**/
2132,
diff --git a/src/vim.h b/src/vim.h
index 7560982711..34a8650c49 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -2458,6 +2458,7 @@ int vim_main2(int argc, char **argv);
#define TFN_INT 1 /* internal function name OK */
#define TFN_QUIET 2 /* no error messages */
#define TFN_NO_AUTOLOAD 4 /* do not use script autoloading */
+#define TFN_NO_DEREF 8 /* do not dereference a Funcref */
/* Values for get_lval() flags argument: */
#define GLV_QUIET TFN_QUIET /* no error messages */