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

patch 8.2.4123: complete function cannot be import.Name

Problem:    Complete function cannot be import.Name.
Solution:   Dereference the function name if needed.  Also: do not see
            "import.Name" as a builtin function. (closes #9541)
This commit is contained in:
Bram Moolenaar 2022-01-17 20:09:08 +00:00
parent 3f3597be3f
commit 15d1635e50
4 changed files with 114 additions and 49 deletions

View File

@ -625,6 +625,63 @@ eval_expr(char_u *arg, exarg_T *eap)
return tv;
}
/*
* "*arg" points to what can be a function name in the form of "import.Name" or
* "Funcref". Return the name of the function. Set "tofree" to something that
* was allocated.
* If "verbose" is FALSE no errors are given.
* Return NULL for any failure.
*/
static char_u *
deref_function_name(
char_u **arg,
char_u **tofree,
evalarg_T *evalarg,
int verbose)
{
typval_T ref;
char_u *name = *arg;
ref.v_type = VAR_UNKNOWN;
if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
return NULL;
if (*skipwhite(*arg) != NUL)
{
if (verbose)
semsg(_(e_trailing_characters_str), *arg);
name = NULL;
}
else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL)
{
name = ref.vval.v_string;
ref.vval.v_string = NULL;
*tofree = name;
}
else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL)
{
if (ref.vval.v_partial->pt_argc > 0
|| ref.vval.v_partial->pt_dict != NULL)
{
if (verbose)
emsg(_(e_cannot_use_partial_here));
name = NULL;
}
else
{
name = vim_strsave(partial_name(ref.vval.v_partial));
*tofree = name;
}
}
else
{
if (verbose)
semsg(_(e_not_callable_type_str), name);
name = NULL;
}
clear_tv(&ref);
return name;
}
/*
* Call some Vim script function and return the result in "*rettv".
* Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc]
@ -640,15 +697,27 @@ call_vim_function(
{
int ret;
funcexe_T funcexe;
char_u *arg;
char_u *name;
char_u *tofree = NULL;
rettv->v_type = VAR_UNKNOWN; // clear_tv() uses this
CLEAR_FIELD(funcexe);
funcexe.fe_firstline = curwin->w_cursor.lnum;
funcexe.fe_lastline = curwin->w_cursor.lnum;
funcexe.fe_evaluate = TRUE;
ret = call_func(func, -1, rettv, argc, argv, &funcexe);
// The name might be "import.Func" or "Funcref".
arg = func;
name = deref_function_name(&arg, &tofree, &EVALARG_EVALUATE, FALSE);
if (name == NULL)
name = func;
ret = call_func(name, -1, rettv, argc, argv, &funcexe);
if (ret == FAIL)
clear_tv(rettv);
vim_free(tofree);
return ret;
}
@ -3979,57 +4048,16 @@ eval_method(
if (**arg != '(' && alias == NULL
&& (paren = vim_strchr(*arg, '(')) != NULL)
{
typval_T ref;
*arg = name;
*paren = NUL;
ref.v_type = VAR_UNKNOWN;
if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
name = deref_function_name(arg, &tofree, evalarg, verbose);
if (name == NULL)
{
*arg = name + len;
ret = FAIL;
}
else if (*skipwhite(*arg) != NUL)
{
if (verbose)
semsg(_(e_trailing_characters_str), *arg);
ret = FAIL;
}
else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL)
{
name = ref.vval.v_string;
ref.vval.v_string = NULL;
tofree = name;
len = STRLEN(name);
}
else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL)
{
if (ref.vval.v_partial->pt_argc > 0
|| ref.vval.v_partial->pt_dict != NULL)
{
emsg(_(e_cannot_use_partial_here));
ret = FAIL;
}
else
{
name = vim_strsave(partial_name(ref.vval.v_partial));
tofree = name;
if (name == NULL)
{
ret = FAIL;
name = *arg;
}
else
len = STRLEN(name);
}
}
else
{
if (verbose)
semsg(_(e_not_callable_type_str), name);
ret = FAIL;
}
clear_tv(&ref);
len = STRLEN(name);
*paren = '(';
}

View File

@ -580,6 +580,29 @@ def Test_use_import_in_mapping()
nunmap <F3>
enddef
def Test_use_import_in_completion()
var lines =<< trim END
vim9script
export def Complete(..._): list<string>
return ['abcd']
enddef
END
writefile(lines, 'Xscript.vim')
lines =<< trim END
vim9script
import './Xscript.vim'
command -nargs=1 -complete=customlist,Xscript.Complete Cmd echo 'ok'
feedkeys(":Cmd ab\<Tab>\<C-B>#\<CR>", 'xnt')
assert_equal('#Cmd abcd', @:)
END
CheckScriptSuccess(lines)
delcommand Cmd
delete('Xscript.vim')
enddef
def Test_export_fails()
CheckScriptFailure(['export var some = 123'], 'E1042:')
CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')

View File

@ -3119,18 +3119,30 @@ free_all_functions(void)
/*
* Return TRUE if "name" looks like a builtin function name: starts with a
* lower case letter and doesn't contain AUTOLOAD_CHAR or ':'.
* lower case letter, doesn't contain AUTOLOAD_CHAR or ':', no "." after the
* name.
* "len" is the length of "name", or -1 for NUL terminated.
*/
int
builtin_function(char_u *name, int len)
{
char_u *p;
int i;
if (!ASCII_ISLOWER(name[0]) || name[1] == ':')
return FALSE;
p = vim_strchr(name, AUTOLOAD_CHAR);
return p == NULL || (len > 0 && p > name + len);
for (i = 0; name[i] != NUL && (len < 0 || i < len); ++i)
{
if (name[i] == AUTOLOAD_CHAR)
return FALSE;
if (!eval_isnamec(name[i]))
{
// "name.something" is not a builtin function
if (name[i] == '.')
return FALSE;
break;
}
}
return TRUE;
}
int

View File

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