From 94bccc5054f73abdc72ff598482fcf799938f94b Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@ruby-lang.org>
Date: Sun, 1 Apr 2012 08:59:00 +0900
Subject: [PATCH] inherited flag

* vm_method.c (rb_mod_method_defined, check_definition): accept inherited flag.
---
 test/ruby/test_module.rb |   48 ++++++++++++++++++++++---
 vm_method.c              |   90 +++++++++++++++++++++++++++++++++-------------
 2 files changed, 108 insertions(+), 30 deletions(-)

diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index 88b7dd1..e88efe9 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -12,7 +12,7 @@ class TestModule < Test::Unit::TestCase
   def assert_method_defined?(klass, mid, message="")
     message = build_message(message, "#{klass}\##{mid} expected to be defined.")
     _wrap_assertion do
-      klass.method_defined?(mid) or
+      klass.method_defined?(*mid) or
         raise Test::Unit::AssertionFailedError, message, caller(3)
     end
   end
@@ -20,7 +20,7 @@ class TestModule < Test::Unit::TestCase
   def assert_method_not_defined?(klass, mid, message="")
     message = build_message(message, "#{klass}\##{mid} expected to not be defined.")
     _wrap_assertion do
-      klass.method_defined?(mid) and
+      klass.method_defined?(*mid) and
         raise Test::Unit::AssertionFailedError, message, caller(3)
     end
   end
@@ -289,9 +289,9 @@ class TestModule < Test::Unit::TestCase
     assert_method_not_defined?(User, :wombat)
     assert_method_defined?(User, :user)
     assert_method_defined?(User, :mixin)
-    assert_method_not_defined?(User, :wombat)
-    assert_method_defined?(User, :user)
-    assert_method_defined?(User, :mixin)
+    assert_method_not_defined?(User, [:wombat, false])
+    assert_method_defined?(User, [:user, false])
+    assert_method_not_defined?(User, [:mixin, false])
   end
 
   def module_exec_aux
@@ -705,6 +705,44 @@ class TestModule < Test::Unit::TestCase
     assert_equal(false, c.private_method_defined?(:foo))
     assert_equal(false, c.private_method_defined?(:bar))
     assert_equal(true, c.private_method_defined?(:baz))
+
+    c = Class.new(c)
+
+    assert_equal(true, c.public_method_defined?(:foo))
+    assert_equal(false, c.public_method_defined?(:bar))
+    assert_equal(false, c.public_method_defined?(:baz))
+
+    assert_equal(false, c.protected_method_defined?(:foo))
+    assert_equal(true, c.protected_method_defined?(:bar))
+    assert_equal(false, c.protected_method_defined?(:baz))
+
+    assert_equal(false, c.private_method_defined?(:foo))
+    assert_equal(false, c.private_method_defined?(:bar))
+    assert_equal(true, c.private_method_defined?(:baz))
+
+    assert_equal(true, c.public_method_defined?(:foo, true))
+    assert_equal(false, c.public_method_defined?(:bar, true))
+    assert_equal(false, c.public_method_defined?(:baz, true))
+
+    assert_equal(false, c.protected_method_defined?(:foo, true))
+    assert_equal(true, c.protected_method_defined?(:bar, true))
+    assert_equal(false, c.protected_method_defined?(:baz, true))
+
+    assert_equal(false, c.private_method_defined?(:foo, true))
+    assert_equal(false, c.private_method_defined?(:bar, true))
+    assert_equal(true, c.private_method_defined?(:baz, true))
+
+    assert_equal(false, c.public_method_defined?(:foo, false))
+    assert_equal(false, c.public_method_defined?(:bar, false))
+    assert_equal(false, c.public_method_defined?(:baz, false))
+
+    assert_equal(false, c.protected_method_defined?(:foo, false))
+    assert_equal(false, c.protected_method_defined?(:bar, false))
+    assert_equal(false, c.protected_method_defined?(:baz, false))
+
+    assert_equal(false, c.private_method_defined?(:foo, false))
+    assert_equal(false, c.private_method_defined?(:bar, false))
+    assert_equal(false, c.private_method_defined?(:baz, false))
   end
 
   def test_change_visibility_under_safe4
diff --git a/vm_method.c b/vm_method.c
index 9c49007..19f6f09 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -433,6 +433,16 @@ rb_method_entry(VALUE klass, ID id)
     return rb_method_entry_get_without_cache(klass, id);
 }
 
+rb_method_entry_t *
+rb_method_entry_at(VALUE klass, ID id)
+{
+    st_data_t body;
+    if (!klass || !st_lookup(RCLASS_M_TBL(klass), id, &body)) {
+	return 0;
+    }
+    return (rb_method_entry_t *)body;
+}
+
 static void
 remove_method(VALUE klass, ID mid)
 {
@@ -548,11 +558,9 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
     }
 }
 
