patch 9.0.1867: Vim9: access to interface statics possible
Problem: Vim9: access to interface statics possible Solution: Prevent direct access to interface statics closes: #13007 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Ernie Rael <errael@raelity.com>
This commit is contained in:
committed by
Christian Brabandt
parent
dccc29c228
commit
18143d3111
@ -3513,5 +3513,6 @@ EXTERN char e_method_str_type_mismatch_expected_str_but_got_str[]
|
|||||||
INIT(= N_("E1407: Member \"%s\": type mismatch, expected %s but got %s"));
|
INIT(= N_("E1407: Member \"%s\": type mismatch, expected %s but got %s"));
|
||||||
EXTERN char e_aptypes_is_null_str_nr[]
|
EXTERN char e_aptypes_is_null_str_nr[]
|
||||||
INIT(= "E1408: Internal error: ap_types or ap_types[idx] is NULL: %s: %d");
|
INIT(= "E1408: Internal error: ap_types or ap_types[idx] is NULL: %s: %d");
|
||||||
|
EXTERN char e_interface_static_direct_access_str[]
|
||||||
|
INIT(= N_("E1409: Cannot directly access interface \"%s\" static member \"%s\""));
|
||||||
// E1371 - E1399 unused
|
// E1371 - E1399 unused
|
||||||
|
|||||||
@ -1180,6 +1180,14 @@ get_lval(
|
|||||||
return NULL;
|
return NULL;
|
||||||
lp->ll_tv = &v->di_tv;
|
lp->ll_tv = &v->di_tv;
|
||||||
}
|
}
|
||||||
|
if (vim9script && writing && lp->ll_tv->v_type == VAR_CLASS
|
||||||
|
&& (lp->ll_tv->vval.v_class->class_flags & CLASS_INTERFACE) != 0)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
semsg(_(e_interface_static_direct_access_str),
|
||||||
|
lp->ll_tv->vval.v_class->class_name, lp->ll_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (vim9script && (flags & GLV_NO_DECL) == 0)
|
if (vim9script && (flags & GLV_NO_DECL) == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/* vim9class.c */
|
/* vim9class.c */
|
||||||
int object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl);
|
int object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl, int is_static);
|
||||||
void ex_class(exarg_T *eap);
|
void ex_class(exarg_T *eap);
|
||||||
type_T *class_member_type(class_T *cl, int is_object, char_u *name, char_u *name_end, int *member_idx, ocmember_T **m);
|
type_T *class_member_type(class_T *cl, int is_object, char_u *name, char_u *name_end, int *member_idx, ocmember_T **m);
|
||||||
void ex_enum(exarg_T *eap);
|
void ex_enum(exarg_T *eap);
|
||||||
|
|||||||
@ -4,8 +4,8 @@ isn_T *generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop);
|
|||||||
isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type);
|
isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type);
|
||||||
isn_T *generate_instr_debug(cctx_T *cctx);
|
isn_T *generate_instr_debug(cctx_T *cctx);
|
||||||
int generate_CONSTRUCT(cctx_T *cctx, class_T *cl);
|
int generate_CONSTRUCT(cctx_T *cctx, class_T *cl);
|
||||||
int generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type);
|
int generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type, int is_static);
|
||||||
int generate_GET_ITF_MEMBER(cctx_T *cctx, class_T *itf, int idx, type_T *type);
|
int generate_GET_ITF_MEMBER(cctx_T *cctx, class_T *itf, int idx, type_T *type, int is_static);
|
||||||
int generate_STORE_THIS(cctx_T *cctx, int idx);
|
int generate_STORE_THIS(cctx_T *cctx, int idx);
|
||||||
int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
|
int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
|
||||||
int generate_add_instr(cctx_T *cctx, vartype_T vartype, type_T *type1, type_T *type2, exprtype_T expr_type);
|
int generate_add_instr(cctx_T *cctx, vartype_T vartype, type_T *type1, type_T *type2, exprtype_T expr_type);
|
||||||
|
|||||||
@ -509,6 +509,36 @@ def Test_assignment_with_operator()
|
|||||||
assert_equal(23, f.x)
|
assert_equal(23, f.x)
|
||||||
END
|
END
|
||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
|
|
||||||
|
# do the same thing, but through an interface
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
interface I
|
||||||
|
public this.x: number
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
class Foo implements I
|
||||||
|
public this.x: number
|
||||||
|
|
||||||
|
def Add(n: number)
|
||||||
|
var i: I = this
|
||||||
|
i.x += n
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var f = Foo.new(3)
|
||||||
|
f.Add(17)
|
||||||
|
assert_equal(20, f.x)
|
||||||
|
|
||||||
|
def AddToFoo(i: I)
|
||||||
|
i.x += 3
|
||||||
|
enddef
|
||||||
|
|
||||||
|
AddToFoo(f)
|
||||||
|
assert_equal(23, f.x)
|
||||||
|
END
|
||||||
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_list_of_objects()
|
def Test_list_of_objects()
|
||||||
@ -3762,6 +3792,142 @@ def Test_dup_member_variable()
|
|||||||
v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val')
|
v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_interface_static_member_access()
|
||||||
|
# In a class cannot read from interface static
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
interface I
|
||||||
|
public static num: number
|
||||||
|
endinterface
|
||||||
|
class C implements I
|
||||||
|
public static num = 3
|
||||||
|
def F()
|
||||||
|
var x = I.num
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
C.new().F()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"')
|
||||||
|
|
||||||
|
# In a class cannot write to interface static
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
interface I
|
||||||
|
public static num: number
|
||||||
|
endinterface
|
||||||
|
class C implements I
|
||||||
|
public static num = 3
|
||||||
|
def F()
|
||||||
|
I.num = 7
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
C.new().F()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"')
|
||||||
|
|
||||||
|
# In a def cannot read from interface static
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
interface I
|
||||||
|
public static num: number
|
||||||
|
endinterface
|
||||||
|
def F()
|
||||||
|
var x = I.num
|
||||||
|
enddef
|
||||||
|
F()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"')
|
||||||
|
|
||||||
|
# In a def cannot write to interface static
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
interface I
|
||||||
|
public static num: number
|
||||||
|
endinterface
|
||||||
|
def F()
|
||||||
|
I.num = 7
|
||||||
|
enddef
|
||||||
|
F()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"')
|
||||||
|
|
||||||
|
# script level cannot read interface static
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
interface I
|
||||||
|
public static s_var1: number
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
var x = I.s_var1
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "s_var1"')
|
||||||
|
|
||||||
|
# script level cannot write interface static
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
interface I
|
||||||
|
public static s_var1: number
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
I.s_var1 = 3
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "I.s_var1 = 3"')
|
||||||
|
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_static_member_access_outside_class()
|
||||||
|
# Verify access of statics implemented from interface
|
||||||
|
# in a :def (outside of a class)
|
||||||
|
# Note the order of the static is different
|
||||||
|
# between the interface and the class,
|
||||||
|
# since they are allocated in order in each interface/class;
|
||||||
|
# so the static index is mapped from interfaced to class as needed.
|
||||||
|
|
||||||
|
# Check reading statics
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
interface I
|
||||||
|
public static s_var1: number
|
||||||
|
public static s_var2: number
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
class C implements I
|
||||||
|
public static s_var2 = 2
|
||||||
|
public static x_static = 7
|
||||||
|
public static s_var1 = 1
|
||||||
|
endclass
|
||||||
|
|
||||||
|
def F1(): number
|
||||||
|
assert_equal(1, C.s_var1)
|
||||||
|
assert_equal(2, C.s_var2)
|
||||||
|
assert_equal(7, C.x_static)
|
||||||
|
return 11
|
||||||
|
enddef
|
||||||
|
|
||||||
|
# access the class static through an interface argument
|
||||||
|
def F2(i: I): number
|
||||||
|
assert_equal(1, i.s_var1)
|
||||||
|
assert_equal(2, i.s_var2)
|
||||||
|
return 22
|
||||||
|
enddef
|
||||||
|
|
||||||
|
# access the class static through an object interface
|
||||||
|
def F3(o: C): number
|
||||||
|
assert_equal(1, o.s_var1)
|
||||||
|
assert_equal(2, o.s_var2)
|
||||||
|
assert_equal(7, o.x_static)
|
||||||
|
return 33
|
||||||
|
enddef
|
||||||
|
|
||||||
|
assert_equal(11, F1())
|
||||||
|
var c = C.new()
|
||||||
|
assert_equal(22, F2(c))
|
||||||
|
assert_equal(33, F3(c))
|
||||||
|
END
|
||||||
|
v9.CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
" Test for accessing a private member outside a class in a def function
|
" Test for accessing a private member outside a class in a def function
|
||||||
def Test_private_member_access_outside_class()
|
def Test_private_member_access_outside_class()
|
||||||
# private object member variable
|
# private object member variable
|
||||||
@ -3794,6 +3960,63 @@ def Test_private_member_access_outside_class()
|
|||||||
T()
|
T()
|
||||||
END
|
END
|
||||||
v9.CheckScriptFailure(lines, 'E1089: Unknown variable: _a = 1')
|
v9.CheckScriptFailure(lines, 'E1089: Unknown variable: _a = 1')
|
||||||
|
|
||||||
|
# private static member variable
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class A
|
||||||
|
static _val = 10
|
||||||
|
endclass
|
||||||
|
def T()
|
||||||
|
var a = A.new()
|
||||||
|
var x = a._val
|
||||||
|
enddef
|
||||||
|
T()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val')
|
||||||
|
|
||||||
|
# private static member variable
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class A
|
||||||
|
static _val = 10
|
||||||
|
endclass
|
||||||
|
def T()
|
||||||
|
var a = A.new()
|
||||||
|
a._val = 3
|
||||||
|
enddef
|
||||||
|
T()
|
||||||
|
END
|
||||||
|
# TODO: wrong error, should be about private member
|
||||||
|
v9.CheckScriptFailure(lines, 'E1089: Unknown variable')
|
||||||
|
|
||||||
|
# private static class variable
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class A
|
||||||
|
static _val = 10
|
||||||
|
endclass
|
||||||
|
def T()
|
||||||
|
var x = A._val
|
||||||
|
enddef
|
||||||
|
T()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val')
|
||||||
|
|
||||||
|
# private static class variable
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class A
|
||||||
|
static _val = 10
|
||||||
|
endclass
|
||||||
|
def T()
|
||||||
|
A._val = 3
|
||||||
|
enddef
|
||||||
|
T()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val')
|
||||||
|
|
||||||
|
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
" Test for changing the member access of an interface in a implementation class
|
" Test for changing the member access of an interface in a implementation class
|
||||||
|
|||||||
@ -699,6 +699,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 */
|
||||||
|
/**/
|
||||||
|
1867,
|
||||||
/**/
|
/**/
|
||||||
1866,
|
1866,
|
||||||
/**/
|
/**/
|
||||||
|
|||||||
@ -498,6 +498,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
class_T *cm_class;
|
class_T *cm_class;
|
||||||
int cm_idx;
|
int cm_idx;
|
||||||
|
int cm_static;
|
||||||
} classmember_T;
|
} classmember_T;
|
||||||
// arguments to ISN_STOREINDEX
|
// arguments to ISN_STOREINDEX
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@ -220,9 +220,11 @@ add_members_to_class(
|
|||||||
* "cl" implementing that interface.
|
* "cl" implementing that interface.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl)
|
object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl,
|
||||||
|
int is_static)
|
||||||
{
|
{
|
||||||
if (idx > (is_method ? itf->class_obj_method_count
|
if (idx >= (is_method ? itf->class_obj_method_count
|
||||||
|
: is_static ? itf->class_class_member_count
|
||||||
: itf->class_obj_member_count))
|
: itf->class_obj_member_count))
|
||||||
{
|
{
|
||||||
siemsg("index %d out of range for interface %s", idx, itf->class_name);
|
siemsg("index %d out of range for interface %s", idx, itf->class_name);
|
||||||
@ -245,8 +247,28 @@ object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl)
|
|||||||
cl->class_name, itf->class_name);
|
cl->class_name, itf->class_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int *table = (int *)(i2c + 1);
|
if (is_static)
|
||||||
return table[idx];
|
{
|
||||||
|
// TODO: Need a table for fast lookup?
|
||||||
|
char_u *name = itf->class_class_members[idx].ocm_name;
|
||||||
|
for (int i = 0; i < i2c->i2c_class->class_class_member_count; ++i)
|
||||||
|
{
|
||||||
|
ocmember_T *m = &i2c->i2c_class->class_class_members[i];
|
||||||
|
if (STRCMP(name, m->ocm_name) == 0)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
siemsg("class %s, interface %s, static %s not found",
|
||||||
|
cl->class_name, itf->class_name, name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// A table follows the i2c for the class
|
||||||
|
int *table = (int *)(i2c + 1);
|
||||||
|
return table[idx];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1808,6 +1830,12 @@ class_object_index(
|
|||||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
if ((cl->class_flags & CLASS_INTERFACE) != 0)
|
||||||
|
{
|
||||||
|
semsg(_(e_interface_static_direct_access_str),
|
||||||
|
cl->class_name, m->ocm_name);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
typval_T *tv = &cl->class_members_tv[i];
|
typval_T *tv = &cl->class_members_tv[i];
|
||||||
copy_tv(tv, rettv);
|
copy_tv(tv, rettv);
|
||||||
|
|||||||
@ -1874,7 +1874,13 @@ compile_lhs(
|
|||||||
&lhs->lhs_member_idx, &m);
|
&lhs->lhs_member_idx, &m);
|
||||||
if (lhs->lhs_member_idx < 0)
|
if (lhs->lhs_member_idx < 0)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
if ((cl->class_flags & CLASS_INTERFACE) != 0
|
||||||
|
&& lhs->lhs_type->tt_type == VAR_CLASS)
|
||||||
|
{
|
||||||
|
semsg(_(e_interface_static_direct_access_str),
|
||||||
|
cl->class_name, m->ocm_name);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
// If it is private member variable, then accessing it outside the
|
// If it is private member variable, then accessing it outside the
|
||||||
// class is not allowed.
|
// class is not allowed.
|
||||||
if ((m->ocm_access != VIM_ACCESS_ALL) && !inside_class(cctx, cl))
|
if ((m->ocm_access != VIM_ACCESS_ALL) && !inside_class(cctx, cl))
|
||||||
@ -2112,8 +2118,9 @@ compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (cl->class_flags & CLASS_INTERFACE)
|
if (cl->class_flags & CLASS_INTERFACE)
|
||||||
return generate_GET_ITF_MEMBER(cctx, cl, lhs->lhs_member_idx, type);
|
return generate_GET_ITF_MEMBER(cctx, cl, lhs->lhs_member_idx, type,
|
||||||
return generate_GET_OBJ_MEMBER(cctx, lhs->lhs_member_idx, type);
|
FALSE);
|
||||||
|
return generate_GET_OBJ_MEMBER(cctx, lhs->lhs_member_idx, type, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
compile_load_lhs(lhs, var_start, NULL, cctx);
|
compile_load_lhs(lhs, var_start, NULL, cctx);
|
||||||
|
|||||||
@ -2316,8 +2316,8 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
|
|||||||
class_T *itf = iptr->isn_arg.storeindex.si_class;
|
class_T *itf = iptr->isn_arg.storeindex.si_class;
|
||||||
if (itf != NULL)
|
if (itf != NULL)
|
||||||
// convert interface member index to class member index
|
// convert interface member index to class member index
|
||||||
lidx = object_index_from_itf_index(itf, FALSE,
|
lidx = object_index_from_itf_index(itf, FALSE, lidx,
|
||||||
lidx, obj->obj_class);
|
obj->obj_class, FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -4261,7 +4261,8 @@ exec_instructions(ectx_T *ectx)
|
|||||||
|
|
||||||
// convert the interface index to the object index
|
// convert the interface index to the object index
|
||||||
int idx = object_index_from_itf_index(mfunc->cmf_itf,
|
int idx = object_index_from_itf_index(mfunc->cmf_itf,
|
||||||
TRUE, mfunc->cmf_idx, cl);
|
TRUE, mfunc->cmf_idx, cl,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
if (call_ufunc(cl->class_obj_methods[idx], NULL,
|
if (call_ufunc(cl->class_obj_methods[idx], NULL,
|
||||||
mfunc->cmf_argcount, ectx, NULL, NULL) == FAIL)
|
mfunc->cmf_argcount, ectx, NULL, NULL) == FAIL)
|
||||||
@ -4410,7 +4411,8 @@ exec_instructions(ectx_T *ectx)
|
|||||||
|
|
||||||
// convert the interface index to the object index
|
// convert the interface index to the object index
|
||||||
int idx = object_index_from_itf_index(extra->fre_class,
|
int idx = object_index_from_itf_index(extra->fre_class,
|
||||||
TRUE, extra->fre_method_idx, cl);
|
TRUE, extra->fre_method_idx, cl,
|
||||||
|
FALSE);
|
||||||
ufunc = cl->class_obj_methods[idx];
|
ufunc = cl->class_obj_methods[idx];
|
||||||
}
|
}
|
||||||
else if (extra == NULL || extra->fre_func_name == NULL)
|
else if (extra == NULL || extra->fre_func_name == NULL)
|
||||||
@ -5389,20 +5391,25 @@ exec_instructions(ectx_T *ectx)
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_static = iptr->isn_arg.classmember.cm_static;
|
||||||
int idx;
|
int idx;
|
||||||
if (iptr->isn_type == ISN_GET_OBJ_MEMBER)
|
if (iptr->isn_type == ISN_GET_OBJ_MEMBER)
|
||||||
idx = iptr->isn_arg.number;
|
idx = iptr->isn_arg.classmember.cm_idx;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
idx = iptr->isn_arg.classmember.cm_idx;
|
idx = iptr->isn_arg.classmember.cm_idx;
|
||||||
// convert the interface index to the object index
|
// convert the interface index to the object index
|
||||||
idx = object_index_from_itf_index(
|
idx = object_index_from_itf_index(
|
||||||
iptr->isn_arg.classmember.cm_class,
|
iptr->isn_arg.classmember.cm_class,
|
||||||
FALSE, idx, obj->obj_class);
|
FALSE, idx, obj->obj_class, is_static);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the members are located right after the object struct
|
// The members are located right after the object struct.
|
||||||
typval_T *mtv = ((typval_T *)(obj + 1)) + idx;
|
typval_T *mtv;
|
||||||
|
if (is_static)
|
||||||
|
mtv = &obj->obj_class->class_members_tv[idx];
|
||||||
|
else
|
||||||
|
mtv = ((typval_T *)(obj + 1)) + idx;
|
||||||
copy_tv(mtv, tv);
|
copy_tv(mtv, tv);
|
||||||
|
|
||||||
// Unreference the object after getting the member, it may
|
// Unreference the object after getting the member, it may
|
||||||
|
|||||||
@ -407,8 +407,27 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
|||||||
|
|
||||||
*arg = name_end;
|
*arg = name_end;
|
||||||
if (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))
|
if (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))
|
||||||
return generate_GET_ITF_MEMBER(cctx, cl, i, m->ocm_type);
|
return generate_GET_ITF_MEMBER(cctx, cl, i, m->ocm_type,
|
||||||
return generate_GET_OBJ_MEMBER(cctx, i, m->ocm_type);
|
FALSE);
|
||||||
|
return generate_GET_OBJ_MEMBER(cctx, i, m->ocm_type, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < cl->class_class_member_count; ++i)
|
||||||
|
{
|
||||||
|
ocmember_T *m = &cl->class_class_members[i];
|
||||||
|
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
||||||
|
{
|
||||||
|
if (*name == '_' && !inside_class(cctx, cl))
|
||||||
|
{
|
||||||
|
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
*arg = name_end;
|
||||||
|
if (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))
|
||||||
|
return generate_GET_ITF_MEMBER(cctx, cl, i, m->ocm_type,
|
||||||
|
TRUE);
|
||||||
|
return generate_GET_OBJ_MEMBER(cctx, i, m->ocm_type, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,6 +458,13 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
|||||||
ocmember_T *m = &cl->class_class_members[idx];
|
ocmember_T *m = &cl->class_class_members[idx];
|
||||||
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
||||||
{
|
{
|
||||||
|
// Note: type->tt_type = VAR_CLASS
|
||||||
|
if ((cl->class_flags & CLASS_INTERFACE) != 0)
|
||||||
|
{
|
||||||
|
semsg(_(e_interface_static_direct_access_str),
|
||||||
|
cl->class_name, m->ocm_name);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
if (*name == '_' && !inside_class(cctx, cl))
|
if (*name == '_' && !inside_class(cctx, cl))
|
||||||
{
|
{
|
||||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||||
|
|||||||
@ -136,7 +136,7 @@ generate_CONSTRUCT(cctx_T *cctx, class_T *cl)
|
|||||||
* index.
|
* index.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type)
|
generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type, int is_static)
|
||||||
{
|
{
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
|
|
||||||
@ -145,7 +145,9 @@ generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type)
|
|||||||
if (isn == NULL)
|
if (isn == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
isn->isn_arg.number = idx;
|
isn->isn_arg.classmember.cm_class = NULL;
|
||||||
|
isn->isn_arg.classmember.cm_idx = idx;
|
||||||
|
isn->isn_arg.classmember.cm_static = is_static;
|
||||||
return push_type_stack2(cctx, type, &t_any);
|
return push_type_stack2(cctx, type, &t_any);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +156,8 @@ generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type)
|
|||||||
* by index.
|
* by index.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
generate_GET_ITF_MEMBER(cctx_T *cctx, class_T *itf, int idx, type_T *type)
|
generate_GET_ITF_MEMBER(cctx_T *cctx, class_T *itf, int idx, type_T *type,
|
||||||
|
int is_static)
|
||||||
{
|
{
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
|
|
||||||
@ -166,6 +169,7 @@ generate_GET_ITF_MEMBER(cctx_T *cctx, class_T *itf, int idx, type_T *type)
|
|||||||
isn->isn_arg.classmember.cm_class = itf;
|
isn->isn_arg.classmember.cm_class = itf;
|
||||||
++itf->class_refcount;
|
++itf->class_refcount;
|
||||||
isn->isn_arg.classmember.cm_idx = idx;
|
isn->isn_arg.classmember.cm_idx = idx;
|
||||||
|
isn->isn_arg.classmember.cm_static = is_static;
|
||||||
return push_type_stack2(cctx, type, &t_any);
|
return push_type_stack2(cctx, type, &t_any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user