mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
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 <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
parent
1d3e0e8f31
commit
2ba9d2e14e
@ -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[]
|
||||
|
@ -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
|
||||
|
@ -699,6 +699,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1814,
|
||||
/**/
|
||||
1813,
|
||||
/**/
|
||||
|
@ -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);
|
||||
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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user