# HG changeset patch # User Christian Brabandt # Date 1695933904 -7200 # Node ID 17301c6417491c89cffc22eb8a42d0dd57c03307 # Parent 7ba7c38a991431b6947b8a1444dc75c402fd74ac patch 9.0.1949: Vim9: allows reserved keywords as members Commit: https://github.com/vim/vim/commit/f057aca1cc2480e820b3ca5d8d407e3976369777 Author: Yegappan Lakshmanan Date: Thu Sep 28 22:28:15 2023 +0200 patch 9.0.1949: Vim9: allows reserved keywords as members Problem: Vim9: allows reserved keywords as members Solution: Disallow reserved keywords, disallow duplicate object and class variables closes: #13209 Signed-off-by: Christian Brabandt Co-authored-by: Yegappan Lakshmanan diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -4150,7 +4150,7 @@ def Test_dup_member_variable() assert_equal(10, C.val) assert_equal(20, c.val) END - v9.CheckSourceSuccess(lines) + v9.CheckSourceFailure(lines, 'E1369: Duplicate variable: val', 4) # Duplicate object member variable in a derived class lines =<< trim END @@ -5768,4 +5768,91 @@ def Test_freed_object_from_previous_meth v9.CheckSourceSuccess(lines) enddef +" Test for duplicate object and class variable +def Test_duplicate_variable() + # Object variable name is same as the class variable name + var lines =<< trim END + vim9script + class A + public static sval: number + public this.sval: number + endclass + var a = A.new() + END + v9.CheckSourceFailure(lines, 'E1369: Duplicate variable: sval', 4) + + # Duplicate variable name and calling a class method + lines =<< trim END + vim9script + class A + public static sval: number + public this.sval: number + def F1() + echo this.sval + enddef + static def F2() + echo sval + enddef + endclass + A.F2() + END + v9.CheckSourceFailure(lines, 'E1369: Duplicate variable: sval', 4) + + # Duplicate variable with an empty constructor + lines =<< trim END + vim9script + class A + public static sval: number + public this.sval: number + def new() + enddef + endclass + var a = A.new() + END + v9.CheckSourceFailure(lines, 'E1369: Duplicate variable: sval', 4) +enddef + +" Test for using a reserved keyword as a variable name +def Test_reserved_varname() + for kword in ['true', 'false', 'null', 'null_blob', 'null_dict', + 'null_function', 'null_list', 'null_partial', 'null_string', + 'null_channel', 'null_job', 'super', 'this'] + + var lines =<< trim eval END + vim9script + class C + public this.{kword}: list = [1, 2, 3] + endclass + var o = C.new() + END + v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3) + + lines =<< trim eval END + vim9script + class C + public this.{kword}: list = [1, 2, 3] + def new() + enddef + endclass + var o = C.new() + END + v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3) + + lines =<< trim eval END + vim9script + class C + public this.{kword}: list = [1, 2, 3] + def new() + enddef + def F() + echo this.{kword} + enddef + endclass + var o = C.new() + o.F() + END + v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3) + endfor +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1949, +/**/ 1948, /**/ 1947, diff --git a/src/vim9class.c b/src/vim9class.c --- a/src/vim9class.c +++ b/src/vim9class.c @@ -893,24 +893,52 @@ check_func_arg_names( } /* - * Returns TRUE if the member "varname" is already defined. + * Returns TRUE if 'varname' is a reserved keyword name */ static int -is_duplicate_member(garray_T *mgap, char_u *varname, char_u *varname_end) +is_reserved_varname(char_u *varname, char_u *varname_end) +{ + int reserved = FALSE; + char_u save_varname_end = *varname_end; + *varname_end = NUL; + + reserved = check_reserved_name(varname, FALSE) == FAIL; + + *varname_end = save_varname_end; + + return reserved; +} + +/* + * Returns TRUE if the variable "varname" is already defined either as a class + * variable or as an object variable. + */ + static int +is_duplicate_variable( + garray_T *class_members, + garray_T *obj_members, + char_u *varname, + char_u *varname_end) { char_u *name = vim_strnsave(varname, varname_end - varname); char_u *pstr = (*name == '_') ? name + 1 : name; int dup = FALSE; - for (int i = 0; i < mgap->ga_len; ++i) + for (int loop = 1; loop <= 2; loop++) { - ocmember_T *m = ((ocmember_T *)mgap->ga_data) + i; - char_u *qstr = *m->ocm_name == '_' ? m->ocm_name + 1 : m->ocm_name; - if (STRCMP(pstr, qstr) == 0) + // loop == 1: class variables, loop == 2: object variables + garray_T *vgap = (loop == 1) ? class_members : obj_members; + for (int i = 0; i < vgap->ga_len; ++i) { - semsg(_(e_duplicate_variable_str), name); - dup = TRUE; - break; + ocmember_T *m = ((ocmember_T *)vgap->ga_data) + i; + char_u *qstr = *m->ocm_name == '_' ? m->ocm_name + 1 + : m->ocm_name; + if (STRCMP(pstr, qstr) == 0) + { + semsg(_(e_duplicate_variable_str), name); + dup = TRUE; + break; + } } } @@ -1646,7 +1674,13 @@ early_ret: &varname_end, &type_list, &type, is_class ? &init_expr: NULL) == FAIL) break; - if (is_duplicate_member(&objmembers, varname, varname_end)) + if (is_reserved_varname(varname, varname_end)) + { + vim_free(init_expr); + break; + } + if (is_duplicate_variable(&classmembers, &objmembers, varname, + varname_end)) { vim_free(init_expr); break; @@ -1768,7 +1802,13 @@ early_ret: &varname_end, &type_list, &type, is_class ? &init_expr : NULL) == FAIL) break; - if (is_duplicate_member(&classmembers, varname, varname_end)) + if (is_reserved_varname(varname, varname_end)) + { + vim_free(init_expr); + break; + } + if (is_duplicate_variable(&classmembers, &objmembers, varname, + varname_end)) { vim_free(init_expr); break;