mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
merge revision(s) r49222,r49480,r49493: [Backport #10765]
method.h: UNDEFINED_REFINED_METHOD_P * method.h (UNDEFINED_REFINED_METHOD_P): macro to tell if refined original method is defined. * vm_method.c (remove_method): When remove refined method, raise a NameError if the method is not defined in refined class. But if the method is defined in refined class, it should keep refined method and remove original method. Patch by Seiei Higa. [ruby-core:67722] [Bug #10765] * class.c (method_entry_i, class_instance_method_list, rb_obj_singleton_methods): should not include methods of superclasses if recur is false. [ruby-dev:48854] [Bug #10826] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_1@49992 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
5d3b8d0d54
commit
c4b21f736e
6 changed files with 133 additions and 22 deletions
18
ChangeLog
18
ChangeLog
|
@ -1,3 +1,21 @@
|
|||
Wed Mar 18 00:58:43 2015 Shugo Maeda <shugo@ruby-lang.org>
|
||||
|
||||
* class.c (method_entry_i, class_instance_method_list,
|
||||
rb_obj_singleton_methods): should not include methods of
|
||||
superclasses if recur is false. [ruby-dev:48854] [Bug #10826]
|
||||
|
||||
Wed Mar 18 00:58:43 2015 Shugo Maeda <shugo@ruby-lang.org>
|
||||
|
||||
* vm_method.c (remove_method): When remove refined
|
||||
method, raise a NameError if the method is not
|
||||
defined in refined class.
|
||||
|
||||
But if the method is defined in refined class,
|
||||
it should keep refined method and remove original
|
||||
method.
|
||||
|
||||
Patch by Seiei Higa. [ruby-core:67722] [Bug #10765]
|
||||
|
||||
Wed Mar 18 00:32:08 2015 Seiei Higa <hanachin@gmail.com>
|
||||
|
||||
* vm_method.c (check_definition): Module#public_method_defined?,
|
||||
|
|
38
class.c
38
class.c
|
@ -1116,25 +1116,32 @@ ins_methods_pub_i(st_data_t name, st_data_t type, st_data_t ary)
|
|||
return ins_methods_push((ID)name, (long)type, (VALUE)ary, NOEX_PUBLIC);
|
||||
}
|
||||
|
||||
struct method_entry_arg {
|
||||
st_table *list;
|
||||
int recur;
|
||||
};
|
||||
|
||||
static int
|
||||
method_entry_i(st_data_t key, st_data_t value, st_data_t data)
|
||||
{
|
||||
const rb_method_entry_t *me = (const rb_method_entry_t *)value;
|
||||
st_table *list = (st_table *)data;
|
||||
struct method_entry_arg *arg = (struct method_entry_arg *)data;
|
||||
long type;
|
||||
|
||||
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
VALUE klass = me->klass;
|
||||
me = rb_resolve_refined_method(Qnil, me, NULL);
|
||||
if (!me) return ST_CONTINUE;
|
||||
if (!arg->recur && me->klass != klass) return ST_CONTINUE;
|
||||
}
|
||||
if (!st_lookup(list, key, 0)) {
|
||||
if (!st_lookup(arg->list, key, 0)) {
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||
type = -1; /* none */
|
||||
}
|
||||
else {
|
||||
type = VISI(me->flag);
|
||||
}
|
||||
st_add_direct(list, key, type);
|
||||
st_add_direct(arg->list, key, type);
|
||||
}
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
@ -1144,7 +1151,7 @@ class_instance_method_list(int argc, VALUE *argv, VALUE mod, int obj, int (*func
|
|||
{
|
||||
VALUE ary;
|
||||
int recur, prepended = 0;
|
||||
st_table *list;
|
||||
struct method_entry_arg me_arg;
|
||||
|
||||
if (argc == 0) {
|
||||
recur = TRUE;
|
||||
|
@ -1160,16 +1167,17 @@ class_instance_method_list(int argc, VALUE *argv, VALUE mod, int obj, int (*func
|
|||
prepended = 1;
|
||||
}
|
||||
|
||||
list = st_init_numtable();
|
||||
me_arg.list = st_init_numtable();
|
||||
me_arg.recur = recur;
|
||||
for (; mod; mod = RCLASS_SUPER(mod)) {
|
||||
if (RCLASS_M_TBL(mod)) st_foreach(RCLASS_M_TBL(mod), method_entry_i, (st_data_t)list);
|
||||
if (RCLASS_M_TBL(mod)) st_foreach(RCLASS_M_TBL(mod), method_entry_i, (st_data_t)&me_arg);
|
||||
if (BUILTIN_TYPE(mod) == T_ICLASS && !prepended) continue;
|
||||
if (obj && FL_TEST(mod, FL_SINGLETON)) continue;
|
||||
if (!recur) break;
|
||||
}
|
||||
ary = rb_ary_new();
|
||||
st_foreach(list, func, ary);
|
||||
st_free_table(list);
|
||||
st_foreach(me_arg.list, func, ary);
|
||||
st_free_table(me_arg.list);
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
@ -1391,7 +1399,8 @@ VALUE
|
|||
rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
|
||||
{
|
||||
VALUE recur, ary, klass, origin;
|
||||
st_table *list, *mtbl;
|
||||
struct method_entry_arg me_arg;
|
||||
st_table *mtbl;
|
||||
|
||||
if (argc == 0) {
|
||||
recur = Qtrue;
|
||||
|
@ -1401,22 +1410,23 @@ rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
|
|||
}
|
||||
klass = CLASS_OF(obj);
|
||||
origin = RCLASS_ORIGIN(klass);
|
||||
list = st_init_numtable();
|
||||
me_arg.list = st_init_numtable();
|
||||
me_arg.recur = recur;
|
||||
if (klass && FL_TEST(klass, FL_SINGLETON)) {
|
||||
if ((mtbl = RCLASS_M_TBL(origin)) != 0)
|
||||
st_foreach(mtbl, method_entry_i, (st_data_t)list);
|
||||
st_foreach(mtbl, method_entry_i, (st_data_t)&me_arg);
|
||||
klass = RCLASS_SUPER(klass);
|
||||
}
|
||||
if (RTEST(recur)) {
|
||||
while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) {
|
||||
if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0)
|
||||
st_foreach(mtbl, method_entry_i, (st_data_t)list);
|
||||
st_foreach(mtbl, method_entry_i, (st_data_t)&me_arg);
|
||||
klass = RCLASS_SUPER(klass);
|
||||
}
|
||||
}
|
||||
ary = rb_ary_new();
|
||||
st_foreach(list, ins_methods_i, ary);
|
||||
st_free_table(list);
|
||||
st_foreach(me_arg.list, ins_methods_i, ary);
|
||||
st_free_table(me_arg.list);
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
|
3
method.h
3
method.h
|
@ -108,6 +108,9 @@ struct unlinked_method_entry_list_entry {
|
|||
};
|
||||
|
||||
#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
|
||||
#define UNDEFINED_REFINED_METHOD_P(def) \
|
||||
((def)->type == VM_METHOD_TYPE_REFINED && \
|
||||
UNDEFINED_METHOD_ENTRY_P((def)->body.orig_me))
|
||||
|
||||
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
|
||||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
|
||||
|
|
|
@ -1281,6 +1281,83 @@ class TestRefinement < Test::Unit::TestCase
|
|||
end;
|
||||
end
|
||||
|
||||
def test_remove_refined_method
|
||||
assert_separately([], <<-"end;")
|
||||
bug10765 = '[ruby-core:67722] [Bug #10765]'
|
||||
|
||||
class C
|
||||
def foo
|
||||
"C#foo"
|
||||
end
|
||||
end
|
||||
|
||||
module RefinementBug
|
||||
refine C do
|
||||
def foo
|
||||
"RefinementBug#foo"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
using RefinementBug
|
||||
|
||||
class C
|
||||
remove_method :foo
|
||||
end
|
||||
|
||||
assert_equal("RefinementBug#foo", C.new.foo, bug10765)
|
||||
end;
|
||||
end
|
||||
|
||||
def test_remove_undefined_refined_method
|
||||
assert_separately([], <<-"end;")
|
||||
bug10765 = '[ruby-core:67722] [Bug #10765]'
|
||||
|
||||
class C
|
||||
end
|
||||
|
||||
module RefinementBug
|
||||
refine C do
|
||||
def foo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
using RefinementBug
|
||||
|
||||
assert_raise(NameError, bug10765) {
|
||||
class C
|
||||
remove_method :foo
|
||||
end
|
||||
}
|
||||
end;
|
||||
end
|
||||
|
||||
module NotIncludeSuperclassMethod
|
||||
class X
|
||||
def foo
|
||||
end
|
||||
end
|
||||
|
||||
class Y < X
|
||||
end
|
||||
|
||||
module Bar
|
||||
refine Y do
|
||||
def foo
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_instance_methods_not_include_superclass_method
|
||||
bug10826 = '[ruby-dev:48854] [Bug #10826]'
|
||||
assert_not_include(NotIncludeSuperclassMethod::Y.instance_methods(false),
|
||||
:foo, bug10826)
|
||||
assert_include(NotIncludeSuperclassMethod::Y.instance_methods(true),
|
||||
:foo, bug10826)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def eval_using(mod, s)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#define RUBY_VERSION "2.1.5"
|
||||
#define RUBY_RELEASE_DATE "2015-03-18"
|
||||
#define RUBY_PATCHLEVEL 313
|
||||
#define RUBY_PATCHLEVEL 314
|
||||
|
||||
#define RUBY_RELEASE_YEAR 2015
|
||||
#define RUBY_RELEASE_MONTH 3
|
||||
|
|
17
vm_method.c
17
vm_method.c
|
@ -732,10 +732,12 @@ remove_method(VALUE klass, ID mid)
|
|||
|
||||
if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
|
||||
!(me = (rb_method_entry_t *)data) ||
|
||||
(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
|
||||
(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF) ||
|
||||
UNDEFINED_REFINED_METHOD_P(me->def)) {
|
||||
rb_name_error(mid, "method `%s' not defined in %s",
|
||||
rb_id2name(mid), rb_class2name(klass));
|
||||
}
|
||||
|
||||
key = (st_data_t)mid;
|
||||
st_delete(RCLASS_M_TBL(klass), &key, &data);
|
||||
|
||||
|
@ -743,6 +745,10 @@ remove_method(VALUE klass, ID mid)
|
|||
rb_clear_method_cache_by_class(klass);
|
||||
rb_unlink_method_entry(me);
|
||||
|
||||
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
rb_add_refined_method_entry(klass, mid);
|
||||
}
|
||||
|
||||
CALL_METHOD_HOOK(self, removed, mid);
|
||||
}
|
||||
|
||||
|
@ -812,8 +818,7 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
|
|||
}
|
||||
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me) ||
|
||||
(me->def->type == VM_METHOD_TYPE_REFINED &&
|
||||
UNDEFINED_METHOD_ENTRY_P(me->def->body.orig_me))) {
|
||||
UNDEFINED_REFINED_METHOD_P(me->def)) {
|
||||
rb_print_undef(klass, name, 0);
|
||||
}
|
||||
|
||||
|
@ -912,8 +917,7 @@ rb_undef(VALUE klass, ID id)
|
|||
me = search_method(klass, id, 0);
|
||||
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me) ||
|
||||
(me->def->type == VM_METHOD_TYPE_REFINED &&
|
||||
UNDEFINED_METHOD_ENTRY_P(me->def->body.orig_me))) {
|
||||
UNDEFINED_REFINED_METHOD_P(me->def)) {
|
||||
const char *s0 = " class";
|
||||
VALUE c = klass;
|
||||
|
||||
|
@ -1260,8 +1264,7 @@ rb_alias(VALUE klass, ID name, ID def)
|
|||
orig_me = search_method(klass, def, &defined_class);
|
||||
|
||||
if (UNDEFINED_METHOD_ENTRY_P(orig_me) ||
|
||||
(orig_me->def->type == VM_METHOD_TYPE_REFINED &&
|
||||
UNDEFINED_METHOD_ENTRY_P(orig_me->def->body.orig_me))) {
|
||||
UNDEFINED_REFINED_METHOD_P(orig_me->def)) {
|
||||
if ((!RB_TYPE_P(klass, T_MODULE)) ||
|
||||
(orig_me = search_method(rb_cObject, def, 0),
|
||||
UNDEFINED_METHOD_ENTRY_P(orig_me))) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue