[前][次][番号順一覧][スレッド一覧]

ruby-changes:37911

From: nagachika <ko1@a...>
Date: Wed, 18 Mar 2015 01:12:49 +0900 (JST)
Subject: [ruby-changes:37911] nagachika:r49992 (ruby_2_1): merge revision(s) r49222, r49480, r49493: [Backport #10765]

nagachika	2015-03-18 01:12:28 +0900 (Wed, 18 Mar 2015)

  New Revision: 49992

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=49992

  Log:
    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]

  Modified directories:
    branches/ruby_2_1/
  Modified files:
    branches/ruby_2_1/ChangeLog
    branches/ruby_2_1/class.c
    branches/ruby_2_1/method.h
    branches/ruby_2_1/test/ruby/test_refinement.rb
    branches/ruby_2_1/version.h
    branches/ruby_2_1/vm_method.c
Index: ruby_2_1/method.h
===================================================================
--- ruby_2_1/method.h	(revision 49991)
+++ ruby_2_1/method.h	(revision 49992)
@@ -108,6 +108,9 @@ struct unlinked_method_entry_list_entry https://github.com/ruby/ruby/blob/trunk/ruby_2_1/method.h#L108
 };
 
 #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);
Index: ruby_2_1/ChangeLog
===================================================================
--- ruby_2_1/ChangeLog	(revision 49991)
+++ ruby_2_1/ChangeLog	(revision 49992)
@@ -1,3 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_1/ChangeLog#L1
+Wed Mar 18 00:58:43 2015  Shugo Maeda  <shugo@r...>
+
+	* 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@r...>
+
+	* 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@g...>
 
 	* vm_method.c (check_definition): Module#public_method_defined?,
Index: ruby_2_1/vm_method.c
===================================================================
--- ruby_2_1/vm_method.c	(revision 49991)
+++ ruby_2_1/vm_method.c	(revision 49992)
@@ -732,10 +732,12 @@ remove_method(VALUE klass, ID mid) https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L732
 
     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) https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L745
     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, r https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L818
     }
 
     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) https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L917
     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) https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L1264
     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))) {
Index: ruby_2_1/class.c
===================================================================
--- ruby_2_1/class.c	(revision 49991)
+++ ruby_2_1/class.c	(revision 49992)
@@ -1116,25 +1116,32 @@ ins_methods_pub_i(st_data_t name, st_dat https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1116
     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, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1151
 {
     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, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1167
 	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 https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1399
 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 https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1410
     }
     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;
 }
Index: ruby_2_1/version.h
===================================================================
--- ruby_2_1/version.h	(revision 49991)
+++ ruby_2_1/version.h	(revision 49992)
@@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_1/version.h#L1
 #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
Index: ruby_2_1/test/ruby/test_refinement.rb
===================================================================
--- ruby_2_1/test/ruby/test_refinement.rb	(revision 49991)
+++ ruby_2_1/test/ruby/test_refinement.rb	(revision 49992)
@@ -1281,6 +1281,83 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/ruby_2_1/test/ruby/test_refinement.rb#L1281
     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)

Property changes on: ruby_2_1
___________________________________________________________________
Modified: svn:mergeinfo
   Merged /trunk:r49222,49480,49493


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]