-int
-rb_method_boundp(VALUE klass, ID id, int ex)
+static int
+method_accessible_p(rb_method_entry_t *me, int ex)
 {
-    rb_method_entry_t *me = rb_method_entry(klass, id);
-
     if (me != 0) {
 	if ((ex & ~NOEX_RESPONDS) &&
 	    ((me->flag & NOEX_PRIVATE) ||
@@ -569,6 +577,27 @@ rb_method_boundp(VALUE klass, ID id, int ex)
     return 0;
 }
 
+int
+rb_method_bound_at(VALUE klass, ID id, int ex)
+{
+    return method_accessible_p(rb_method_entry_at(klass, id), ex);
+}
+
+int
+rb_method_boundp(VALUE klass, ID id, int ex)
+{
+    return method_accessible_p(rb_method_entry(klass, id), ex);
+}
+
+static int
+method_boundp(VALUE klass, ID id, int ex, int inherited)
+{
+    if (inherited)
+	return rb_method_boundp(klass, id, ex);
+    else
+	return rb_method_bound_at(klass, id, ex);
+}
+
 void
 rb_attr(VALUE klass, ID id, int read, int write, int ex)
 {
@@ -745,10 +774,15 @@ rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
  */
 
 static VALUE
-rb_mod_method_defined(VALUE mod, VALUE mid)
+rb_mod_method_defined(int argc, VALUE *argv, VALUE mod)
 {
-    ID id = rb_check_id(&mid);
-    if (!id || !rb_method_boundp(mod, id, 1)) {
+    VALUE mid;
+    ID id;
+
+    rb_check_arity(argc, 1, 2);
+    mid = argv[0];
+    id = rb_check_id(&mid);
+    if (!id || !method_boundp(mod, id, 1, argc == 1 || RTEST(argv[1]))) {
 	return Qfalse;
     }
     return Qtrue;
@@ -758,10 +792,22 @@ rb_mod_method_defined(VALUE mod, VALUE mid)
 #define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f))
 
 static VALUE
-check_definition(VALUE mod, ID mid, rb_method_flag_t noex)
+check_definition(VALUE mod, int argc, VALUE *argv, rb_method_flag_t noex)
 {
     const rb_method_entry_t *me;
-    me = rb_method_entry(mod, mid);
+    VALUE mid;
+    ID id;
+
+    rb_check_arity(argc, 1, 2);
+    mid = argv[0];
+    id = rb_check_id(&mid);
+    if (!id) return Qfalse;
+    if (argc == 1 || RTEST(argv[1])) {
+	me = rb_method_entry(mod, id);
+    }
+    else {
+	me = rb_method_entry_at(mod, id);
+    }
     if (me) {
 	if (VISI_CHECK(me->flag, noex))
 	    return Qtrue;
@@ -796,11 +842,9 @@ check_definition(VALUE mod, ID mid, rb_method_flag_t noex)
  */
 
 static VALUE
-rb_mod_public_method_defined(VALUE mod, VALUE mid)
+rb_mod_public_method_defined(int argc, VALUE *argv, VALUE mod)
 {
-    ID id = rb_check_id(&mid);
-    if (!id) return Qfalse;
-    return check_definition(mod, id, NOEX_PUBLIC);
+    return check_definition(mod, argc, argv, NOEX_PUBLIC);
 }
 
 /*
@@ -830,11 +874,9 @@ rb_mod_public_method_defined(VALUE mod, VALUE mid)
  */
 
 static VALUE
-rb_mod_private_method_defined(VALUE mod, VALUE mid)
+rb_mod_private_method_defined(int argc, VALUE *argv, VALUE mod)
 {
-    ID id = rb_check_id(&mid);
-    if (!id) return Qfalse;
-    return check_definition(mod, id, NOEX_PRIVATE);
+    return check_definition(mod, argc, argv, NOEX_PRIVATE);
 }
 
 /*
@@ -864,11 +906,9 @@ rb_mod_private_method_defined(VALUE mod, VALUE mid)
  */
 
 static VALUE
-rb_mod_protected_method_defined(VALUE mod, VALUE mid)
+rb_mod_protected_method_defined(int argc, VALUE *argv, VALUE mod)
 {
-    ID id = rb_check_id(&mid);
-    if (!id) return Qfalse;
-    return check_definition(mod, id, NOEX_PROTECTED);
+    return check_definition(mod, argc, argv, NOEX_PROTECTED);
 }
 
 int
@@ -1374,10 +1414,10 @@ Init_eval_method(void)
     rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
     rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
 
-    rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
-    rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
-    rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
-    rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
+    rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, -1);
+    rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, -1);
+    rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, -1);
+    rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, -1);
     rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
     rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
 
-- 
1.7.9

