]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.2002: Vim9: need cleanup of class related interface code v9.0.2002
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sun, 8 Oct 2023 17:07:39 +0000 (19:07 +0200)
committerChristian Brabandt <cb@256bit.org>
Sun, 8 Oct 2023 17:07:39 +0000 (19:07 +0200)
Problem:  Vim9: need cleanup of class related interface code
Solution: Remove the unused class variable and class method related code
          for interfaces.

Remove unused class variable and class method related code for
interfaces.

Refactor the code.

Optimize the object/class member double lookup in compile_lhs().

Change unused global functions to static functions.

closes: #13302

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
src/proto/vim9class.pro
src/testdir/test_vim9_class.vim
src/version.c
src/vim9class.c
src/vim9cmds.c
src/vim9compile.c

index e36c7e288ec1f46f61e40ba479d8235ed98c8a67..c9e19d0067bbadaf56ca2864c78ee89e64cbc29d 100644 (file)
@@ -10,11 +10,8 @@ ufunc_T *find_class_func(char_u **arg);
 int class_member_idx(class_T *cl, char_u *name, size_t namelen);
 ocmember_T *class_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
 int class_method_idx(class_T *cl, char_u *name, size_t namelen);
-ufunc_T *class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
-int object_member_idx(class_T *cl, char_u *name, size_t namelen);
 ocmember_T *object_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
 int object_method_idx(class_T *cl, char_u *name, size_t namelen);
-ufunc_T *object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
 ocmember_T *member_lookup(class_T *cl, vartype_T v_type, char_u *name, size_t namelen, int *idx);
 void emsg_var_cl_define(char *msg, char_u *name, size_t len, class_T *cl);
 ufunc_T *method_lookup(class_T *cl, vartype_T v_type, char_u *name, size_t namelen, int *idx);
@@ -26,7 +23,6 @@ void class_unref(class_T *cl);
 int class_free_nonref(int copyID);
 int set_ref_in_classes(int copyID);
 void object_created(object_T *obj);
-void object_cleared(object_T *obj);
 int object_free_nonref(int copyID);
 void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
 void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
index 555c46cc8e867f0d7a16a442a1ae2543714b971f..c911206c9f20a2fcdc4b2c01e8d93286cf7c5ad9 100644 (file)
@@ -975,6 +975,28 @@ def Test_class_new_with_object_member()
     Check()
   END
   v9.CheckSourceSuccess(lines)
+
+  # Try using "this." argument in a class method
+  lines =<< trim END
+    vim9script
+    class A
+      this.val = 10
+      static def Foo(this.val: number)
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1390: Cannot use an object variable "this.val" except with the "new" method', 4)
+
+  # Try using "this." argument in an object method
+  lines =<< trim END
+    vim9script
+    class A
+      this.val = 10
+      def Foo(this.val: number)
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1390: Cannot use an object variable "this.val" except with the "new" method', 4)
 enddef
 
 def Test_class_object_member_inits()
@@ -1722,7 +1744,7 @@ def Test_class_member()
     var a = A.new()
     var v = a.bar
   END
-  v9.CheckSourceFailure(lines, 'E1326: Variable not found on object "A": bar', 5)
+  v9.CheckSourceFailure(lines, 'E1337: Class variable "bar" not found in class "A"', 5)
 enddef
 
 " These messages should show the defining class of the variable (base class),
@@ -4255,7 +4277,7 @@ def Test_private_object_method()
     var a = A.new()
     a._Foo()
   END
-  v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 9)
+  v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 9)
 
   # Try calling a private method using an object (from a def function)
   lines =<< trim END
@@ -4468,7 +4490,7 @@ def Test_private_object_method()
     var c = C.new()
     assert_equal(1234, c._Foo())
   END
-  v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 16)
+  v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 16)
 
   # Using "_" prefix in a method name should fail outside of a class
   lines =<< trim END
@@ -4494,7 +4516,7 @@ def Test_private_class_method()
     endclass
     A._Foo()
   END
-  v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 8)
+  v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 8)
 
   # Try calling a class private method (from a def function)
   lines =<< trim END
