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

ruby-changes:37657

From: usa <ko1@a...>
Date: Wed, 25 Feb 2015 15:01:41 +0900 (JST)
Subject: [ruby-changes:37657] usa:r49738 (ruby_2_0_0): merge revision(s) 49222,49480,49493: [Backport #10765] [Backport #1010826]

usa	2015-02-25 15:01:25 +0900 (Wed, 25 Feb 2015)

  New Revision: 49738

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

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

  Modified directories:
    branches/ruby_2_0_0/
  Modified files:
    branches/ruby_2_0_0/ChangeLog
    branches/ruby_2_0_0/class.c
    branches/ruby_2_0_0/method.h
    branches/ruby_2_0_0/test/ruby/test_refinement.rb
    branches/ruby_2_0_0/version.h
    branches/ruby_2_0_0/vm_method.c
Index: ruby_2_0_0/method.h
===================================================================
--- ruby_2_0_0/method.h	(revision 49737)
+++ ruby_2_0_0/method.h	(revision 49738)
@@ -106,6 +106,9 @@ struct unlinked_method_entry_list_entry https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/method.h#L106
 };
 
 #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_0_0/ChangeLog
===================================================================
--- ruby_2_0_0/ChangeLog	(revision 49737)
+++ ruby_2_0_0/ChangeLog	(revision 49738)
@@ -1,3 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/ChangeLog#L1
+Wed Feb 25 14:53:27 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 Feb 25 14:53:27 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 Feb 25 14:41:01 2015  Seiei Higa  <hanachin@g...>
 
 	* vm_method.c (check_definition): Module#public_method_defined?,
Index: ruby_2_0_0/vm_method.c
===================================================================
--- ruby_2_0_0/vm_method.c	(revision 49737)
+++ ruby_2_0_0/vm_method.c	(revision 49738)
@@ -690,10 +690,12 @@ remove_method(VALUE klass, ID mid) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L690
 
     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) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L703
     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, r https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L778
     }
 
     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) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L886
     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) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L1226
     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_0_0/class.c
===================================================================
--- ruby_2_0_0/class.c	(revision 49737)
+++ ruby_2_0_0/class.c	(revision 49738)
@@ -986,25 +986,32 @@ ins_methods_pub_i(st_data_t name, st_dat https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L986
     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, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L1021
 {
     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, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L1037
 	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 *a https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L1259
 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 https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L1270
 	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;
 }
Index: ruby_2_0_0/version.h
===================================================================
--- ruby_2_0_0/version.h	(revision 49737)
+++ ruby_2_0_0/version.h	(revision 49738)
@@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/version.h#L1
 #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
Index: ruby_2_0_0/test/ruby/test_refinement.rb
===================================================================
--- ruby_2_0_0/test/ruby/test_refinement.rb	(revision 49737)
+++ ruby_2_0_0/test/ruby/test_refinement.rb	(revision 49738)
@@ -1120,6 +1120,85 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/test/ruby/test_refinement.rb#L1120
     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)

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


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

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