From 6acf757c6a11c0653b0132a17c22983856da5ad6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Jan 2023 19:53:30 +0000 Subject: [PATCH] patch 9.0.1127: no error if function argument shadows class member Problem: No error if function argument shadows class member. Solution: Give an error for shadowing a class member. --- src/proto/vim9class.pro | 2 +- src/testdir/test_vim9_class.vim | 35 +++++++++++++++++++++- src/version.c | 2 ++ src/vim9class.c | 52 ++++++++++++++++----------------- src/vim9compile.c | 46 ++++++++++++----------------- src/vim9expr.c | 2 +- 6 files changed, 82 insertions(+), 57 deletions(-) diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro index edbddd267..66c6107a1 100644 --- a/src/proto/vim9class.pro +++ b/src/proto/vim9class.pro @@ -6,7 +6,7 @@ void ex_enum(exarg_T *eap); void ex_type(exarg_T *eap); int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose); ufunc_T *find_class_func(char_u **arg); -int class_member_exists(char_u *name, class_T **cl_ret, int *idx_ret, cctx_T *cctx); +int class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx); void copy_object(typval_T *from, typval_T *to); void object_unref(object_T *obj); void copy_class(typval_T *from, typval_T *to); diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index 9dd6f8394..8cb911338 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -367,7 +367,8 @@ def Test_class_object_member_access() v9.CheckScriptFailure(lines, 'E1041:') enddef -def Test_class_member_access() +def Test_class_member() + # check access rules var lines =<< trim END vim9script class TextPos @@ -401,6 +402,38 @@ def Test_class_member_access() assert_equal(17, TextPos.anybody) END v9.CheckScriptSuccess(lines) + + # check shadowing + lines =<< trim END + vim9script + + class Some + static count = 0 + def Method(count: number) + echo count + enddef + endclass + + var s = Some.new() + s.Method(7) + END + v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count') + + lines =<< trim END + vim9script + + class Some + static count = 0 + def Method(arg: number) + var count = 3 + echo arg count + enddef + endclass + + var s = Some.new() + s.Method(7) + END + v9.CheckScriptFailure(lines, 'E1341: Variable already declared in the class: count') enddef def Test_class_function() diff --git a/src/version.c b/src/version.c index 389209aae..dc320bef6 100644 --- a/src/version.c +++ b/src/version.c @@ -695,6 +695,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1127, /**/ 1126, /**/ diff --git a/src/vim9class.c b/src/vim9class.c index b05dea8ef..8e05a17f4 100644 --- a/src/vim9class.c +++ b/src/vim9class.c @@ -358,17 +358,19 @@ ex_class(exarg_T *eap) ufunc_T *uf = define_function(&ea, NULL, &lines_to_free, TRUE); ga_clear_strings(&lines_to_free); - // TODO: how about errors? - int is_new = STRNCMP(uf->uf_name, "new", 3) == 0; - garray_T *fgap = has_static || is_new - ? &classfunctions : &objmethods; - if (uf != NULL && ga_grow(fgap, 1) == OK) + if (uf != NULL) { - if (is_new) - uf->uf_flags |= FC_NEW; + int is_new = STRNCMP(uf->uf_name, "new", 3) == 0; + garray_T *fgap = has_static || is_new + ? &classfunctions : &objmethods; + if (ga_grow(fgap, 1) == OK) + { + if (is_new) + uf->uf_flags |= FC_NEW; - ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf; - ++fgap->ga_len; + ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf; + ++fgap->ga_len; + } } } @@ -863,32 +865,30 @@ fail_after_eval: } /* - * If "cctx->ctx_ufunc" indicates we are in a class, check if "name" is a class - * member. If it is then return TRUE and set "cl_ret" and "idx_ret". + * If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the + * index in class.class_class_members[]. + * If "cl_ret" is not NULL set it to the class. + * Otherwise return -1; */ int -class_member_exists( - char_u *name, - class_T **cl_ret, - int *idx_ret, - cctx_T *cctx) +class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx) { - if (cctx->ctx_ufunc == NULL || cctx->ctx_ufunc->uf_class == NULL) - return FALSE; + if (cctx == NULL || cctx->ctx_ufunc == NULL + || cctx->ctx_ufunc->uf_class == NULL) + return -1; class_T *cl = cctx->ctx_ufunc->uf_class; - for (int idx = 0; idx < cl->class_class_member_count; ++idx) + for (int i = 0; i < cl->class_class_member_count; ++i) { - ocmember_T *m = &cl->class_class_members[idx]; - if (STRCMP(m->ocm_name, name) == 0) + ocmember_T *m = &cl->class_class_members[i]; + if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL) { - *cl_ret = cl; - *idx_ret = idx; - return TRUE; + if (cl_ret != NULL) + *cl_ret = cl; + return i; } } - - return FALSE; + return -1; } /* diff --git a/src/vim9compile.c b/src/vim9compile.c index 0d980ba4e..0e6c32cbf 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -301,28 +301,6 @@ script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack) return FAIL; } -/* - * If "name" is a class member in cctx->ctx_ufunc->uf_class return the index in - * class.class_class_members[]. - * Otherwise return -1; - */ - static int -class_member_index(char_u *name, size_t len, cctx_T *cctx) -{ - if (cctx == NULL || cctx->ctx_ufunc == NULL - || cctx->ctx_ufunc->uf_class == NULL) - return -1; - class_T *cl = cctx->ctx_ufunc->uf_class; - 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) - return i; - } - return -1; -} - /* * Return TRUE if "name" is a local variable, argument, script variable or * imported. @@ -338,7 +316,7 @@ variable_exists(char_u *name, size_t len, cctx_T *cctx) && (cctx->ctx_ufunc->uf_flags & FC_OBJECT) && STRNCMP(name, "this", 4) == 0))) || script_var_exists(name, len, cctx, NULL) == OK - || class_member_index(name, len, cctx) >= 0 + || class_member_index(name, len, NULL, cctx) >= 0 || find_imported(name, len, FALSE) != NULL; } @@ -376,9 +354,6 @@ check_defined( if (len == 1 && *p == '_') return OK; - if (class_member_index(p, len, cctx) >= 0) - return OK; - if (script_var_exists(p, len, cctx, cstack) == OK) { if (is_arg) @@ -388,6 +363,15 @@ check_defined( return FAIL; } + if (class_member_index(p, len, NULL, cctx) >= 0) + { + if (is_arg) + semsg(_(e_argument_already_declared_in_class_str), p); + else + semsg(_(e_variable_already_declared_in_class_str), p); + return FAIL; + } + p[len] = NUL; if ((cctx != NULL && (lookup_local(p, len, NULL, cctx) == OK @@ -1592,8 +1576,14 @@ compile_lhs( } } else if ((lhs->lhs_classmember_idx = class_member_index( - var_start, lhs->lhs_varlen, cctx)) >= 0) + var_start, lhs->lhs_varlen, NULL, cctx)) >= 0) { + if (is_decl) + { + semsg(_(e_variable_already_declared_in_class_str), + lhs->lhs_name); + return FAIL; + } lhs->lhs_dest = dest_class_member; lhs->lhs_class = cctx->ctx_ufunc->uf_class; } @@ -2264,7 +2254,7 @@ compile_assignment( CLEAR_FIELD(lhs); long start_lnum = SOURCING_LNUM; - int has_arg_is_set_prefix = STRNCMP(arg, "ifargisset ", 11) == 0; + int has_arg_is_set_prefix = STRNCMP(arg, "ifargisset ", 11) == 0; if (has_arg_is_set_prefix) { arg += 11; diff --git a/src/vim9expr.c b/src/vim9expr.c index 463e79cbe..4a3527f05 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -603,7 +603,7 @@ compile_load( else gen_load = TRUE; } - else if (class_member_exists(name, &cl, &idx, cctx)) + else if ((idx = class_member_index(*arg, len, &cl, cctx)) >= 0) { res = generate_CLASSMEMBER(cctx, TRUE, cl, idx); } -- 2.40.0