@@ -5122,7 +5144,7 @@ def Test_class_variable_access_using_object()
     var a = A.new()
     echo a.svar2
   END
-  v9.CheckSourceFailure(lines, 'E1375: Class variable "svar2" accessible only using class "A"', 8)
+  v9.CheckSourceFailure(lines, 'E1337: Class variable "svar2" not found in class "A"', 8)
 
   # Cannot write to a class variable using an object in script context
   lines =<< trim END
@@ -5597,7 +5619,7 @@ def Test_class_variable()
     var a = A.new()
     var i = a.val
   END
-  v9.CheckSourceFailure(lines, 'E1375: Class variable "val" accessible only using class "A"', 7)
+  v9.CheckSourceFailure(lines, 'E1337: Class variable "val" not found in class "A"', 7)
 
   # Modifying a class variable using an object at function level
   lines =<< trim END
@@ -5969,6 +5991,18 @@ def Test_extend_interface()
   END
   v9.CheckSourceSuccess(lines)
 
+  # extending empty interface
+  lines =<< trim END
+    vim9script
+    interface A
+    endinterface
+    interface B extends A
+    endinterface
+    class C implements B
+    endclass
+  END
+  v9.CheckSourceSuccess(lines)
+
   lines =<< trim END
     vim9script
     interface A
@@ -6567,6 +6601,17 @@ def Test_reserved_varname()
       o.F()
     END
     v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3)
+
+    # class variable name
+    if kword != 'this'
+      lines =<< trim eval END
+        vim9script
+        class C
+          public static {kword}: list<number> = [1, 2, 3]
+        endclass
+      END
+      v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3)
+    endif
   endfor
 enddef
 
index e408dc1f71db2a43b6853c5cf2b7e1745b45b90a..6a92ab75c72177af316f5d0c5f9f64d27a0dbab0 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2002,
 /**/
     2001,
 /**/
