summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorErnie Rael <errael@raelity.com>2023-10-06 19:55:52 +0200
committerChristian Brabandt <cb@256bit.org>2023-10-06 19:55:52 +0200
commite6c9aa5e6a88d539a412a9b5526f41ea101aa185 (patch)
tree2ba9d1d12205cbe879b917b1e78b3df7bc43f4f9 /src
parent85f4521808dd9a587c00f9a2927e84217721cfca (diff)
patch 9.0.1999: Vim9: some error messages can be improvedv9.0.1999
Problem: Vim9: some error messages can be improved Solution: Mention the defining class for variable access error message closes: #13272 Signed-off-by: Christian Brabandt <cb@256bit.org> Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Co-authored-by: Ernie Rael <errael@raelity.com>
Diffstat (limited to 'src')
-rw-r--r--src/eval.c18
-rw-r--r--src/proto/vim9class.pro1
-rw-r--r--src/testdir/test_vim9_class.vim113
-rw-r--r--src/version.c2
-rw-r--r--src/vim9class.c75
-rw-r--r--src/vim9compile.c2
-rw-r--r--src/vim9execute.c4
-rw-r--r--src/vim9expr.c8
8 files changed, 204 insertions, 19 deletions
diff --git a/src/eval.c b/src/eval.c
index a9f7112f2d..d9fbec234c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1105,26 +1105,28 @@ get_lval_check_access(
#endif
if (cl_exec == NULL || cl_exec != cl)
{
+ char *msg = NULL;
switch (om->ocm_access)
{
case VIM_ACCESS_PRIVATE:
- semsg(_(e_cannot_access_private_variable_str),
- om->ocm_name, cl->class_name);
- return FAIL;
+ msg = e_cannot_access_private_variable_str;
+ break;
case VIM_ACCESS_READ:
// If [idx] or .key following, read only OK.
if (*p == '[' || *p == '.')
break;
if ((flags & GLV_READ_ONLY) == 0)
- {
- semsg(_(e_variable_is_not_writable_str),
- om->ocm_name, cl->class_name);
- return FAIL;
- }
+ msg = e_variable_is_not_writable_str;
break;
case VIM_ACCESS_ALL:
break;
}
+ if (msg != NULL)
+ {
+ emsg_var_cl_define(msg, om->ocm_name, 0, cl);
+ return FAIL;
+ }
+
}
return OK;
}
diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro
index f2e642ec70..e36c7e288e 100644
--- a/src/proto/vim9class.pro
+++ b/src/proto/vim9class.pro
@@ -16,6 +16,7 @@ ocmember_T *object_member_lookup(class_T *cl, char_u *name, size_t namelen, int
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);
int inside_class(cctx_T *cctx_arg, class_T *cl);
void copy_object(typval_T *from, typval_T *to);
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index dc539aca49..0c8fd7057a 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -1725,6 +1725,119 @@ def Test_class_member()
v9.CheckSourceFailure(lines, 'E1326: Variable not found on object "A": bar', 5)
enddef
+" These messages should show the defining class of the variable (base class),
+" not the class that did the reference (super class)
+def Test_defining_class_message()
+ var lines =<< trim END
+ vim9script
+
+ class Base
+ this._v1: list<list<number>>
+ endclass
+
+ class Child extends Base
+ endclass
+
+ var o = Child.new()
+ var x = o._v1
+ END
+ v9.CheckSourceFailure(lines, 'E1333: Cannot access private variable "_v1" in class "Base"', 11)
+ lines =<< trim END
+ vim9script
+
+ class Base
+ this._v1: list<list<number>>
+ endclass
+
+ class Child extends Base
+ endclass
+
+ def F()
+ var o = Child.new()
+ var x = o._v1
+ enddef
+ F()
+ END
+ v9.CheckSourceFailure(lines, 'E1333: Cannot access private variable "_v1" in class "Base"', 2)
+ lines =<< trim END
+ vim9script
+
+ class Base
+ this.v1: list<list<number>>
+ endclass
+
+ class Child extends Base
+ endclass
+
+ var o = Child.new()
+ o.v1 = []
+ END
+ v9.CheckSourceFailure(lines, 'E1335: Variable "v1" in class "Base" is not writable', 11)
+ lines =<< trim END
+ vim9script
+
+ class Base
+ this.v1: list<list<number>>
+ endclass
+
+ class Child extends Base
+ endclass
+
+ def F()
+ var o = Child.new()
+ o.v1 = []
+ enddef
+ F()
+ END
+
+ # Attempt to read a private variable that is in the middle
+ # of the class hierarchy.
+ v9.CheckSourceFailure(lines, 'E1335: Variable "v1" in class "Base" is not writable', 2)
+ lines =<< trim END
+ vim9script
+
+ class Base0
+ endclass
+
+ class Base extends Base0
+ this._v1: list<list<number>>
+ endclass
+
+ class Child extends Base
+ endclass
+
+ def F()
+ var o = Child.new()
+ var x = o._v1
+ enddef
+ F()
+ END
+ v9.CheckSourceFailure(lines, 'E1333: Cannot access private variable "_v1" in class "Base"', 2)
+
+ # Attempt to read a private variable that is at the start
+ # of the class hierarchy.
+ lines =<< trim END
+ vim9script
+
+ class Base0
+ endclass
+
+ class Base extends Base0
+ endclass
+
+ class Child extends Base
+ this._v1: list<list<number>>
+ endclass
+
+ def F()
+ var o = Child.new()
+ var x = o._v1
+ enddef
+ F()
+ END
+ v9.CheckSourceFailure(lines, 'E1333: Cannot access private variable "_v1" in class "Child"', 2)
+enddef
+
func Test_class_garbagecollect()
let lines =<< trim END
vim9script
diff --git a/src/version.c b/src/version.c
index 5335352b03..8dea204b2b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1999,
+/**/
1998,
/**/
1997,
diff --git a/src/vim9class.c b/src/vim9class.c
index 295716e18e..7d1a7fdcaa 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -2167,8 +2167,8 @@ get_member_tv(
if (*name == '_')
{
- semsg(_(e_cannot_access_private_variable_str), m->ocm_name,
- cl->class_name);
+ emsg_var_cl_define(e_cannot_access_private_variable_str,
+ m->ocm_name, 0, cl);
return FAIL;
}
@@ -2329,8 +2329,8 @@ class_object_index(
if (*name == '_')
{
- semsg(_(e_cannot_access_private_variable_str), m->ocm_name,
- cl->class_name);
+ emsg_var_cl_define(e_cannot_access_private_variable_str,
+ m->ocm_name, 0, cl);
return FAIL;
}
@@ -2581,6 +2581,57 @@ member_lookup(
}
/*
+ * Find the class that defines the named member. Look up the hierarchy
+ * starting at "cl".
+ *
+ * Return the class that defines the member "name", else NULL.
+ * Fill in "p_m", if specified, for ocmember_T in found class.
+ */
+// NOTE: if useful for something could also indirectly return vartype and idx.
+ static class_T *
+class_defining_member(class_T *cl, char_u *name, size_t len, ocmember_T **p_m)
+{
+ class_T *cl_found = NULL;
+ vartype_T vartype = VAR_UNKNOWN;
+ ocmember_T *m_found = NULL;
+
+ len = len != 0 ? len : STRLEN(name);
+
+ // Loop assumes if member is not defined in "cl", then it is not
+ // defined in any super class; the last class where it's found is the
+ // class where it is defined. Once the vartype is found, the other
+ // type is no longer checked.
+ for (class_T *super = cl; super != NULL; super = super->class_extends)
+ {
+ class_T *cl_tmp = NULL;
+ ocmember_T *m = NULL;
+ if (vartype == VAR_UNKNOWN || vartype == VAR_OBJECT)
+ {
+ if ((m = object_member_lookup(super, name, len, NULL)) != NULL)
+ {
+ cl_tmp = super;
+ vartype = VAR_OBJECT;
+ }
+ }
+ if (vartype == VAR_UNKNOWN || vartype == VAR_CLASS)
+ {
+ if (( m = class_member_lookup(super, name, len, NULL)) != NULL)
+ {
+ cl_tmp = super;
+ vartype = VAR_OBJECT;
+ }
+ }
+ if (cl_tmp == NULL)
+ break; // member is not in this or any super class.
+ cl_found = cl_tmp;
+ m_found = m;
+ }
+ if (p_m != NULL)
+ *p_m = m_found;
+ return cl_found;
+}
+
+/*
* Lookup a class or object method by name. If v_type is VAR_CLASS, then
* lookup a class method and if it is VAR_OBJECT, then lookup a object method.
*
@@ -2854,6 +2905,22 @@ object_free_nonref(int copyID)
}
/*
+ * Output message which takes a variable name and the class that defines it.
+ * "cl" is that class where the name was found. Search "cl"'s hierarchy to
+ * find the defining class.
+ */
+ void
+emsg_var_cl_define(char *msg, char_u *name, size_t len, class_T *cl)
+{
+ ocmember_T *m;
+ class_T *cl_def = class_defining_member(cl, name, len, &m);
+ if (cl_def != NULL)
+ semsg(_(msg), m->ocm_name, cl_def->class_name);
+ else
+ emsg(_(e_internal_error_please_report_a_bug));
+}
+
+/*
* Echo a class or object method not found message.
*/
void
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 136bea49d3..828fe02e81 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1616,7 +1616,7 @@ lhs_class_member_modifiable(lhs_T *lhs, char_u *var_start, cctx_T *cctx)
char *msg = (m->ocm_access == VIM_ACCESS_PRIVATE)
? e_cannot_access_private_variable_str
: e_variable_is_not_writable_str;
- semsg(_(msg), m->ocm_name, cl->class_name);
+ emsg_var_cl_define(msg, m->ocm_name, 0, cl);
return FALSE;
}
diff --git a/src/vim9execute.c b/src/vim9execute.c
index a899745207..f237132a89 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2180,8 +2180,8 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
{
if (*member == '_')
{
- semsg(_(e_cannot_access_private_variable_str),
- m->ocm_name, cl->class_name);
+ emsg_var_cl_define(e_cannot_access_private_variable_str,
+ m->ocm_name, 0, cl);
status = FAIL;
}
diff --git a/src/vim9expr.c b/src/vim9expr.c
index 05eb524180..c15021e82a 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -407,8 +407,8 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
{
if (*name == '_' && !inside_class(cctx, cl))
{
- semsg(_(e_cannot_access_private_variable_str), m->ocm_name,
- cl->class_name);
+ emsg_var_cl_define(e_cannot_access_private_variable_str,
+ m->ocm_name, 0, cl);
return FAIL;
}
@@ -443,8 +443,8 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
// it is defined.
if (*name == '_' && cctx->ctx_ufunc->uf_class != cl)
{
- semsg(_(e_cannot_access_private_variable_str), m->ocm_name,
- cl->class_name);
+ emsg_var_cl_define(e_cannot_access_private_variable_str,
+ m->ocm_name, 0, cl);
return FAIL;
}