aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Ennen <mike.ennen@gmail.com>2016-12-17 18:01:24 -0700
committerMichael Ennen <mike.ennen@gmail.com>2017-02-14 17:38:17 -0700
commit1e3c0efa0f3d41563f91097d04b3616848d5eb62 (patch)
tree31841b7e60bd87f9ffc6d8992d2df65994fff5ae
parentd7c798cd863611754c5ff1c92fbc0b9c12479a47 (diff)
downloadrneovim-1e3c0efa0f3d41563f91097d04b3616848d5eb62.tar.gz
rneovim-1e3c0efa0f3d41563f91097d04b3616848d5eb62.tar.bz2
rneovim-1e3c0efa0f3d41563f91097d04b3616848d5eb62.zip
vim-patch:7.4.2134
Problem: No error for using function() badly. Solution: Check for passing wrong function name. (Ken Takata) https://github.com/vim/vim/commit/b54c3ff3174dbb5dfbfcabdf95200b047beaa644
-rw-r--r--src/nvim/eval.c95
-rw-r--r--src/nvim/testdir/test_expr.vim7
-rw-r--r--src/nvim/version.c2
3 files changed, 62 insertions, 42 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index e84742abcf..d1b60d67b6 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -200,14 +200,15 @@ static garray_T ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL};
static int echo_attr = 0; /* attributes used for ":echo" */
-/* Values for trans_function_name() argument: */
-#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 */
+// Values for trans_function_name() argument:
+#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 */
-#define GLV_NO_AUTOLOAD TFN_NO_AUTOLOAD /* do not use script autoloading */
+// Values for get_lval() flags argument:
+#define GLV_QUIET TFN_QUIET // no error messages
+#define GLV_NO_AUTOLOAD TFN_NO_AUTOLOAD // do not use script autoloading
// function flags
#define FC_ABORT 1 // abort function on error
@@ -7018,7 +7019,8 @@ err_ret:
}
/// Parse a lambda expression and get a Funcref from "*arg".
-/// Return OK or FAIL. Returns NOTDONE for dict or {expr}.
+///
+/// @return OK or FAIL. Returns NOTDONE for dict or {expr}.
static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
{
garray_T newargs;
@@ -7056,7 +7058,7 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
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;
}
@@ -9242,12 +9244,13 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
n = TRUE;
xfree(p);
}
- } else if (*p == '&' || *p == '+') { /* option */
- n = (get_option_tv(&p, NULL, TRUE) == OK);
- if (*skipwhite(p) != NUL)
- n = FALSE; /* trailing garbage */
- } else if (*p == '*') { /* internal or user defined function */
- n = function_exists(p + 1);
+ } else if (*p == '&' || *p == '+') { // option
+ n = (get_option_tv(&p, NULL, true) == OK);
+ if (*skipwhite(p) != NUL) {
+ n = false; // trailing garbage
+ }
+ } else if (*p == '*') { // internal or user defined function
+ n = function_exists(p + 1, false);
} else if (*p == ':') {
n = cmd_exists(p + 1);
} else if (*p == '#') {
@@ -10019,7 +10022,7 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (s == NULL || *s == NUL || (use_string && ascii_isdigit(*s))) {
EMSG2(_(e_invarg2), s);
} else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
- && !function_exists(s)) {
+ && !function_exists(s, true)) {
// Don't check an autoload name for existence here.
EMSG2(_("E700: Unknown function: %s"), s);
} else {
@@ -20457,10 +20460,10 @@ var_check_func_name (
EMSG2(_("E704: Funcref variable name must start with a capital: %s"), name);
return TRUE;
}
- /* 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)) {
+ // 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, false)) {
EMSG2(_("E705: Variable name conflicts with existing function: %s"),
name);
return TRUE;
@@ -21397,16 +21400,16 @@ ret_free:
need_wait_return |= saved_wait_return;
}
-/*
- * Get a function name, translating "<SID>" and "<SNR>".
- * Also handles a Funcref in a List or Dictionary.
- * Returns the function name in allocated memory, or NULL for failure.
- * flags:
- * TFN_INT: internal function name OK
- * TFN_QUIET: be quiet
- * TFN_NO_AUTOLOAD: do not use script autoloading
- * Advances "pp" to just after the function name (if no error).
- */
+/// Get a function name, translating "<SID>" and "<SNR>".
+/// Also handles a Funcref in a List or Dictionary.
+/// flags:
+/// 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).
+///
+/// @return the function name in allocated memory, or NULL for failure.
static char_u *
trans_function_name (
char_u **pp,
@@ -21509,7 +21512,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);
if (name == *pp) {
@@ -21572,7 +21575,7 @@ trans_function_name (
goto theend;
}
- if (!skip && !(flags & TFN_QUIET)) {
+ if (!skip && !(flags & TFN_QUIET) && !(flags & TFN_NO_DEREF)) {
char_u *cp = vim_strchr(lv.ll_name, ':');
if (cp != NULL && cp < end) {
@@ -21709,17 +21712,23 @@ int translated_function_exists(char_u *name)
return find_func(name) != NULL;
}
-/*
- * Return TRUE if a function "name" exists.
- */
-static int function_exists(char_u *name)
+/// Check if a function exists by name
+///
+/// @param[in] name The name of the function to check.
+/// @param[in] no_deref If true, do not dereference a Funcref.
+///
+/// @return true if a function "name" exists.
+static int function_exists(char_u *name, bool no_deref)
{
char_u *nm = name;
char_u *p;
- int n = FALSE;
+ int n = false;
+ int flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
- p = trans_function_name(&nm, false, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD,
- NULL, NULL);
+ 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
@@ -21730,9 +21739,13 @@ static int function_exists(char_u *name)
return n;
}
-/// Return TRUE if "name" looks like a builtin function name: starts with a
+/// Checks if a builtin function with the given name exists.
+///
+/// @param[in] name The name of the builtin function to check.
+/// @param[in] len The length of "name", or -1 for NUL terminated.
+///
+/// @return true if "name" looks like a builtin function name: starts with a
/// lower case letter and doesn't contain AUTOLOAD_CHAR.
-/// "len" is the length of "name", or -1 for NUL terminated.
static bool builtin_function(char_u *name, int len)
{
if (!ASCII_ISLOWER(name[0])) {
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 0c4a91298c..7e43af9ebd 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -143,3 +143,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/nvim/version.c b/src/nvim/version.c
index f2a10c1143..9134ee04ff 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -306,7 +306,7 @@ static int included_patches[] = {
// 2137,
// 2136,
// 2135,
- // 2134,
+ 2134,
// 2133 NA
// 2132 NA
// 2131 NA