0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 9.0.1887: Vim9: class members are accessible via object

Problem:  Vim9: class members are accessible via object
Solution: Disable class member variable access using an object

Class methods can be accessed only using the class name and cannot be
accessed using an object. To be consistent with this, do the same for
class member variables also. They can be accessed only using the class
name and not using an object.

closes: #13057

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
Yegappan Lakshmanan
2023-09-09 11:33:29 +02:00
committed by Christian Brabandt
parent ee17b6f70d
commit 23c92d93c1
4 changed files with 65 additions and 78 deletions

View File

@@ -1955,10 +1955,6 @@ def Test_class_implements_interface()
enddef
endclass
def F1(i: I1): list<number>
return [ i.svar1, i.svar2 ]
enddef
def F2(i: I1): list<number>
return [ i.mvar1, i.mvar2 ]
enddef
@@ -1967,10 +1963,6 @@ def Test_class_implements_interface()
var ob = B.new()
var oc = C.new()
assert_equal([11, 12], F1(oa))
assert_equal([21, 22], F1(ob))
assert_equal([31, 32], F1(oc))
assert_equal([111, 112], F2(oa))
assert_equal([121, 122], F2(ob))
assert_equal([131, 132], F2(oc))
@@ -2041,39 +2033,21 @@ def Test_class_implements_interface()
enddef
endclass
def F1(i: I1): list<number>
return [ i.svar1, i.svar2 ]
enddef
def F2(i: I1): list<number>
return [ i.mvar1, i.mvar2 ]
enddef
def F3(i: I2): list<number>
return [ i.svar3, i.svar4 ]
enddef
def F4(i: I2): list<number>
return [ i.mvar3, i.mvar4 ]
enddef
def F5(o: C): number
return o.svar5
enddef
var oa = A.new()
var ob = B.new()
var oc = C.new()
assert_equal([[11, 12]], [F1(oa)])
assert_equal([[21, 22], [23, 24]], [F1(ob), F3(ob)])
assert_equal([[31, 32], [33, 34]], [F1(oc), F3(oc)])
assert_equal([[111, 112]], [F2(oa)])
assert_equal([[121, 122], [123, 124]], [F2(ob), F4(ob)])
assert_equal([[131, 132], [133, 134]], [F2(oc), F4(oc)])
assert_equal(1001, F5(oc))
END
v9.CheckScriptSuccess(lines)
enddef
@@ -4182,25 +4156,7 @@ def Test_static_member_access_outside_class()
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
@@ -4250,7 +4206,7 @@ def Test_private_member_access_outside_class()
enddef
T()
END
v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val')
v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": _val')
# private static member variable
lines =<< trim END
@@ -4362,7 +4318,7 @@ def Test_modify_class_member_from_def_function()
enddef
" Test for accessing a class member variable using an object
def Test_class_member_access_using_object()
def Test_class_variable_access_using_object()
var lines =<< trim END
vim9script
class A
@@ -4374,26 +4330,74 @@ def Test_class_member_access_using_object()
A.svar2->add(4)
assert_equal([1, 3], A.svar1)
assert_equal([2, 4], A.svar2)
var a1 = A.new()
a1.svar1->add(5)
a1.svar2->add(6)
assert_equal([1, 3, 5], a1.svar1)
assert_equal([2, 4, 6], a1.svar2)
def Foo()
A.svar1->add(7)
A.svar2->add(8)
assert_equal([1, 3, 5, 7], A.svar1)
assert_equal([2, 4, 6, 8], A.svar2)
var a2 = A.new()
a2.svar1->add(9)
a2.svar2->add(10)
assert_equal([1, 3, 5, 7, 9], a2.svar1)
assert_equal([2, 4, 6, 8, 10], a2.svar2)
assert_equal([1, 3, 7], A.svar1)
assert_equal([2, 4, 8], A.svar2)
enddef
Foo()
END
v9.CheckScriptSuccess(lines)
# Cannot read from a class variable using an object in script context
lines =<< trim END
vim9script
class A
public this.var1: number
public static svar2: list<number> = [1]
endclass
var a = A.new()
echo a.svar2
END
v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": svar2')
# Cannot write to a class variable using an object in script context
lines =<< trim END
vim9script
class A
public this.var1: number
public static svar2: list<number> = [1]
endclass
var a = A.new()
a.svar2 = [2]
END
v9.CheckScriptFailure(lines, 'E1334: Object member not found: svar2 = [2]')
# Cannot read from a class variable using an object in def method context
lines =<< trim END
vim9script
class A
public this.var1: number
public static svar2: list<number> = [1]
endclass
def T()
var a = A.new()
echo a.svar2
enddef
T()
END
v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": svar2')
# Cannot write to a class variable using an object in def method context
lines =<< trim END
vim9script
class A
public this.var1: number
public static svar2: list<number> = [1]
endclass
def T()
var a = A.new()
a.svar2 = [2]
enddef
T()
END
v9.CheckScriptFailure(lines, 'E1089: Unknown variable: svar2 = [2]')
enddef
" Test for using a interface method using a child object

View File

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

View File

@@ -1966,8 +1966,7 @@ class_object_index(
{
// Search in the object member variable table and the class member
// variable table.
if (get_member_tv(cl, TRUE, name, len, rettv) == OK
|| get_member_tv(cl, FALSE, name, len, rettv) == OK)
if (get_member_tv(cl, TRUE, name, len, rettv) == OK)
{
*arg = name_end;
return OK;

View File

@@ -413,24 +413,6 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
}
}
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);
}
}
// Could be a function reference: "obj.Func".
for (int i = 0; i < cl->class_obj_method_count; ++i)
{