Skip to content

Commit c4b21f7

Browse files
committed
merge revision(s) r49222,r49480,r49493: [Backport ruby#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 ruby#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 ruby#10826] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_1@49992 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 5d3b8d0 commit c4b21f7

File tree

6 files changed

+133
-22
lines changed

6 files changed

+133
-22
lines changed

ChangeLog

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
Wed Mar 18 00:58:43 2015 Shugo Maeda <[email protected]>
2+
3+
* class.c (method_entry_i, class_instance_method_list,
4+
rb_obj_singleton_methods): should not include methods of
5+
superclasses if recur is false. [ruby-dev:48854] [Bug #10826]
6+
7+
Wed Mar 18 00:58:43 2015 Shugo Maeda <[email protected]>
8+
9+
* vm_method.c (remove_method): When remove refined
10+
method, raise a NameError if the method is not
11+
defined in refined class.
12+
13+
But if the method is defined in refined class,
14+
it should keep refined method and remove original
15+
method.
16+
17+
Patch by Seiei Higa. [ruby-core:67722] [Bug #10765]
18+
119
Wed Mar 18 00:32:08 2015 Seiei Higa <[email protected]>
220

321
* vm_method.c (check_definition): Module#public_method_defined?,

class.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,25 +1116,32 @@ ins_methods_pub_i(st_data_t name, st_data_t type, st_data_t ary)
11161116
return ins_methods_push((ID)name, (long)type, (VALUE)ary, NOEX_PUBLIC);
11171117
}
11181118

1119+
struct method_entry_arg {
1120+
st_table *list;
1121+
int recur;
1122+
};
1123+
11191124
static int
11201125
method_entry_i(st_data_t key, st_data_t value, st_data_t data)
11211126
{
11221127
const rb_method_entry_t *me = (const rb_method_entry_t *)value;
1123-
st_table *list = (st_table *)data;
1128+
struct method_entry_arg *arg = (struct method_entry_arg *)data;
11241129
long type;
11251130

11261131
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
1132+
VALUE klass = me->klass;
11271133
me = rb_resolve_refined_method(Qnil, me, NULL);
11281134
if (!me) return ST_CONTINUE;
1135+
if (!arg->recur && me->klass != klass) return ST_CONTINUE;
11291136
}
1130-
if (!st_lookup(list, key, 0)) {
1137+
if (!st_lookup(arg->list, key, 0)) {
11311138
if (UNDEFINED_METHOD_ENTRY_P(me)) {
11321139
type = -1; /* none */
11331140
}
11341141
else {
11351142
type = VISI(me->flag);
11361143
}
1137-
st_add_direct(list, key, type);
1144+
st_add_direct(arg->list, key, type);
11381145
}
11391146
return ST_CONTINUE;
11401147
}
@@ -1144,7 +1151,7 @@ class_instance_method_list(int argc, VALUE *argv, VALUE mod, int obj, int (*func
11441151
{
11451152
VALUE ary;
11461153
int recur, prepended = 0;
1147-
st_table *list;
1154+
struct method_entry_arg me_arg;
11481155

11491156
if (argc == 0) {
11501157
recur = TRUE;
@@ -1160,16 +1167,17 @@ class_instance_method_list(int argc, VALUE *argv, VALUE mod, int obj, int (*func
11601167
prepended = 1;
11611168
}
11621169

1163-
list = st_init_numtable();
1170+
me_arg.list = st_init_numtable();
1171+
me_arg.recur = recur;
11641172
for (; mod; mod = RCLASS_SUPER(mod)) {
1165-
if (RCLASS_M_TBL(mod)) st_foreach(RCLASS_M_TBL(mod), method_entry_i, (st_data_t)list);
1173+
if (RCLASS_M_TBL(mod)) st_foreach(RCLASS_M_TBL(mod), method_entry_i, (st_data_t)&me_arg);
11661174
if (BUILTIN_TYPE(mod) == T_ICLASS && !prepended) continue;
11671175
if (obj && FL_TEST(mod, FL_SINGLETON)) continue;
11681176
if (!recur) break;
11691177
}
11701178
ary = rb_ary_new();
1171-
st_foreach(list, func, ary);
1172-
st_free_table(list);
1179+
st_foreach(me_arg.list, func, ary);
1180+
st_free_table(me_arg.list);
11731181

11741182
return ary;
11751183
}
@@ -1391,7 +1399,8 @@ VALUE
13911399
rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
13921400
{
13931401
VALUE recur, ary, klass, origin;
1394-
st_table *list, *mtbl;
1402+
struct method_entry_arg me_arg;
1403+
st_table *mtbl;
13951404

13961405
if (argc == 0) {
13971406
recur = Qtrue;
@@ -1401,22 +1410,23 @@ rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
14011410
}
14021411
klass = CLASS_OF(obj);
14031412
origin = RCLASS_ORIGIN(klass);
1404-
list = st_init_numtable();
1413+
me_arg.list = st_init_numtable();
1414+
me_arg.recur = recur;
14051415
if (klass && FL_TEST(klass, FL_SINGLETON)) {
14061416
if ((mtbl = RCLASS_M_TBL(origin)) != 0)
1407-
st_foreach(mtbl, method_entry_i, (st_data_t)list);
1417+
st_foreach(mtbl, method_entry_i, (st_data_t)&me_arg);
14081418
klass = RCLASS_SUPER(klass);
14091419
}
14101420
if (RTEST(recur)) {
14111421
while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) {
14121422
if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0)
1413-
st_foreach(mtbl, method_entry_i, (st_data_t)list);
1423+
st_foreach(mtbl, method_entry_i, (st_data_t)&me_arg);
14141424
klass = RCLASS_SUPER(klass);
14151425
}
14161426
}
14171427
ary = rb_ary_new();
1418-
st_foreach(list, ins_methods_i, ary);
1419-
st_free_table(list);
1428+
st_foreach(me_arg.list, ins_methods_i, ary);
1429+
st_free_table(me_arg.list);
14201430

14211431
return ary;
14221432
}

method.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ struct unlinked_method_entry_list_entry {
108108
};
109109

110110
#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
111+
#define UNDEFINED_REFINED_METHOD_P(def) \
112+
((def)->type == VM_METHOD_TYPE_REFINED && \
113+
UNDEFINED_METHOD_ENTRY_P((def)->body.orig_me))
111114

112115
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
113116
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);

test/ruby/test_refinement.rb

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,83 @@ def undefined_refined_private; end
12811281
end;
12821282
end
12831283

1284+
def test_remove_refined_method
1285+
assert_separately([], <<-"end;")
1286+
bug10765 = '[ruby-core:67722] [Bug #10765]'
1287+
1288+
class C
1289+
def foo
1290+
"C#foo"
1291+
end
1292+
end
1293+
1294+
module RefinementBug
1295+
refine C do
1296+
def foo
1297+
"RefinementBug#foo"
1298+
end
1299+
end
1300+
end
1301+
1302+
using RefinementBug
1303+
1304+
class C
1305+
remove_method :foo
1306+
end
1307+
1308+
assert_equal("RefinementBug#foo", C.new.foo, bug10765)
1309+
end;
1310+
end
1311+
1312+
def test_remove_undefined_refined_method
1313+
assert_separately([], <<-"end;")
1314+
bug10765 = '[ruby-core:67722] [Bug #10765]'
1315+
1316+
class C
1317+
end
1318+
1319+
module RefinementBug
1320+
refine C do
1321+
def foo
1322+
end
1323+
end
1324+
end
1325+
1326+
using RefinementBug
1327+
1328+
assert_raise(NameError, bug10765) {
1329+
class C
1330+
remove_method :foo
1331+
end
1332+
}
1333+
end;
1334+
end
1335+
1336+
module NotIncludeSuperclassMethod
1337+
class X
1338+
def foo
1339+
end
1340+
end
1341+
1342+
class Y < X
1343+
end
1344+
1345+
module Bar
1346+
refine Y do
1347+
def foo
1348+
end
1349+
end
1350+
end
1351+
end
1352+
1353+
def test_instance_methods_not_include_superclass_method
1354+
bug10826 = '[ruby-dev:48854] [Bug #10826]'
1355+
assert_not_include(NotIncludeSuperclassMethod::Y.instance_methods(false),
1356+
:foo, bug10826)
1357+
assert_include(NotIncludeSuperclassMethod::Y.instance_methods(true),
1358+
:foo, bug10826)
1359+
end
1360+
12841361
private
12851362

12861363
def eval_using(mod, s)

version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#define RUBY_VERSION "2.1.5"
22
#define RUBY_RELEASE_DATE "2015-03-18"
3-
#define RUBY_PATCHLEVEL 313
3+
#define RUBY_PATCHLEVEL 314
44

55
#define RUBY_RELEASE_YEAR 2015
66
#define RUBY_RELEASE_MONTH 3

vm_method.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -732,17 +732,23 @@ remove_method(VALUE klass, ID mid)
732732

733733
if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
734734
!(me = (rb_method_entry_t *)data) ||
735-
(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
735+
(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF) ||
736+
UNDEFINED_REFINED_METHOD_P(me->def)) {
736737
rb_name_error(mid, "method `%s' not defined in %s",
737738
rb_id2name(mid), rb_class2name(klass));
738739
}
740+
739741
key = (st_data_t)mid;
740742
st_delete(RCLASS_M_TBL(klass), &key, &data);
741743

742744
rb_vm_check_redefinition_opt_method(me, klass);
743745
rb_clear_method_cache_by_class(klass);
744746
rb_unlink_method_entry(me);
745747

748+
if (me->def->type == VM_METHOD_TYPE_REFINED) {
749+
rb_add_refined_method_entry(klass, mid);
750+
}
751+
746752
CALL_METHOD_HOOK(self, removed, mid);
747753
}
748754

@@ -812,8 +818,7 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
812818
}
813819

814820
if (UNDEFINED_METHOD_ENTRY_P(me) ||
815-
(me->def->type == VM_METHOD_TYPE_REFINED &&
816-
UNDEFINED_METHOD_ENTRY_P(me->def->body.orig_me))) {
821+
UNDEFINED_REFINED_METHOD_P(me->def)) {
817822
rb_print_undef(klass, name, 0);
818823
}
819824

@@ -912,8 +917,7 @@ rb_undef(VALUE klass, ID id)
912917
me = search_method(klass, id, 0);
913918

914919
if (UNDEFINED_METHOD_ENTRY_P(me) ||
915-
(me->def->type == VM_METHOD_TYPE_REFINED &&
916-
UNDEFINED_METHOD_ENTRY_P(me->def->body.orig_me))) {
920+
UNDEFINED_REFINED_METHOD_P(me->def)) {
917921
const char *s0 = " class";
918922
VALUE c = klass;
919923

@@ -1260,8 +1264,7 @@ rb_alias(VALUE klass, ID name, ID def)
12601264
orig_me = search_method(klass, def, &defined_class);
12611265

12621266
if (UNDEFINED_METHOD_ENTRY_P(orig_me) ||
1263-
(orig_me->def->type == VM_METHOD_TYPE_REFINED &&
1264-
UNDEFINED_METHOD_ENTRY_P(orig_me->def->body.orig_me))) {
1267+
UNDEFINED_REFINED_METHOD_P(orig_me->def)) {
12651268
if ((!RB_TYPE_P(klass, T_MODULE)) ||
12661269
(orig_me = search_method(rb_cObject, def, 0),
12671270
UNDEFINED_METHOD_ENTRY_P(orig_me))) {

0 commit comments

Comments
 (0)