mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 9.0.1338: :defcompile and :disassemble can't find class method
Problem: :defcompile and :disassemble can't find class method. (Ernie Rael) Solution: Make a class name and class.method name work. (closes #11984)
This commit is contained in:
102
src/eval.c
102
src/eval.c
@@ -1529,45 +1529,81 @@ get_lval(
|
|||||||
if (cl != NULL)
|
if (cl != NULL)
|
||||||
{
|
{
|
||||||
lp->ll_valtype = NULL;
|
lp->ll_valtype = NULL;
|
||||||
int count = v_type == VAR_OBJECT ? cl->class_obj_member_count
|
|
||||||
: cl->class_class_member_count;
|
if (flags & GLV_PREFER_FUNC)
|
||||||
ocmember_T *members = v_type == VAR_OBJECT
|
|
||||||
? cl->class_obj_members
|
|
||||||
: cl->class_class_members;
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
{
|
||||||
ocmember_T *om = members + i;
|
// First look for a function with this name.
|
||||||
if (STRNCMP(om->ocm_name, key, p - key) == 0
|
// round 1: class functions (skipped for an object)
|
||||||
&& om->ocm_name[p - key] == NUL)
|
// round 2: object methods
|
||||||
|
for (int round = v_type == VAR_OBJECT ? 2 : 1;
|
||||||
|
round <= 2; ++round)
|
||||||
{
|
{
|
||||||
switch (om->ocm_access)
|
int count = round == 1
|
||||||
|
? cl->class_class_function_count
|
||||||
|
: cl->class_obj_method_count;
|
||||||
|
ufunc_T **funcs = round == 1
|
||||||
|
? cl->class_class_functions
|
||||||
|
: cl->class_obj_methods;
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
case ACCESS_PRIVATE:
|
ufunc_T *fp = funcs[i];
|
||||||
semsg(_(e_cannot_access_private_member_str),
|
char_u *ufname = (char_u *)fp->uf_name;
|
||||||
om->ocm_name);
|
if (STRNCMP(ufname, key, p - key) == 0
|
||||||
return NULL;
|
&& ufname[p - key] == NUL)
|
||||||
case ACCESS_READ:
|
{
|
||||||
if (!(flags & GLV_READ_ONLY))
|
lp->ll_ufunc = fp;
|
||||||
{
|
lp->ll_valtype = fp->uf_func_type;
|
||||||
semsg(_(e_member_is_not_writable_str),
|
round = 3;
|
||||||
om->ocm_name);
|
break;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ACCESS_ALL:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lp->ll_valtype = om->ocm_type;
|
|
||||||
|
|
||||||
if (v_type == VAR_OBJECT)
|
|
||||||
lp->ll_tv = ((typval_T *)(
|
|
||||||
lp->ll_tv->vval.v_object + 1)) + i;
|
|
||||||
else
|
|
||||||
lp->ll_tv = &cl->class_members_tv[i];
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lp->ll_valtype == NULL)
|
||||||
|
{
|
||||||
|
int count = v_type == VAR_OBJECT
|
||||||
|
? cl->class_obj_member_count
|
||||||
|
: cl->class_class_member_count;
|
||||||
|
ocmember_T *members = v_type == VAR_OBJECT
|
||||||
|
? cl->class_obj_members
|
||||||
|
: cl->class_class_members;
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
ocmember_T *om = members + i;
|
||||||
|
if (STRNCMP(om->ocm_name, key, p - key) == 0
|
||||||
|
&& om->ocm_name[p - key] == NUL)
|
||||||
|
{
|
||||||
|
switch (om->ocm_access)
|
||||||
|
{
|
||||||
|
case ACCESS_PRIVATE:
|
||||||
|
semsg(_(e_cannot_access_private_member_str),
|
||||||
|
om->ocm_name);
|
||||||
|
return NULL;
|
||||||
|
case ACCESS_READ:
|
||||||
|
if ((flags & GLV_READ_ONLY) == 0)
|
||||||
|
{
|
||||||
|
semsg(_(e_member_is_not_writable_str),
|
||||||
|
om->ocm_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACCESS_ALL:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lp->ll_valtype = om->ocm_type;
|
||||||
|
|
||||||
|
if (v_type == VAR_OBJECT)
|
||||||
|
lp->ll_tv = ((typval_T *)(
|
||||||
|
lp->ll_tv->vval.v_object + 1)) + i;
|
||||||
|
else
|
||||||
|
lp->ll_tv = &cl->class_members_tv[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lp->ll_valtype == NULL)
|
if (lp->ll_valtype == NULL)
|
||||||
{
|
{
|
||||||
if (v_type == VAR_OBJECT)
|
if (v_type == VAR_OBJECT)
|
||||||
|
@@ -41,7 +41,8 @@ void user_func_error(funcerror_T error, char_u *name, int found_var);
|
|||||||
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
|
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
|
||||||
int call_simple_func(char_u *funcname, int len, typval_T *rettv);
|
int call_simple_func(char_u *funcname, int len, typval_T *rettv);
|
||||||
char_u *printable_func_name(ufunc_T *fp);
|
char_u *printable_func_name(ufunc_T *fp);
|
||||||
char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type);
|
char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags);
|
||||||
|
char_u *trans_function_name_ext(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type, ufunc_T **ufunc);
|
||||||
char_u *get_scriptlocal_funcname(char_u *funcname);
|
char_u *get_scriptlocal_funcname(char_u *funcname);
|
||||||
char_u *alloc_printable_func_name(char_u *fname);
|
char_u *alloc_printable_func_name(char_u *fname);
|
||||||
char_u *save_function_name(char_u **name, int *is_global, int skip, int flags, funcdict_T *fudi);
|
char_u *save_function_name(char_u **name, int *is_global, int skip, int flags, funcdict_T *fudi);
|
||||||
|
@@ -4521,6 +4521,7 @@ typedef struct lval_S
|
|||||||
char_u *ll_newkey; // New key for Dict in alloc. mem or NULL.
|
char_u *ll_newkey; // New key for Dict in alloc. mem or NULL.
|
||||||
type_T *ll_valtype; // type expected for the value or NULL
|
type_T *ll_valtype; // type expected for the value or NULL
|
||||||
blob_T *ll_blob; // The Blob or NULL
|
blob_T *ll_blob; // The Blob or NULL
|
||||||
|
ufunc_T *ll_ufunc; // The function or NULL
|
||||||
} lval_T;
|
} lval_T;
|
||||||
|
|
||||||
// Structure used to save the current state. Used when executing Normal mode
|
// Structure used to save the current state. Used when executing Normal mode
|
||||||
|
@@ -842,6 +842,34 @@ def Test_class_function()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_class_defcompile()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class C
|
||||||
|
def Fo(i: number): string
|
||||||
|
return i
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
defcompile C.Fo
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number')
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class C
|
||||||
|
static def Fc(): number
|
||||||
|
return 'x'
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
defcompile C.Fc
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got string')
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_class_object_to_string()
|
def Test_class_object_to_string()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
|
@@ -1037,8 +1037,7 @@ get_function_body(
|
|||||||
if (*p == '!')
|
if (*p == '!')
|
||||||
p = skipwhite(p + 1);
|
p = skipwhite(p + 1);
|
||||||
p += eval_fname_script(p);
|
p += eval_fname_script(p);
|
||||||
vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL,
|
vim_free(trans_function_name(&p, NULL, TRUE, 0));
|
||||||
NULL, NULL));
|
|
||||||
if (*skipwhite(p) == '(')
|
if (*skipwhite(p) == '(')
|
||||||
{
|
{
|
||||||
if (nesting == MAX_FUNC_NESTING - 1)
|
if (nesting == MAX_FUNC_NESTING - 1)
|
||||||
@@ -4038,13 +4037,29 @@ list_func_head(ufunc_T *fp, int indent)
|
|||||||
*/
|
*/
|
||||||
char_u *
|
char_u *
|
||||||
trans_function_name(
|
trans_function_name(
|
||||||
|
char_u **pp,
|
||||||
|
int *is_global,
|
||||||
|
int skip, // only find the end, don't evaluate
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
return trans_function_name_ext(pp, is_global, skip, flags,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* trans_function_name() with extra arguments.
|
||||||
|
* "fdp", "partial", "type" and "ufunc" can be NULL.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
trans_function_name_ext(
|
||||||
char_u **pp,
|
char_u **pp,
|
||||||
int *is_global,
|
int *is_global,
|
||||||
int skip, // only find the end, don't evaluate
|
int skip, // only find the end, don't evaluate
|
||||||
int flags,
|
int flags,
|
||||||
funcdict_T *fdp, // return: info about dictionary used
|
funcdict_T *fdp, // return: info about dictionary used
|
||||||
partial_T **partial, // return: partial of a FuncRef
|
partial_T **partial, // return: partial of a FuncRef
|
||||||
type_T **type) // return: type of funcref if not NULL
|
type_T **type, // return: type of funcref
|
||||||
|
ufunc_T **ufunc) // return: function
|
||||||
{
|
{
|
||||||
char_u *name = NULL;
|
char_u *name = NULL;
|
||||||
char_u *start;
|
char_u *start;
|
||||||
@@ -4079,7 +4094,8 @@ trans_function_name(
|
|||||||
start += lead;
|
start += lead;
|
||||||
|
|
||||||
// Note that TFN_ flags use the same values as GLV_ flags.
|
// Note that TFN_ flags use the same values as GLV_ flags.
|
||||||
end = get_lval(start, NULL, &lv, FALSE, skip, flags | GLV_READ_ONLY,
|
end = get_lval(start, NULL, &lv, FALSE, skip,
|
||||||
|
flags | GLV_READ_ONLY | GLV_PREFER_FUNC,
|
||||||
lead > 2 ? 0 : FNE_CHECK_START);
|
lead > 2 ? 0 : FNE_CHECK_START);
|
||||||
if (end == start || (vim9script && end != NULL
|
if (end == start || (vim9script && end != NULL
|
||||||
&& end[-1] == AUTOLOAD_CHAR && *end == '('))
|
&& end[-1] == AUTOLOAD_CHAR && *end == '('))
|
||||||
@@ -4105,6 +4121,13 @@ trans_function_name(
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lv.ll_ufunc != NULL)
|
||||||
|
{
|
||||||
|
*ufunc = lv.ll_ufunc;
|
||||||
|
name = vim_strsave(lv.ll_ufunc->uf_name);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
|
||||||
if (lv.ll_tv != NULL)
|
if (lv.ll_tv != NULL)
|
||||||
{
|
{
|
||||||
if (fdp != NULL)
|
if (fdp != NULL)
|
||||||
@@ -4455,8 +4478,8 @@ save_function_name(
|
|||||||
CLEAR_POINTER(fudi);
|
CLEAR_POINTER(fudi);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
saved = trans_function_name(&p, is_global, skip,
|
saved = trans_function_name_ext(&p, is_global, skip,
|
||||||
flags, fudi, NULL, NULL);
|
flags, fudi, NULL, NULL, NULL);
|
||||||
*name = p;
|
*name = p;
|
||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
@@ -5330,15 +5353,20 @@ find_func_by_name(char_u *name, compiletype_T *compile_type)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// First try finding a method in a class, find_func_by_name() will give
|
// First try finding a method in a class, trans_function_name() will
|
||||||
// an error if the function is not found.
|
// give an error if the function is not found.
|
||||||
ufunc = find_class_func(&arg);
|
ufunc = find_class_func(&arg);
|
||||||
if (ufunc != NULL)
|
if (ufunc != NULL)
|
||||||
return ufunc;
|
return ufunc;
|
||||||
|
|
||||||
fname = trans_function_name(&arg, &is_global, FALSE,
|
fname = trans_function_name_ext(&arg, &is_global, FALSE,
|
||||||
TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DECL,
|
TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DECL,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL, &ufunc);
|
||||||
|
if (ufunc != NULL)
|
||||||
|
{
|
||||||
|
vim_free(fname);
|
||||||
|
return ufunc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (fname == NULL)
|
if (fname == NULL)
|
||||||
{
|
{
|
||||||
@@ -5375,13 +5403,10 @@ find_func_by_name(char_u *name, compiletype_T *compile_type)
|
|||||||
void
|
void
|
||||||
ex_defcompile(exarg_T *eap)
|
ex_defcompile(exarg_T *eap)
|
||||||
{
|
{
|
||||||
ufunc_T *ufunc;
|
|
||||||
|
|
||||||
if (*eap->arg != NUL)
|
if (*eap->arg != NUL)
|
||||||
{
|
{
|
||||||
compiletype_T compile_type = CT_NONE;
|
compiletype_T compile_type = CT_NONE;
|
||||||
|
ufunc_T *ufunc = find_func_by_name(eap->arg, &compile_type);
|
||||||
ufunc = find_func_by_name(eap->arg, &compile_type);
|
|
||||||
if (ufunc != NULL)
|
if (ufunc != NULL)
|
||||||
{
|
{
|
||||||
if (func_needs_compiling(ufunc, compile_type))
|
if (func_needs_compiling(ufunc, compile_type))
|
||||||
@@ -5401,7 +5426,7 @@ ex_defcompile(exarg_T *eap)
|
|||||||
if (!HASHITEM_EMPTY(hi))
|
if (!HASHITEM_EMPTY(hi))
|
||||||
{
|
{
|
||||||
--todo;
|
--todo;
|
||||||
ufunc = HI2UF(hi);
|
ufunc_T *ufunc = HI2UF(hi);
|
||||||
if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
|
if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
|
||||||
&& ufunc->uf_def_status == UF_TO_BE_COMPILED
|
&& ufunc->uf_def_status == UF_TO_BE_COMPILED
|
||||||
&& (ufunc->uf_flags & FC_DEAD) == 0)
|
&& (ufunc->uf_flags & FC_DEAD) == 0)
|
||||||
@@ -5475,7 +5500,7 @@ function_exists(char_u *name, int no_deref)
|
|||||||
flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
|
flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
|
||||||
if (no_deref)
|
if (no_deref)
|
||||||
flag |= TFN_NO_DEREF;
|
flag |= TFN_NO_DEREF;
|
||||||
p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL, NULL);
|
p = trans_function_name(&nm, &is_global, FALSE, flag);
|
||||||
nm = skipwhite(nm);
|
nm = skipwhite(nm);
|
||||||
|
|
||||||
// Only accept "funcname", "funcname ", "funcname (..." and
|
// Only accept "funcname", "funcname ", "funcname (..." and
|
||||||
@@ -5494,8 +5519,7 @@ get_expanded_name(char_u *name, int check)
|
|||||||
char_u *p;
|
char_u *p;
|
||||||
int is_global = FALSE;
|
int is_global = FALSE;
|
||||||
|
|
||||||
p = trans_function_name(&nm, &is_global, FALSE,
|
p = trans_function_name(&nm, &is_global, FALSE, TFN_INT|TFN_QUIET);
|
||||||
TFN_INT|TFN_QUIET, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (p != NULL && *nm == NUL
|
if (p != NULL && *nm == NUL
|
||||||
&& (!check || translated_function_exists(p, is_global)))
|
&& (!check || translated_function_exists(p, is_global)))
|
||||||
@@ -5631,8 +5655,8 @@ ex_delfunction(exarg_T *eap)
|
|||||||
int is_global = FALSE;
|
int is_global = FALSE;
|
||||||
|
|
||||||
p = eap->arg;
|
p = eap->arg;
|
||||||
name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi,
|
name = trans_function_name_ext(&p, &is_global, eap->skip, 0, &fudi,
|
||||||
NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
vim_free(fudi.fd_newkey);
|
vim_free(fudi.fd_newkey);
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
{
|
{
|
||||||
@@ -6166,8 +6190,8 @@ ex_call(exarg_T *eap)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tofree = trans_function_name(&arg, NULL, eap->skip, TFN_INT,
|
tofree = trans_function_name_ext(&arg, NULL, eap->skip, TFN_INT,
|
||||||
&fudi, &partial, vim9script ? &type : NULL);
|
&fudi, &partial, vim9script ? &type : NULL, NULL);
|
||||||
if (fudi.fd_newkey != NULL)
|
if (fudi.fd_newkey != NULL)
|
||||||
{
|
{
|
||||||
// Still need to give an error message for missing key.
|
// Still need to give an error message for missing key.
|
||||||
|
@@ -695,6 +695,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1338,
|
||||||
/**/
|
/**/
|
||||||
1337,
|
1337,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2722,6 +2722,7 @@ typedef char *(*opt_did_set_cb_T)(optset_T *args);
|
|||||||
#define GLV_NO_DECL TFN_NO_DECL // assignment without :var or :let
|
#define GLV_NO_DECL TFN_NO_DECL // assignment without :var or :let
|
||||||
#define GLV_COMPILING TFN_COMPILING // variable may be defined later
|
#define GLV_COMPILING TFN_COMPILING // variable may be defined later
|
||||||
#define GLV_ASSIGN_WITH_OP TFN_ASSIGN_WITH_OP // assignment with operator
|
#define GLV_ASSIGN_WITH_OP TFN_ASSIGN_WITH_OP // assignment with operator
|
||||||
|
#define GLV_PREFER_FUNC 0x10000 // prefer function above variable
|
||||||
|
|
||||||
#define DO_NOT_FREE_CNT 99999 // refcount for dict or list that should not
|
#define DO_NOT_FREE_CNT 99999 // refcount for dict or list that should not
|
||||||
// be freed.
|
// be freed.
|
||||||
|
Reference in New Issue
Block a user