Mercurial > vim
diff src/vim9compile.c @ 33286:0c3553cfe22e v9.0.1909
patch 9.0.1909: Vim9: problem calling class method from other class
Commit: https://github.com/vim/vim/commit/00cd18222ee1551c65228e9556c158624507fc7a
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Mon Sep 18 19:56:49 2023 +0200
patch 9.0.1909: Vim9: problem calling class method from other class
Problem: Vim9: problem calling class method from other class
Solution: Fix this problem, fix readonly object access, update error
messages.
Calling a class method from another method without the class name prefix
doesn't work properly.
A readonly object variable is modifiable outside the class using a
nested object assignment.
Remove the unused E1338 error message.
Update error messages.
closes: #13116
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 18 Sep 2023 20:00:12 +0200 |
parents | aba1fa2b7d1e |
children | 6340c608ca54 |
line wrap: on
line diff
--- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1579,6 +1579,47 @@ is_decl_command(cmdidx_T cmdidx) } /* + * Returns TRUE if the class or object variable in "lhs" is modifiable. + * "var_start" points to the start of the variable name and "lhs->lhs_varlen" + * has the total length. Note that the "lhs" can be nested an object reference + * (e.g. a.b.c.d.var). + */ + static int +lhs_class_member_modifiable(lhs_T *lhs, char_u *var_start, cctx_T *cctx) +{ + size_t varlen = lhs->lhs_varlen; + class_T *cl = lhs->lhs_type->tt_class; + int is_object = lhs->lhs_type->tt_type == VAR_OBJECT; + char_u *name = var_start + varlen + 1; + size_t namelen = lhs->lhs_end - var_start - varlen - 1; + ocmember_T *m; + + m = member_lookup(cl, lhs->lhs_type->tt_type, name, namelen, NULL); + if (m == NULL) + { + member_not_found_msg(cl, lhs->lhs_type->tt_type, name, namelen); + return FALSE; + } + + // 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_member_str + : e_cannot_change_readonly_variable_str; + semsg(_(msg), m->ocm_name); + return FALSE; + } + + return TRUE; +} + +/* * Figure out the LHS type and other properties for an assignment or one item * of ":unlet" with an index. * Returns OK or FAIL. @@ -1691,9 +1732,9 @@ compile_lhs( { if (is_decl) { - // if we come here with what looks like an assignment like .= - // but which has been reject by assignment_len() from may_compile_assignment - // give a better error message + // if we come here with what looks like an assignment like + // .= but which has been reject by assignment_len() from + // may_compile_assignment give a better error message char_u *p = skipwhite(lhs->lhs_end); if (p[0] == '.' && p[1] == '=') emsg(_(e_dot_equal_not_supported_with_script_version_two)); @@ -1959,36 +2000,17 @@ compile_lhs( { // for an object or class member get the type of the member class_T *cl = lhs->lhs_type->tt_class; - ocmember_T *m; int is_object = lhs->lhs_type->tt_type == VAR_OBJECT; + if (!lhs_class_member_modifiable(lhs, var_start, cctx)) + return FAIL; + lhs->lhs_member_type = class_member_type(cl, is_object, after + 1, lhs->lhs_end, - &lhs->lhs_member_idx, &m); + &lhs->lhs_member_idx); if (lhs->lhs_member_idx < 0) return FAIL; - if ((cl->class_flags & CLASS_INTERFACE) != 0 - && lhs->lhs_type->tt_type == VAR_CLASS) - { - semsg(_(e_interface_static_direct_access_str), - cl->class_name, m->ocm_name); - return FAIL; - } - // 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_member_str - : e_cannot_change_readonly_variable_str; - semsg(_(msg), m->ocm_name); - return FAIL; - } } else { @@ -2163,6 +2185,14 @@ compile_load_lhs( lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void : get_type_on_stack(cctx, 0); + + if (lhs->lhs_type->tt_type == VAR_OBJECT) + { + // Check whether the object variable is modifiable + if (!lhs_class_member_modifiable(lhs, var_start, cctx)) + return FAIL; + } + // Now we can properly check the type. The variable is indexed, thus // we need the member type. For a class or object we don't know the // type yet, it depends on what member is used. @@ -2198,8 +2228,7 @@ compile_load_lhs_with_index(lhs_T *lhs, class_T *cl = lhs->lhs_type->tt_class; type_T *type = class_member_type(cl, TRUE, dot + 1, - lhs->lhs_end, &lhs->lhs_member_idx, - NULL); + lhs->lhs_end, &lhs->lhs_member_idx); if (lhs->lhs_member_idx < 0) return FAIL;