patch 9.0.1814: Vim9 no error on duplicate object member var

Commit: 
https://github.com/vim/vim/commit/2ba9d2e14e3633c92a32abba2a12533f93fefbf5
Author: Yegappan Lakshmanan <[email protected]>
Date:   Mon Aug 28 21:26:23 2023 +0200

    patch 9.0.1814: Vim9 no error on duplicate object member var
    
    Problem:  Vim9 no error on duplicate object member var
    Solution: detect duplicate members and error out
    
    closes: #12938
    
    Signed-off-by: Christian Brabandt <[email protected]>
    Co-authored-by: Yegappan Lakshmanan <[email protected]>

diff --git a/src/errors.h b/src/errors.h
index cc0af8ad1..bf994333e 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3489,6 +3489,10 @@ EXTERN char e_cannot_access_private_method_str[]
 
 EXTERN char e_interface_str_and_class_str_function_access_not_same[]
        INIT(= N_("E1367: Access type of class method %s differs from interface 
method %s"));
+EXTERN char e_static_cannot_be_followed_by_this[]
+       INIT(= N_("E1368: Static cannot be followed by \"this\" in a member 
name"));
+EXTERN char e_duplicate_member_str[]
+       INIT(= N_("E1369: Duplicate member: %s"));
 EXTERN char e_cannot_mix_positional_and_non_positional_str[]
        INIT(= N_("E1400: Cannot mix positional and non-positional arguments: 
%s"));
 EXTERN char e_fmt_arg_nr_unused_str[]
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index f7d6b73f4..319eb0546 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -894,6 +894,15 @@ def Test_class_object_member_access()
     endclass
   END
   v9.CheckScriptFailure(lines, 'E1065:')
+
+  # Test for "static" cannot be followed by "this".
+  lines =<< trim END
+    vim9script
+    class Something
+      static this.val = 1
+    endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1368: Static cannot be followed by "this" in 
a member name')
 enddef
 
 def Test_class_object_compare()
@@ -3438,4 +3447,92 @@ def Test_objmethod_funcarg()
   v9.CheckScriptSuccess(lines)
 enddef
 
+" Test for declaring duplicate object and class members
+def Test_dup_member_variable()
+  # Duplicate member variable
+  var lines =<< trim END
+    vim9script
+    class C
+      this.val = 10
+      this.val = 20
+    endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val')
+
+  # Duplicate private member variable
+  lines =<< trim END
+    vim9script
+    class C
+      this._val = 10
+      this._val = 20
+    endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _val')
+
+  # Duplicate public member variable
+  lines =<< trim END
+    vim9script
+    class C
+      public this.val = 10
+      public this.val = 20
+    endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val')
+
+  # Duplicate private member variable
+  lines =<< trim END
+    vim9script
+    class C
+      this.val = 10
+      this._val = 20
+    endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _val')
+
+  # Duplicate public and private member variable
+  lines =<< trim END
+    vim9script
+    class C
+      this._val = 20
+      public this.val = 10
+    endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val')
+
+  # Duplicate class member variable
+  lines =<< trim END
+    vim9script
+    class C
+      static s: string = "abc"
+      static _s: string = "def"
+    endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _s')
+
+  # Duplicate public and private class member variable
+  lines =<< trim END
+    vim9script
+    class C
+      public static s: string = "abc"
+      static _s: string = "def"
+    endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _s')
+
+  # Duplicate class and object member variable
+  lines =<< trim END
+    vim9script
+    class C
+      static val = 10
+      this.val = 20
+      def new()
+      enddef
+    endclass
+    var c = C.new()
+    assert_equal(10, C.val)
+    assert_equal(20, c.val)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/version.c b/src/version.c
index 7b8683e7c..ce2869486 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1814,
 /**/
     1813,
 /**/
diff --git a/src/vim9class.c b/src/vim9class.c
index 36a5d0a35..955bd0cbc 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -24,7 +24,7 @@
 /*
  * Parse a member declaration, both object and class member.
  * Returns OK or FAIL.  When OK then "varname_end" is set to just after the
- * variable name and "type_ret" is set to the decleared or detected type.
+ * variable name and "type_ret" is set to the declared or detected type.
  * "init_expr" is set to the initialisation expression (allocated), if there is
  * one.  For an interface "init_expr" is NULL.
  */
@@ -489,6 +489,52 @@ check_func_arg_names(
     return success;
 }
 
+/*
+ * Returns TRUE if the member "varname" is already defined.
+ */
+    static int
+is_duplicate_member(garray_T *mgap, char_u *varname, char_u *varname_end)
+{
+    char_u *pstr = (*varname == '_') ? varname + 1 : varname;
+
+    for (int i = 0; i < mgap->ga_len; ++i)
+    {
+       ocmember_T *m = ((ocmember_T *)mgap->ga_data) + i;
+       char_u *qstr = *m->ocm_name == '_' ? m->ocm_name + 1 : m->ocm_name;
+       if (STRNCMP(pstr, qstr, varname_end - pstr) == 0)
+       {
+           char_u *name = vim_strnsave(varname, varname_end - varname);
+           semsg(_(e_duplicate_member_str), name);
+           vim_free(name);
+           return TRUE;
+       }
+    }
+
+    return FALSE;
+}
+
+/*
+ * Returns TRUE if the method "name" is already defined.
+ */
+    static int
+is_duplicate_method(garray_T *fgap, char_u *name)
+{
+    char_u *pstr = (*name == '_') ? name + 1 : name;
+
+    for (int i = 0; i < fgap->ga_len; ++i)
+    {
+       char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name;
+       char_u *qstr = *n == '_' ? n + 1 : n;
+       if (STRCMP(pstr, qstr) == 0)
+       {
+           semsg(_(e_duplicate_function_str), name);
+           return TRUE;
+       }
+    }
+
+    return FALSE;
+}
+
 /*
  * Update the interface class lookup table for the member index on the
  * interface to the member index in the class implementing the interface.
@@ -1080,6 +1126,11 @@ early_ret:
                semsg(_(e_invalid_object_member_declaration_str), p);
                break;
            }
+           if (has_static)
+           {
+               emsg(_(e_static_cannot_be_followed_by_this));
+               break;
+           }
            char_u *varname = p + 5;
            char_u *varname_end = NULL;
            type_T *type = NULL;
@@ -1088,6 +1139,11 @@ early_ret:
                          &varname_end, &type_list, &type,
                          is_class ? &init_expr: NULL) == FAIL)
                break;
+           if (is_duplicate_member(&objmembers, varname, varname_end))
+           {
+               vim_free(init_expr);
+               break;
+           }
            if (add_member(&objmembers, varname, varname_end,
                                          has_public, type, init_expr) == FAIL)
            {
@@ -1154,17 +1210,8 @@ early_ret:
                garray_T *fgap = has_static || is_new
                                               ? &classfunctions : &objmethods;
                // Check the name isn't used already.
-               for (int i = 0; i < fgap->ga_len; ++i)
-               {
-                   char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name;
-                   char_u *pstr = *name == '_' ? name + 1 : name;
-                   char_u *qstr = *n == '_' ? n + 1 : n;
-                   if (STRCMP(pstr, qstr) == 0)
-                   {
-                       semsg(_(e_duplicate_function_str), name);
-                       break;
-                   }
-               }
+               if (is_duplicate_method(fgap, name))
+                   break;
 
                if (ga_grow(fgap, 1) == OK)
                {
@@ -1197,6 +1244,11 @@ early_ret:
                      &varname_end, &type_list, &type,
                      is_class ? &init_expr : NULL) == FAIL)
                break;
+           if (is_duplicate_member(&classmembers, varname, varname_end))
+           {
+               vim_free(init_expr);
+               break;
+           }
            if (add_member(&classmembers, varname, varname_end,
                                      has_public, type, init_expr) == FAIL)
            {

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qahwA-005178-Vd%40256bit.org.

Raspunde prin e-mail lui