summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-02-25 06:01:25 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-02-25 06:01:25 +0000
commit94ec0a64197ab7a0edfb6599074df0a2920607e4 (patch)
tree687082f0a7811e404327e0ce8dac4b1f60621b7c
parent24bb5756b1e61279c0be437c10210ad26e951ffd (diff)
merge revision(s) 49222,49480,49493: [Backport #10765] [Backport #1010826]
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_0_0@49738 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog18
-rw-r--r--class.c45
-rw-r--r--method.h3
-rw-r--r--test/ruby/test_refinement.rb79
-rw-r--r--version.h2
-rw-r--r--vm_method.c17
6 files changed, 139 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index c1742fd2d2..a59ebd3a8e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Wed Feb 25 14:53:27 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 Feb 25 14:53:27 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 Feb 25 14:41:01 2015 Seiei Higa <hanachin@gmail.com>
* vm_method.c (check_definition): Module#public_method_defined?,
diff --git a/class.c b/class.c
index 384037b2b7..9da8fe76a3 100644
--- a/class.c
+++ b/class.c
@@ -986,25 +986,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;
}
@@ -1014,7 +1021,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;
@@ -1030,16 +1037,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;
}
@@ -1251,8 +1259,9 @@ rb_obj_public_methods(int argc, VALUE *argv, VALUE obj)
VALUE
rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
{
- VALUE recur, ary, klass;
- st_table *list;
+ VALUE recur, ary, klass, origin;
+ struct method_entry_arg me_arg;
+ st_table *mtbl;
if (argc == 0) {
recur = Qtrue;
@@ -1261,22 +1270,24 @@ rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
rb_scan_args(argc, argv, "01", &recur);
}
klass = CLASS_OF(obj);
- list = st_init_numtable();
+ origin = RCLASS_ORIGIN(klass);
+ me_arg.list = st_init_numtable();
+ me_arg.recur = RTEST(recur);
if (klass && FL_TEST(klass, FL_SINGLETON)) {
- if (RCLASS_M_TBL(klass))
- st_foreach(RCLASS_M_TBL(klass), method_entry_i, (st_data_t)list);
+ if ((mtbl = RCLASS_M_TBL(origin)) != 0)
+ 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 (RCLASS_M_TBL(klass))
- st_foreach(RCLASS_M_TBL(klass), method_entry_i, (st_data_t)list);
+ if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0)
+ 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;
}
diff --git a/method.h b/method.h
index f2f519679e..7d03b99c96 100644
--- a/method.h
+++ b/method.h
@@ -106,6 +106,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);
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index b390e65ccc..a9b20a1f65 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -1120,6 +1120,85 @@ class TestRefinement < Test::Unit::TestCase
end;
end
+ def test_remove_refined_method
+ assert_separately([], <<-"end;")
+ $VERBOSE = nil
+ 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;")
+ $VERBOSE = nil
+ 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)
diff --git a/version.h b/version.h
index 3bbe2258b5..d4b41b29f1 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.0.0"
#define RUBY_RELEASE_DATE "2015-02-25"
-#define RUBY_PATCHLEVEL 640
+#define RUBY_PATCHLEVEL 641
#define RUBY_RELEASE_YEAR 2015
#define RUBY_RELEASE_MONTH 2
diff --git a/vm_method.c b/vm_method.c
index b836d1ddde..6982e58760 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -690,10 +690,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);
@@ -701,6 +703,10 @@ remove_method(VALUE klass, ID mid)
rb_clear_cache_for_undef(klass, mid);
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);
}
@@ -772,8 +778,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);
}
@@ -881,8 +886,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;
@@ -1222,8 +1226,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))) {