]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1887: Vim9: class members are accessible via object v9.0.1887
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sat, 9 Sep 2023 09:33:29 +0000 (11:33 +0200)
committerChristian Brabandt <cb@256bit.org>
Sat, 9 Sep 2023 09:33:29 +0000 (11:33 +0200)
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>
src/testdir/test_vim9_class.vim
src/version.c
src/vim9class.c
src/vim9expr.c

index 2549f32d6e860ddbf9e74515358f63e638a78a37..cf6122d8583b9e241a727e43e71b35244a78c79d 100644 (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
index 70dd46fe12fb12bce722ca772bf0fc305f4c04d8..b8e7879c6ee0ea6423da613f985a9bd4b0b07844 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1887,
 /**/
     1886,
 /**/
index 8e2c88b14df699e93107761cf14c60610b009609..14d29c7dac505e0d6d1cb03f86138482fe1ace64 100644 (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;
index f9756c0bba13960ab9e03186686ea4feebe55fd9..3817e38c569959167655640d2e8d8f1caa311bcd 100644 (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)
        {