Skip to content

Commit 58dc8bf

Browse files
committed
Fix {Method,UnboundMethod}#{public?,private?,protected?} for ZSUPER methods
Add a visibility member to struct METHOD storing the original method visibility, and use that, instead of taking the visibility from the stored method entry (which may have different visibility for ZSUPER methods). Consider Method/UnboundMethod objects different if they have different visibilities. Fixes [Bug #18435]
1 parent a93cc3e commit 58dc8bf

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

proc.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct METHOD {
4040
const VALUE iclass;
4141
const rb_method_entry_t * const me;
4242
/* for bound methods, `me' should be rb_callable_method_entry_t * */
43+
rb_method_visibility_t visibility;
4344
};
4445

4546
VALUE rb_cUnboundMethod;
@@ -1626,6 +1627,7 @@ mnew_missing(VALUE klass, VALUE obj, ID id, VALUE mclass)
16261627
me = rb_method_entry_create(id, klass, METHOD_VISI_UNDEF, def);
16271628

16281629
RB_OBJ_WRITE(method, &data->me, me);
1630+
data->visibility = METHOD_ENTRY_VISI(me);
16291631

16301632
return method;
16311633
}
@@ -1683,6 +1685,7 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
16831685
RB_OBJ_WRITE(method, &data->klass, klass);
16841686
RB_OBJ_WRITE(method, &data->iclass, iclass);
16851687
RB_OBJ_WRITE(method, &data->me, me);
1688+
data->visibility = visi;
16861689

16871690
return method;
16881691
}
@@ -1780,6 +1783,7 @@ method_eq(VALUE method, VALUE other)
17801783

17811784
if (!rb_method_entry_eq(m1->me, m2->me) ||
17821785
klass1 != klass2 ||
1786+
m1->visibility != m2->visibility ||
17831787
m1->klass != m2->klass ||
17841788
m1->recv != m2->recv) {
17851789
return Qfalse;
@@ -1833,6 +1837,7 @@ method_unbind(VALUE obj)
18331837
RB_OBJ_WRITE(method, &data->klass, orig->klass);
18341838
RB_OBJ_WRITE(method, &data->iclass, orig->iclass);
18351839
RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
1840+
data->visibility = orig->visibility;
18361841

18371842
return method;
18381843
}
@@ -2340,6 +2345,7 @@ method_clone(VALUE self)
23402345
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
23412346
RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
23422347
RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
2348+
data->visibility = orig->visibility;
23432349
return clone;
23442350
}
23452351

@@ -2590,6 +2596,7 @@ umethod_bind(VALUE method, VALUE recv)
25902596
RB_OBJ_WRITE(method, &bound->klass, klass);
25912597
RB_OBJ_WRITE(method, &bound->iclass, iclass);
25922598
RB_OBJ_WRITE(method, &bound->me, me);
2599+
bound->visibility = data->visibility;
25932600

25942601
return method;
25952602
}
@@ -2625,7 +2632,7 @@ umethod_bind_call(int argc, VALUE *argv, VALUE method)
26252632
VALUE methclass, klass, iclass;
26262633
const rb_method_entry_t *me;
26272634
convert_umethod_to_method_components(data, recv, &methclass, &klass, &iclass, &me);
2628-
struct METHOD bound = { recv, klass, 0, me };
2635+
struct METHOD bound = { recv, klass, 0, me, METHOD_ENTRY_VISI(me) };
26292636

26302637
return call_method_data(ec, &bound, argc, argv, passed_procval, RB_PASS_CALLED_KEYWORDS);
26312638
}
@@ -3314,7 +3321,7 @@ method_public_p(VALUE method)
33143321
{
33153322
const struct METHOD *data;
33163323
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
3317-
return RBOOL(METHOD_ENTRY_VISI(data->me) == METHOD_VISI_PUBLIC);
3324+
return RBOOL(data->visibility == METHOD_VISI_PUBLIC);
33183325
}
33193326

33203327
/*
@@ -3329,7 +3336,7 @@ method_protected_p(VALUE method)
33293336
{
33303337
const struct METHOD *data;
33313338
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
3332-
return RBOOL(METHOD_ENTRY_VISI(data->me) == METHOD_VISI_PROTECTED);
3339+
return RBOOL(data->visibility == METHOD_VISI_PROTECTED);
33333340
}
33343341

33353342
/*
@@ -3344,7 +3351,7 @@ method_private_p(VALUE method)
33443351
{
33453352
const struct METHOD *data;
33463353
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
3347-
return RBOOL(METHOD_ENTRY_VISI(data->me) == METHOD_VISI_PRIVATE);
3354+
return RBOOL(data->visibility == METHOD_VISI_PRIVATE);
33483355
}
33493356

33503357
/*

test/ruby/test_method.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,11 @@ def m.foo; end
199199
assert_equal(o.method(:foo), o.method(:foo))
200200
assert_equal(o.method(:foo), o.method(:bar))
201201
assert_not_equal(o.method(:foo), o.method(:baz))
202+
203+
class << o
204+
private :bar
205+
end
206+
assert_not_equal(o.method(:foo), o.method(:bar))
202207
end
203208

204209
def test_hash
@@ -1200,6 +1205,31 @@ def test_unbound_method_visibility_predicates
12001205
assert_equal(false, Visibility.instance_method(:mv1).protected?)
12011206
end
12021207

1208+
class VisibilitySub < Visibility
1209+
protected :mv1
1210+
public :mv2
1211+
private :mv3
1212+
end
1213+
1214+
def test_method_visibility_predicates_with_subclass_visbility_change
1215+
v = VisibilitySub.new
1216+
assert_equal(false, v.method(:mv1).public?)
1217+
assert_equal(false, v.method(:mv2).private?)
1218+
assert_equal(false, v.method(:mv3).protected?)
1219+
assert_equal(true, v.method(:mv2).public?)
1220+
assert_equal(true, v.method(:mv3).private?)
1221+
assert_equal(true, v.method(:mv1).protected?)
1222+
end
1223+
1224+
def test_unbound_method_visibility_predicates_with_subclass_visbility_change
1225+
assert_equal(false, VisibilitySub.instance_method(:mv1).public?)
1226+
assert_equal(false, VisibilitySub.instance_method(:mv2).private?)
1227+
assert_equal(false, VisibilitySub.instance_method(:mv3).protected?)
1228+
assert_equal(true, VisibilitySub.instance_method(:mv2).public?)
1229+
assert_equal(true, VisibilitySub.instance_method(:mv3).private?)
1230+
assert_equal(true, VisibilitySub.instance_method(:mv1).protected?)
1231+
end
1232+
12031233
def rest_parameter(*rest)
12041234
rest
12051235
end

0 commit comments

Comments
 (0)