index 7d1a7fdcaadddb119efdb61700aaefe9787dace1..0cb353bb57f08dd7f4ac2b95ccae28dd824a8f92 100644 (file)
@@ -555,7 +555,6 @@ validate_abstract_class_methods(
 intf_variable_present(
     char_u     *intf_class_name,
     ocmember_T *if_var,
-    int                is_class_var,
     ocmember_T *cl_mt,
     int                cl_member_count,
     class_T    *extends_cl)
@@ -600,15 +599,10 @@ intf_variable_present(
 
     if (!variable_present && extends_cl != NULL)
     {
-       int ext_cl_count = is_class_var
-                               ? extends_cl->class_class_member_count
-                               : extends_cl->class_obj_member_count;
-       ocmember_T *ext_cl_mt = is_class_var
-                               ? extends_cl->class_class_members
-                               : extends_cl->class_obj_members;
+       int ext_cl_count = extends_cl->class_obj_member_count;
+       ocmember_T *ext_cl_mt = extends_cl->class_obj_members;
        return intf_variable_present(intf_class_name, if_var,
-                                       is_class_var, ext_cl_mt,
-                                       ext_cl_count,
+                                       ext_cl_mt, ext_cl_count,
                                        extends_cl->class_extends);
     }
 
@@ -616,43 +610,32 @@ intf_variable_present(
 }
 
 /*
- * Check the variables of the interface class "ifcl" match the class variables
- * ("classmembers_gap") and object variables ("objmembers_gap") of a class.
- * Returns TRUE if the class and object variables names are valid.
+ * Check the variables of the interface class "ifcl" match object variables
+ * ("objmembers_gap") of a class.
+ * Returns TRUE if the object variables names are valid.
  */
     static int
 validate_interface_variables(
     char_u     *intf_class_name,
     class_T    *ifcl,
-    garray_T   *classmembers_gap,
     garray_T   *objmembers_gap,
     class_T    *extends_cl)
 {
-    for (int loop = 1; loop <= 2; ++loop)
+    int if_count = ifcl->class_obj_member_count;
+    if (if_count == 0)
+       return TRUE;
+
+    ocmember_T *if_ms = ifcl->class_obj_members;
+    ocmember_T *cl_ms = (ocmember_T *)(objmembers_gap->ga_data);
+    int cl_count = objmembers_gap->ga_len;
+    for (int if_i = 0; if_i < if_count; ++if_i)
     {
-       // loop == 1: check class variables
-       // loop == 2: check object variables
-       int is_class_var = (loop == 1);
-       int if_count = is_class_var ? ifcl->class_class_member_count
-                                               : ifcl->class_obj_member_count;
-       if (if_count == 0)
-           continue;
-       ocmember_T *if_ms = is_class_var ? ifcl->class_class_members
-                                               : ifcl->class_obj_members;
-       ocmember_T *cl_ms = (ocmember_T *)(is_class_var
-                                               ? classmembers_gap->ga_data
-                                               : objmembers_gap->ga_data);
-       int cl_count = is_class_var ? classmembers_gap->ga_len
-                                               : objmembers_gap->ga_len;
-       for (int if_i = 0; if_i < if_count; ++if_i)
-       {
-           if (!intf_variable_present(intf_class_name, &if_ms[if_i],
-                               is_class_var, cl_ms, cl_count, extends_cl))
-           {
-               semsg(_(e_variable_str_of_interface_str_not_implemented),
-                       if_ms[if_i].ocm_name, intf_class_name);
-               return FALSE;
-           }
+       if (!intf_variable_present(intf_class_name, &if_ms[if_i], cl_ms,
+                                                       cl_count, extends_cl))
+       {
+           semsg(_(e_variable_str_of_interface_str_not_implemented),
+                   if_ms[if_i].ocm_name, intf_class_name);
+           return FALSE;
        }
     }
 
@@ -685,7 +668,6 @@ intf_method_type_matches(ufunc_T *if_method, ufunc_T *cl_method)
     static int
 intf_method_present(
     ufunc_T *if_ufunc,
-    int            is_class_method,
     ufunc_T **cl_fp,
     int            cl_count,
     class_T *extends_cl)
@@ -707,15 +689,10 @@ intf_method_present(
 
     if (!method_present && extends_cl != NULL)
     {
-       ufunc_T **ext_cl_fp = (ufunc_T **)(is_class_method
-                                       ? extends_cl->class_class_functions
-                                       : extends_cl->class_obj_methods);
-       int     ext_cl_count = is_class_method
-                               ? extends_cl->class_class_function_count
-                               : extends_cl->class_obj_method_count;
-       return intf_method_present(if_ufunc, is_class_method, ext_cl_fp,
-                                       ext_cl_count,
-                                       extends_cl->class_extends);
+       ufunc_T **ext_cl_fp = (ufunc_T **)(extends_cl->class_obj_methods);
+       int     ext_cl_count = extends_cl->class_obj_method_count;
+       return intf_method_present(if_ufunc, ext_cl_fp, ext_cl_count,
+                                               extends_cl->class_extends);
     }
 
     return method_present;
@@ -733,37 +710,25 @@ intf_method_present(
 validate_interface_methods(
     char_u     *intf_class_name,
     class_T    *ifcl,
-    garray_T   *classfunctions_gap,
     garray_T   *objmethods_gap,
     class_T    *extends_cl)
 {
-    for (int loop = 1; loop <= 2; ++loop)
+    int if_count = ifcl->class_obj_method_count;
+    if (if_count == 0)
+       return TRUE;
+
+    ufunc_T **if_fp = ifcl->class_obj_methods;
+    ufunc_T **cl_fp = (ufunc_T **)(objmethods_gap->ga_data);
+    int cl_count = objmethods_gap->ga_len;
+    for (int if_i = 0; if_i < if_count; ++if_i)
     {
-       // loop == 1: check class methods
-       // loop == 2: check object methods
-       int is_class_method = (loop == 1);
-       int if_count = is_class_method ? ifcl->class_class_function_count
-                                       : ifcl->class_obj_method_count;
-       if (if_count == 0)
-           continue;
-       ufunc_T **if_fp = is_class_method ? ifcl->class_class_functions
-                                               : ifcl->class_obj_methods;
-       ufunc_T **cl_fp = (ufunc_T **)(is_class_method
-                                               ? classfunctions_gap->ga_data
-                                               : objmethods_gap->ga_data);
-       int cl_count = is_class_method ? classfunctions_gap->ga_len
-                                               : objmethods_gap->ga_len;
-       for (int if_i = 0; if_i < if_count; ++if_i)
-       {
-           char_u      *if_name = if_fp[if_i]->uf_name;
+       char_u  *if_name = if_fp[if_i]->uf_name;
 
-           if (!intf_method_present(if_fp[if_i], is_class_method, cl_fp,
-                                                       cl_count, extends_cl))
-           {
-               semsg(_(e_method_str_of_interface_str_not_implemented),
-                       if_name, intf_class_name);
-               return FALSE;
-           }
+       if (!intf_method_present(if_fp[if_i], cl_fp, cl_count, extends_cl))
+       {
+           semsg(_(e_method_str_of_interface_str_not_implemented),
+                   if_name, intf_class_name);
+           return FALSE;
        }
     }
 
@@ -781,8 +746,6 @@ validate_interface_methods(
 validate_implements_classes(
     garray_T   *impl_gap,
     class_T    **intf_classes,
-    garray_T   *classfunctions_gap,
-    garray_T   *classmembers_gap,
     garray_T   *objmethods_gap,
     garray_T   *objmembers_gap,
     class_T    *extends_cl)
@@ -816,15 +779,14 @@ validate_implements_classes(
        ++ifcl->class_refcount;
 
        // check the variables of the interface match the members of the class
-       success = validate_interface_variables(impl, ifcl, classmembers_gap,
-                                               objmembers_gap, extends_cl);
+       success = validate_interface_variables(impl, ifcl, objmembers_gap,
+                                                               extends_cl);
 
        // check the functions/methods of the interface match the
        // functions/methods of the class
        if (success)
-           success = validate_interface_methods(impl, ifcl,
-                                       classfunctions_gap, objmethods_gap,
-                                       extends_cl);
+           success = validate_interface_methods(impl, ifcl, objmethods_gap,
+                                                               extends_cl);
        clear_tv(&tv);
     }
 
@@ -1873,9 +1835,7 @@ early_ret:
        intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len);
 
        success = validate_implements_classes(&ga_impl, intf_classes,
-                                       &classfunctions, &classmembers,
-                                       &objmethods, &objmembers,
-                                       extends_cl);
+                                       &objmethods, &objmembers, extends_cl);
     }
 
     // Check no function argument name is used as a class member.
@@ -2172,18 +2132,90 @@ get_member_tv(
        return FAIL;
     }
 
-    // The object only contains a pointer to the class, the member
-    // values array follows right after that.
-    object_T *obj = rettv->vval.v_object;
     if (is_object)
     {
+       // The object only contains a pointer to the class, the member values
+       // array follows right after that.
+       object_T *obj = rettv->vval.v_object;
        typval_T *tv = (typval_T *)(obj + 1) + m_idx;
        copy_tv(tv, rettv);
+       object_unref(obj);
     }
     else
+    {
        copy_tv(&cl->class_members_tv[m_idx], rettv);
+       class_unref(cl);
+    }
+
+    return OK;
+}
 
-    object_unref(obj);
+/*
+ * Call an object or class method "name" in class "cl".  The method return
+ * value is returned in "rettv".
+ */
+    static int
+call_oc_method(
+    class_T    *cl,
+    char_u     *name,
+    size_t     len,
+    char_u     *name_end,
+    evalarg_T  *evalarg,
+    char_u     **arg,
+    typval_T   *rettv)
+{
+    ufunc_T    *fp;
+    typval_T   argvars[MAX_FUNC_ARGS + 1];
+    int                argcount = 0;
+
+    fp = method_lookup(cl, rettv->v_type, name, len, NULL);
+    if (fp == NULL)
+    {
+       method_not_found_msg(cl, rettv->v_type, name, len);
+       return FAIL;
+    }
+
+    if (*fp->uf_name == '_')
+    {
+       // Cannot access a private method outside of a class
+       semsg(_(e_cannot_access_private_method_str), fp->uf_name);
+       return FAIL;
+    }
+
+    char_u *argp = name_end;
+    int ret = get_func_arguments(&argp, evalarg, 0, argvars, &argcount);
+    if (ret == FAIL)
+       return FAIL;
+
+    funcexe_T funcexe;
+    CLEAR_FIELD(funcexe);
+    funcexe.fe_evaluate = TRUE;
+    if (rettv->v_type == VAR_OBJECT)
+    {
+       funcexe.fe_object = rettv->vval.v_object;
+       ++funcexe.fe_object->obj_refcount;
+    }
+
+    // Clear the class or object after calling the function, in
+    // case the refcount is one.
+    typval_T tv_tofree = *rettv;
+    rettv->v_type = VAR_UNKNOWN;
+
+    // Call the user function.  Result goes into rettv;
+    int error = call_user_func_check(fp, argcount, argvars, rettv, &funcexe,
+                                                               NULL);
+
+    // Clear the previous rettv and the arguments.
+    clear_tv(&tv_tofree);
+    for (int idx = 0; idx < argcount; ++idx)
+       clear_tv(&argvars[idx]);
+
+    if (error != FCERR_NONE)
+    {
+       user_func_error(error, printable_func_name(fp), funcexe.fe_found_var);
+       return FAIL;
+    }
+    *arg = argp;
 
     return OK;
 }
@@ -2242,104 +2274,22 @@ class_object_index(
     }
 
     if (*name_end == '(')
-    {
-       ufunc_T *fp;
-
-       fp = method_lookup(cl, rettv->v_type, name, len, NULL);
-       if (fp == NULL)
-       {
-           method_not_found_msg(cl, rettv->v_type, name, len);
-           return FAIL;
-       }
-
-       typval_T        argvars[MAX_FUNC_ARGS + 1];
-       int             argcount = 0;
-
-       if (*fp->uf_name == '_')
-       {
-           // Cannot access a private method outside of a class
-           semsg(_(e_cannot_access_private_method_str), name);
-           return FAIL;
-       }
-
-       char_u *argp = name_end;
-       int ret = get_func_arguments(&argp, evalarg, 0,
-               argvars, &argcount);
-       if (ret == FAIL)
-           return FAIL;
-
-       funcexe_T funcexe;
-       CLEAR_FIELD(funcexe);
-       funcexe.fe_evaluate = TRUE;
-       if (rettv->v_type == VAR_OBJECT)
-       {
-           funcexe.fe_object = rettv->vval.v_object;
-           ++funcexe.fe_object->obj_refcount;
-       }
-
-       // Clear the class or object after calling the function, in
-       // case the refcount is one.
-       typval_T tv_tofree = *rettv;
-       rettv->v_type = VAR_UNKNOWN;
-
-       // Call the user function.  Result goes into rettv;
-       int error = call_user_func_check(fp, argcount, argvars,
-               rettv, &funcexe, NULL);
-
-       // Clear the previous rettv and the arguments.
-       clear_tv(&tv_tofree);
-       for (int idx = 0; idx < argcount; ++idx)
-           clear_tv(&argvars[idx]);
-
-       if (error != FCERR_NONE)
-       {
-           user_func_error(error, printable_func_name(fp),
-                   funcexe.fe_found_var);
-           return FAIL;
-       }
-       *arg = argp;
-       return OK;
-    }
+       // Invoke the class or object method
+       return call_oc_method(cl, name, len, name_end, evalarg, arg, rettv);
 
-    else if (rettv->v_type == VAR_OBJECT)
+    else if (rettv->v_type == VAR_OBJECT || rettv->v_type == VAR_CLASS)
     {
        // Search in the object member variable table and the class member
        // variable table.
-       if (get_member_tv(cl, TRUE, name, len, rettv) == OK)
+       int is_object = rettv->v_type == VAR_OBJECT;
+       if (get_member_tv(cl, is_object, name, len, rettv) == OK)
        {
            *arg = name_end;
            return OK;
        }
 
        if (did_emsg == did_emsg_save)
-           member_not_found_msg(cl, VAR_OBJECT, name, len);
-    }
-
-    else if (rettv->v_type == VAR_CLASS)
-    {
-       int         m_idx;
-
-       // class member
-       ocmember_T *m = class_member_lookup(cl, name, len, &m_idx);
-       if (m == NULL)
-       {
-           member_not_found_msg(cl, VAR_CLASS, name, len);
-           return FAIL;
-       }
-
-       if (*name == '_')
-       {
-           emsg_var_cl_define(e_cannot_access_private_variable_str,
-                                                       m->ocm_name, 0, cl);
-           return FAIL;
-       }
-
-       typval_T *tv = &cl->class_members_tv[m_idx];
-       copy_tv(tv, rettv);
-       class_unref(cl);
-
-       *arg = name_end;
-       return OK;
+           member_not_found_msg(cl, is_object, name, len);
     }
 
     return FAIL;
@@ -2432,24 +2382,12 @@ class_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
     return ret_m;
 }
 
-/*
- * Returns the index of class method "name" in the class "cl".
- * Returns -1, if the method is not found.
- */
-    int
-class_method_idx(class_T *cl, char_u *name, size_t namelen)
-{
-    int idx;
-    class_method_lookup(cl, name, namelen, &idx);
-    return idx;
-}
-
 /*
  * Returns a pointer to the class method "name" in class "cl".
  * Returns NULL if the method is not found.
  * The method index is set in "idx".
  */
-    ufunc_T *
+    static ufunc_T *
 class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
 {
     ufunc_T    *ret_fp = NULL;
@@ -2470,12 +2408,24 @@ class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
     return ret_fp;
 }
 
+/*
+ * Returns the index of class method "name" in the class "cl".
+ * Returns -1, if the method is not found.
+ */
+    int
+class_method_idx(class_T *cl, char_u *name, size_t namelen)
+{
+    int idx;
+    class_method_lookup(cl, name, namelen, &idx);
+    return idx;
+}
+
 /*
  * Returns the index of object member variable "name" in the class "cl".
  * Returns -1, if the variable is not found.
  * If "namelen" is zero, then it is assumed that "name" is NUL terminated.
  */
-    int
+    static int
 object_member_idx(class_T *cl, char_u *name, size_t namelen)
 {
     int idx;
@@ -2518,24 +2468,12 @@ object_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
     return ret_m;
 }
 
-/*
- * Returns the index of object method "name" in the class "cl".
- * Returns -1, if the method is not found.
- */
-    int
-object_method_idx(class_T *cl, char_u *name, size_t namelen)
-{
-    int idx;
-    object_method_lookup(cl, name, namelen, &idx);
-    return idx;
-}
-
 /*
  * Returns a pointer to the object method "name" in class "cl".
  * Returns NULL if the method is not found.
  * The object method index is set in "idx".
  */
-    ufunc_T *
+    static ufunc_T *
 object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
 {
     ufunc_T    *ret_fp = NULL;
@@ -2558,6 +2496,18 @@ object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
     return ret_fp;
 }
 
+/*
+ * Returns the index of object method "name" in the class "cl".
+ * Returns -1, if the method is not found.
+ */
+    int
+object_method_idx(class_T *cl, char_u *name, size_t namelen)
+{
+    int idx;
+    object_method_lookup(cl, name, namelen, &idx);
+    return idx;
+}
+
 /*
  * Lookup a class or object member variable by name.  If v_type is VAR_CLASS,
  * then lookup a class member variable and if it is VAR_OBJECT, then lookup a
@@ -2681,42 +2631,6 @@ copy_object(typval_T *from, typval_T *to)
     }
 }
 
-/*
- * Free an object.
- */
-    static void
-object_clear(object_T *obj)
-{
-    // Avoid a recursive call, it can happen if "obj" has a circular reference.
-    obj->obj_refcount = INT_MAX;
-
-    class_T *cl = obj->obj_class;
-
-    if (!cl)
-       return;
-
-    // the member values are just after the object structure
-    typval_T *tv = (typval_T *)(obj + 1);
-    for (int i = 0; i < cl->class_obj_member_count; ++i)
-       clear_tv(tv + i);
-
-    // Remove from the list headed by "first_object".
-    object_cleared(obj);
-
-    vim_free(obj);
-    class_unref(cl);
-}
-
-/*
- * Unreference an object.
- */
-    void
-object_unref(object_T *obj)
-{
-    if (obj != NULL && --obj->obj_refcount <= 0)
-       object_clear(obj);
-}
-
 /*
  * Make a copy of a class.
  */
@@ -2866,7 +2780,7 @@ static object_T   *next_nonref_obj = NULL;
  * Call this function when an object has been cleared and is about to be freed.
  * It is removed from the list headed by "first_object".
  */
-    void
+    static void
 object_cleared(object_T *obj)
 {
     if (obj->obj_next_used != NULL)
@@ -2881,6 +2795,42 @@ object_cleared(object_T *obj)
        next_nonref_obj = obj->obj_next_used;
 }
 
+/*
+ * Free an object.
+ */
+    static void
+object_clear(object_T *obj)
+{
+    // Avoid a recursive call, it can happen if "obj" has a circular reference.
+    obj->obj_refcount = INT_MAX;
+
+    class_T *cl = obj->obj_class;
+
+    if (!cl)
+       return;
+
+    // the member values are just after the object structure
+    typval_T *tv = (typval_T *)(obj + 1);
+    for (int i = 0; i < cl->class_obj_member_count; ++i)
+       clear_tv(tv + i);
+
+    // Remove from the list headed by "first_object".
+    object_cleared(obj);
+
+    vim_free(obj);
+    class_unref(cl);
+}
+
+/*
+ * Unreference an object.
+ */
+    void
+object_unref(object_T *obj)
+{
+    if (obj != NULL && --obj->obj_refcount <= 0)
+       object_clear(obj);
+}
+
 /*
  * Go through the list of all objects and free items without "copyID".
  */
index 0be207795fce6e84c1bca069d7ad5e6d8b456eb5..8b5b569808cb696b47e0bfde2bbb7aa13dcdc819 100644 (file)
@@ -254,7 +254,7 @@ compile_lock_unlock(
                {
                    // Push the class of the bare class variable name
                    name = cl->class_name;
-                   len = STRLEN(name);
+                   len = (int)STRLEN(name);
 #ifdef LOG_LOCKVAR
                    ch_log(NULL, "LKVAR:    ... cctx_class_member: name %s",
                           name);
index 828fe02e81247339bd9b3ae384cf7a44ec4d88d8..7e1914b69478b8e705c90f0154f2fe14aece325e 100644 (file)
@@ -2011,16 +2011,33 @@ compile_lhs(
            // for an object or class member get the type of the member
            class_T     *cl = lhs->lhs_type->tt_class;
            int         is_object = lhs->lhs_type->tt_type == VAR_OBJECT;
+           char_u      *name = var_start + lhs->lhs_varlen + 1;
+           size_t      namelen = lhs->lhs_end - var_start - lhs->lhs_varlen - 1;
 
-           if (!lhs_class_member_modifiable(lhs, var_start, cctx))
+           ocmember_T  *m = member_lookup(cl, lhs->lhs_type->tt_type,
+                                       name, namelen, &lhs->lhs_member_idx);
+           if (m == NULL)
+           {
+               member_not_found_msg(cl, lhs->lhs_type->tt_type, name, namelen);
                return FAIL;
+           }
 
-           lhs->lhs_member_type = class_member_type(cl,
-                                       is_object,
-                                       after + 1, lhs->lhs_end,
-                                       &lhs->lhs_member_idx);
-           if (lhs->lhs_member_idx < 0)
+           // If it is private member variable, then accessing it outside the
+           // class is not allowed.
+           // If it is a read only class variable, then it can be modified
+           // only inside the class where it is defined.
+           if ((m->ocm_access != VIM_ACCESS_ALL) &&
+                   ((is_object && !inside_class(cctx, cl))
+                    || (!is_object && cctx->ctx_ufunc->uf_class != cl)))
+           {
+               char *msg = (m->ocm_access == VIM_ACCESS_PRIVATE)
+                                       ? e_cannot_access_private_variable_str
+                                       : e_variable_is_not_writable_str;
+               emsg_var_cl_define(msg, m->ocm_name, 0, cl);
                return FAIL;
+           }
+
+           lhs->lhs_member_type = m->ocm_type;
        }
        else
        {