mirror of
https://github.com/vim/vim.git
synced 2025-08-26 20:03:41 -04:00
patch 9.0.1804: Vim9: no support for private object methods
Problem: Vim9: no support for private object methods Solution: Add support for private object/class methods closes: #12920 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
parent
03e44a1d70
commit
cd7293bf6c
@ -129,6 +129,7 @@ Further Vim9 improvements, possibly after launch:
|
||||
or: def _Func()
|
||||
Perhaps use "private" keyword instead of "_" prefix?
|
||||
- "final" object members - can only be set in the constructor.
|
||||
- Support export/import of classes and interfaces.
|
||||
- Cannot use class type of itself in the method (Issue #12369)
|
||||
- Cannot use an object method in a lambda #12417
|
||||
Define all methods before compiling them?
|
||||
|
@ -178,6 +178,26 @@ number to the total number of lines: >
|
||||
enddef
|
||||
|
||||
|
||||
Private methods ~
|
||||
If you want object methods to be accessible only from other methods of the
|
||||
same class and not used from outside the class, then you can make them
|
||||
private. This is done by prefixing the method name with an underscore: >
|
||||
|
||||
class SomeClass
|
||||
def _Foo(): number
|
||||
return 10
|
||||
enddef
|
||||
def Bar(): number
|
||||
return this._Foo()
|
||||
enddef
|
||||
endclass
|
||||
<
|
||||
Accessing a private method outside the class will result in an error (using
|
||||
the above class): >
|
||||
|
||||
var a = SomeClass.new()
|
||||
a._Foo()
|
||||
<
|
||||
Simplifying the new() method ~
|
||||
|
||||
Many constructors take values for the object members. Thus you very often see
|
||||
@ -284,6 +304,18 @@ object members, they cannot use the "this" keyword. >
|
||||
Inside the class the function can be called by name directly, outside the
|
||||
class the class name must be prefixed: `OtherThing.ClearTotalSize()`.
|
||||
|
||||
Just like object methods the access can be made private by using an underscore
|
||||
as the first character in the method name: >
|
||||
|
||||
class OtherThing
|
||||
static def _Foo()
|
||||
echo "Foo"
|
||||
enddef
|
||||
def Bar()
|
||||
OtherThing._Foo()
|
||||
enddef
|
||||
endclass
|
||||
|
||||
==============================================================================
|
||||
|
||||
4. Using an abstract class *Vim9-abstract-class*
|
||||
|
@ -3484,6 +3484,11 @@ EXTERN char e_warning_pointer_block_corrupted[]
|
||||
INIT(= N_("E1364: Warning: Pointer block corrupted"));
|
||||
EXTERN char e_cannot_use_a_return_type_with_new[]
|
||||
INIT(= N_("E1365: Cannot use a return type with the \"new\" function"));
|
||||
EXTERN char e_cannot_access_private_method_str[]
|
||||
INIT(= N_("E1366: Cannot access private method: %s"));
|
||||
|
||||
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_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[]
|
||||
@ -3501,4 +3506,4 @@ EXTERN char e_member_str_type_mismatch_expected_str_but_got_str[]
|
||||
EXTERN char e_method_str_type_mismatch_expected_str_but_got_str[]
|
||||
INIT(= N_("E1407: Member \"%s\": type mismatch, expected %s but got %s"));
|
||||
|
||||
// E1366 - E1399 unused
|
||||
// E1368 - E1399 unused
|
||||
|
@ -1489,8 +1489,8 @@ typedef struct {
|
||||
#define TTFLAG_SUPER 0x40 // object from "super".
|
||||
|
||||
typedef enum {
|
||||
VIM_ACCESS_PRIVATE, // read/write only inside th class
|
||||
VIM_ACCESS_READ, // read everywhere, write only inside th class
|
||||
VIM_ACCESS_PRIVATE, // read/write only inside the class
|
||||
VIM_ACCESS_READ, // read everywhere, write only inside the class
|
||||
VIM_ACCESS_ALL // read/write everywhere
|
||||
} omacc_T;
|
||||
|
||||
@ -1790,6 +1790,7 @@ struct ufunc_S
|
||||
|
||||
class_T *uf_class; // for object method and constructor; does not
|
||||
// count for class_refcount
|
||||
int uf_private; // TRUE if class or object private method
|
||||
|
||||
garray_T uf_args; // arguments, including optional arguments
|
||||
garray_T uf_def_args; // default argument expressions
|
||||
|
@ -2801,4 +2801,594 @@ def Test_object_lockvar()
|
||||
v9.CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
" Test for a private object method
|
||||
def Test_private_object_method()
|
||||
# Try calling a private method using an object (at the script level)
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
a._Foo()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Try calling a private method using an object (from a def function)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
def T()
|
||||
var a = A.new()
|
||||
a._Foo()
|
||||
enddef
|
||||
T()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Use a private method from another object method (in script context)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
def Bar(): number
|
||||
return this._Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
assert_equal(1234, a.Bar())
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Use a private method from another object method (def function context)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
def Bar(): number
|
||||
return this._Foo()
|
||||
enddef
|
||||
endclass
|
||||
def T()
|
||||
var a = A.new()
|
||||
assert_equal(1234, a.Bar())
|
||||
enddef
|
||||
T()
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Try calling a private method without the "this" prefix
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
def Bar(): number
|
||||
return _Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
a.Bar()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E117: Unknown function: _Foo')
|
||||
|
||||
# Try calling a private method using the class name
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
A._Foo()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": _Foo()')
|
||||
|
||||
# Try to use "public" keyword when defining a private method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
public def _Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
a._Foo()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1331: Public must be followed by "this" or "static"')
|
||||
|
||||
# Define two private methods with the same name
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo()
|
||||
enddef
|
||||
def _Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1355: Duplicate function: _Foo')
|
||||
|
||||
# Define a private method and a object method with the same name
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo()
|
||||
enddef
|
||||
def Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1355: Duplicate function: Foo')
|
||||
|
||||
# Define an object method and a private method with the same name
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def Foo()
|
||||
enddef
|
||||
def _Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1355: Duplicate function: _Foo')
|
||||
|
||||
# Call a public method and a private method from a private method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def Foo(): number
|
||||
return 100
|
||||
enddef
|
||||
def _Bar(): number
|
||||
return 200
|
||||
enddef
|
||||
def _Baz()
|
||||
assert_equal(100, this.Foo())
|
||||
assert_equal(200, this._Bar())
|
||||
enddef
|
||||
def T()
|
||||
this._Baz()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
a.T()
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Try calling a private method from another class
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 100
|
||||
enddef
|
||||
endclass
|
||||
class B
|
||||
def Foo(): number
|
||||
var a = A.new()
|
||||
a._Foo()
|
||||
enddef
|
||||
endclass
|
||||
var b = B.new()
|
||||
b.Foo()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Call a private object method from a child class object method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
class B extends A
|
||||
def Bar()
|
||||
enddef
|
||||
endclass
|
||||
class C extends B
|
||||
def Baz(): number
|
||||
return this._Foo()
|
||||
enddef
|
||||
endclass
|
||||
var c = C.new()
|
||||
assert_equal(1234, c.Baz())
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Call a private object method from a child class object
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class A
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
class B extends A
|
||||
def Bar()
|
||||
enddef
|
||||
endclass
|
||||
class C extends B
|
||||
def Baz(): number
|
||||
enddef
|
||||
endclass
|
||||
var c = C.new()
|
||||
assert_equal(1234, c._Foo())
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Using "_" prefix in a method name should fail outside of a class
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
var a = _Foo()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1267: Function name must start with a capital: _Foo(): number')
|
||||
enddef
|
||||
|
||||
" Test for an private class method
|
||||
def Test_private_class_method()
|
||||
# Try calling a class private method (at the script level)
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
A._Foo()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Try calling a class private method (from a def function)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
def T()
|
||||
A._Foo()
|
||||
enddef
|
||||
T()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Try calling a class private method using an object (at the script level)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
a._Foo()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": _Foo()')
|
||||
|
||||
# Try calling a class private method using an object (from a def function)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
def T()
|
||||
var a = A.new()
|
||||
a._Foo()
|
||||
enddef
|
||||
T()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": _Foo()')
|
||||
|
||||
# Use a class private method from an object method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
def Bar()
|
||||
assert_equal(1234, A._Foo())
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
a.Bar()
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Use a class private method from another class private method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
static def _Foo1(): number
|
||||
return 1234
|
||||
enddef
|
||||
static def _Foo2()
|
||||
assert_equal(1234, A._Foo1())
|
||||
enddef
|
||||
def Bar()
|
||||
A._Foo2()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
a.Bar()
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Declare a class method and a class private method with the same name
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
static def _Foo()
|
||||
enddef
|
||||
static def Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1355: Duplicate function: Foo')
|
||||
|
||||
# Try calling a class private method from another class
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
class B
|
||||
def Foo(): number
|
||||
return A._Foo()
|
||||
enddef
|
||||
endclass
|
||||
var b = B.new()
|
||||
assert_equal(1234, b.Foo())
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Call a private class method from a child class object method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
class B extends A
|
||||
def Bar()
|
||||
enddef
|
||||
endclass
|
||||
class C extends B
|
||||
def Baz(): number
|
||||
return A._Foo()
|
||||
enddef
|
||||
endclass
|
||||
var c = C.new()
|
||||
assert_equal(1234, c.Baz())
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Call a private class method from a child class private class method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
class B extends A
|
||||
def Bar()
|
||||
enddef
|
||||
endclass
|
||||
class C extends B
|
||||
static def Baz(): number
|
||||
return A._Foo()
|
||||
enddef
|
||||
endclass
|
||||
assert_equal(1234, C.Baz())
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Call a private class method from a child class object
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class A
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
class B extends A
|
||||
def Bar()
|
||||
enddef
|
||||
endclass
|
||||
class C extends B
|
||||
def Baz(): number
|
||||
enddef
|
||||
endclass
|
||||
var c = C.new()
|
||||
assert_equal(1234, C._Foo())
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
enddef
|
||||
|
||||
" Test for an interface private object_method
|
||||
def Test_interface_private_object_method()
|
||||
# Implement an interface private method and use it from a public method
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
interface Intf
|
||||
def _Foo(): number
|
||||
endinterface
|
||||
class A implements Intf
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
def Bar(): number
|
||||
return this._Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
assert_equal(1234, a.Bar())
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Call an interface private class method (script context)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
interface Intf
|
||||
def _Foo(): number
|
||||
endinterface
|
||||
class A implements Intf
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
assert_equal(1234, a._Foo())
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Call an interface private class method (def context)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
interface Intf
|
||||
def _Foo(): number
|
||||
endinterface
|
||||
class A implements Intf
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
def T()
|
||||
var a = A.new()
|
||||
assert_equal(1234, a._Foo())
|
||||
enddef
|
||||
T()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()')
|
||||
|
||||
# Implement an interface private object method as a private class method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
interface Intf
|
||||
def _Foo(): number
|
||||
endinterface
|
||||
class A implements Intf
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1349: Function "_Foo" of interface "Intf" not implemented')
|
||||
enddef
|
||||
|
||||
" Test for an interface private class method
|
||||
def Test_interface_private_class_method()
|
||||
# Implement an interface private class method and use it from a public method
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
interface Intf
|
||||
static def _Foo(): number
|
||||
endinterface
|
||||
class A implements Intf
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
def Bar(): number
|
||||
return A._Foo()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
assert_equal(1234, a.Bar())
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
# Call an interface private class method (script context)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
interface Intf
|
||||
static def _Foo(): number
|
||||
endinterface
|
||||
class A implements Intf
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
assert_equal(1234, A._Foo())
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo())')
|
||||
|
||||
# Call an interface private class method (def context)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
interface Intf
|
||||
static def _Foo(): number
|
||||
endinterface
|
||||
class A implements Intf
|
||||
static def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
def T()
|
||||
assert_equal(1234, A._Foo())
|
||||
enddef
|
||||
T()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo())')
|
||||
|
||||
# Implement an interface private class method as a private object method
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
interface Intf
|
||||
static def _Foo(): number
|
||||
endinterface
|
||||
class A implements Intf
|
||||
def _Foo(): number
|
||||
return 1234
|
||||
enddef
|
||||
endclass
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1349: Function "_Foo" of interface "Intf" not implemented')
|
||||
enddef
|
||||
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||
|
@ -4369,10 +4369,14 @@ trans_function_name_ext(
|
||||
lead += (int)STRLEN(sid_buf);
|
||||
}
|
||||
}
|
||||
// The function name must start with an upper case letter (unless it is a
|
||||
// Vim9 class new() function or a Vim9 class private method)
|
||||
else if (!(flags & TFN_INT)
|
||||
&& (builtin_function(lv.ll_name, len)
|
||||
|| (vim9script && *lv.ll_name == '_'))
|
||||
&& !((flags & TFN_IN_CLASS) && STRNCMP(lv.ll_name, "new", 3) == 0))
|
||||
&& !((flags & TFN_IN_CLASS)
|
||||
&& (STRNCMP(lv.ll_name, "new", 3) == 0
|
||||
|| (*lv.ll_name == '_'))))
|
||||
{
|
||||
semsg(_(vim9script ? e_function_name_must_start_with_capital_str
|
||||
: e_function_name_must_start_with_capital_or_s_str),
|
||||
|
@ -699,6 +699,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1804,
|
||||
/**/
|
||||
1803,
|
||||
/**/
|
||||
|
@ -357,6 +357,13 @@ validate_interface_methods(
|
||||
if (check_type_maybe(if_fp[if_i]->uf_func_type,
|
||||
cl_fp[cl_i]->uf_func_type, TRUE, where) != OK)
|
||||
success = FALSE;
|
||||
// Ensure the public/private access level is matching.
|
||||
if (if_fp[if_i]->uf_private != cl_fp[cl_i]->uf_private)
|
||||
{
|
||||
semsg(_(e_interface_str_and_class_str_function_access_not_same),
|
||||
cl_name, if_name);
|
||||
success = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1150,7 +1157,9 @@ early_ret:
|
||||
for (int i = 0; i < fgap->ga_len; ++i)
|
||||
{
|
||||
char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name;
|
||||
if (STRCMP(name, n) == 0)
|
||||
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);
|
||||
break;
|
||||
@ -1162,6 +1171,11 @@ early_ret:
|
||||
if (is_new)
|
||||
uf->uf_flags |= FC_NEW;
|
||||
|
||||
// If the method name starts with '_', then it a private
|
||||
// method.
|
||||
if (*name == '_')
|
||||
uf->uf_private = TRUE;
|
||||
|
||||
((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
|
||||
++fgap->ga_len;
|
||||
}
|
||||
@ -1523,6 +1537,13 @@ class_object_index(
|
||||
typval_T argvars[MAX_FUNC_ARGS + 1];
|
||||
int argcount = 0;
|
||||
|
||||
if (fp->uf_private)
|
||||
{
|
||||
// Cannot access a private method outside of a class
|
||||
semsg(_(e_cannot_access_private_method_str), name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
char_u *argp = name_end;
|
||||
int ret = get_func_arguments(&argp, evalarg, 0,
|
||||
argvars, &argcount);
|
||||
|
@ -251,6 +251,30 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns TRUE if the current function is inside the class "cl" or one of the
|
||||
* parent classes.
|
||||
*/
|
||||
static int
|
||||
inside_class_hierarchy(cctx_T *cctx_arg, class_T *cl)
|
||||
{
|
||||
for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
|
||||
{
|
||||
if (cctx->ctx_ufunc != NULL && cctx->ctx_ufunc->uf_class != NULL)
|
||||
{
|
||||
class_T *clp = cctx->ctx_ufunc->uf_class;
|
||||
while (clp != NULL)
|
||||
{
|
||||
if (clp == cl)
|
||||
return TRUE;
|
||||
clp = clp->class_extends;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile ".member" coming after an object or class.
|
||||
*/
|
||||
@ -348,6 +372,12 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (ufunc->uf_private && !inside_class_hierarchy(cctx, cl))
|
||||
{
|
||||
semsg(_(e_cannot_access_private_method_str), name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// Compile the arguments and call the class function or object method.
|
||||
// The object method will know that the object is on the stack, just
|
||||
// before the arguments.
|
||||
|
Loading…
x
Reference in New Issue
Block a user