0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -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 enddef
endclass endclass
def F1(i: I1): list<number>
return [ i.svar1, i.svar2 ]
enddef
def F2(i: I1): list<number> def F2(i: I1): list<number>
return [ i.mvar1, i.mvar2 ] return [ i.mvar1, i.mvar2 ]
enddef enddef
@@ -1967,10 +1963,6 @@ def Test_class_implements_interface()
var ob = B.new() var ob = B.new()
var oc = C.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([111, 112], F2(oa))
assert_equal([121, 122], F2(ob)) assert_equal([121, 122], F2(ob))
assert_equal([131, 132], F2(oc)) assert_equal([131, 132], F2(oc))
@@ -2041,39 +2033,21 @@ def Test_class_implements_interface()
enddef enddef
endclass endclass
def F1(i: I1): list<number>
return [ i.svar1, i.svar2 ]
enddef
def F2(i: I1): list<number> def F2(i: I1): list<number>
return [ i.mvar1, i.mvar2 ] return [ i.mvar1, i.mvar2 ]
enddef enddef
def F3(i: I2): list<number>
return [ i.svar3, i.svar4 ]
enddef
def F4(i: I2): list<number> def F4(i: I2): list<number>
return [ i.mvar3, i.mvar4 ] return [ i.mvar3, i.mvar4 ]
enddef enddef
def F5(o: C): number
return o.svar5
enddef
var oa = A.new() var oa = A.new()
var ob = B.new() var ob = B.new()
var oc = C.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([[111, 112]], [F2(oa)])
assert_equal([[121, 122], [123, 124]], [F2(ob), F4(ob)]) assert_equal([[121, 122], [123, 124]], [F2(ob), F4(ob)])
assert_equal([[131, 132], [133, 134]], [F2(oc), F4(oc)]) assert_equal([[131, 132], [133, 134]], [F2(oc), F4(oc)])
assert_equal(1001, F5(oc))
END END
v9.CheckScriptSuccess(lines) v9.CheckScriptSuccess(lines)
enddef enddef
@@ -4182,25 +4156,7 @@ def Test_static_member_access_outside_class()
return 11 return 11
enddef 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()) assert_equal(11, F1())
var c = C.new()
assert_equal(22, F2(c))
assert_equal(33, F3(c))
END END
v9.CheckScriptSuccess(lines) v9.CheckScriptSuccess(lines)
enddef enddef
@@ -4250,7 +4206,7 @@ def Test_private_member_access_outside_class()
enddef enddef
T() T()
END 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 # private static member variable
lines =<< trim END lines =<< trim END
@@ -4362,7 +4318,7 @@ def Test_modify_class_member_from_def_function()
enddef enddef
" Test for accessing a class member variable using an object " 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 var lines =<< trim END
vim9script vim9script
class A class A
@@ -4374,26 +4330,74 @@ def Test_class_member_access_using_object()
A.svar2->add(4) A.svar2->add(4)
assert_equal([1, 3], A.svar1) assert_equal([1, 3], A.svar1)
assert_equal([2, 4], A.svar2) 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() def Foo()
A.svar1->add(7) A.svar1->add(7)
A.svar2->add(8) A.svar2->add(8)
assert_equal([1, 3, 5, 7], A.svar1) assert_equal([1, 3, 7], A.svar1)
assert_equal([2, 4, 6, 8], A.svar2) assert_equal([2, 4, 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)
enddef enddef
Foo() Foo()
END END
v9.CheckScriptSuccess(lines) 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 enddef
" Test for using a interface method using a child object " Test for using a interface method using a child object

View File

@@ -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 */
/**/
1887,
/**/ /**/
1886, 1886,
/**/ /**/

View File

@@ -1966,8 +1966,7 @@ class_object_index(
{ {
// Search in the object member variable table and the class member // Search in the object member variable table and the class member
// variable table. // variable table.
if (get_member_tv(cl, TRUE, name, len, rettv) == OK if (get_member_tv(cl, TRUE, name, len, rettv) == OK)
|| get_member_tv(cl, FALSE, name, len, rettv) == OK)
{ {
*arg = name_end; *arg = name_end;
return OK; 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". // Could be a function reference: "obj.Func".
for (int i = 0; i < cl->class_obj_method_count; ++i) for (int i = 0; i < cl->class_obj_method_count; ++i)
{ {