void rb_alias(VALUE klass, ID name, ID def) { NODE *orig_fbody, *node, *method; VALUE singleton = 0; st_data_t data; rb_frozen_class_p(klass); if (klass == rb_cObject) { rb_secure(4); } orig_fbody = search_method(klass, def, 0); if (!orig_fbody || !orig_fbody->nd_body) { if (TYPE(klass) == T_MODULE) { orig_fbody = search_method(rb_cObject, def, 0); } } if (!orig_fbody || !orig_fbody->nd_body) { rb_print_undef(klass, def, 0); } if (FL_TEST(klass, FL_SINGLETON)) { singleton = rb_iv_get(klass, "__attached__"); } orig_fbody->nd_cnt++; if (st_lookup(RCLASS_M_TBL(klass), name, &data)) { node = (NODE *)data; if (node) { if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) { rb_warning("discarding old %s", rb_id2name(name)); } if (nd_type(node->nd_body->nd_body) == NODE_CFUNC) { rb_vm_check_redefinition_opt_method(node); } } } st_insert(RCLASS_M_TBL(klass), name, (st_data_t) NEW_FBODY( method = NEW_METHOD(orig_fbody->nd_body->nd_body, orig_fbody->nd_body->nd_clss, NOEX_WITH_SAFE(orig_fbody->nd_body->nd_noex)), def)); method->nd_file = (void *)def; rb_clear_cache_by_id(name); if (!ruby_running) return; if (singleton) { rb_funcall(singleton, singleton_added, 1, ID2SYM(name)); } else { rb_funcall(klass, added, 1, ID2SYM(name)); } }
static int clone_method(ID mid, NODE *body, struct clone_method_data *data) { if (body == 0) { st_insert(data->tbl, mid, 0); } else { st_insert(data->tbl, mid, (st_data_t) NEW_FBODY( NEW_METHOD(body->nd_body->nd_body, data->klass, /* TODO */ body->nd_body->nd_noex), 0)); } return ST_CONTINUE; }
void rb_add_method(VALUE klass, ID mid, NODE * node, int noex) { NODE *body; if (NIL_P(klass)) { klass = rb_cObject; } if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) { rb_raise(rb_eSecurityError, "Insecure: can't define method"); } if (!FL_TEST(klass, FL_SINGLETON) && node && nd_type(node) != NODE_ZSUPER && (mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) { noex = NOEX_PRIVATE | noex; } else if (FL_TEST(klass, FL_SINGLETON) && node && nd_type(node) == NODE_CFUNC && mid == rb_intern("allocate")) { rb_warn ("defining %s.allocate is deprecated; use rb_define_alloc_func()", rb_class2name(rb_iv_get(klass, "__attached__"))); mid = ID_ALLOCATOR; } if (OBJ_FROZEN(klass)) { rb_error_frozen("class/module"); } rb_clear_cache_by_id(mid); /* * NODE_METHOD (NEW_METHOD(body, klass, vis)): * nd_body : method body // (2) // mark * nd_clss : klass // (1) // mark * nd_noex : visibility // (3) * * NODE_FBODY (NEW_FBODY(method, alias)): * nd_body : method (NODE_METHOD) // (2) // mark * nd_oid : original id // (1) * nd_cnt : alias count // (3) */ if (node) { body = NEW_FBODY(NEW_METHOD(node, klass, NOEX_WITH_SAFE(noex)), 0); } else { body = 0; } { /* check re-definition */ st_data_t data; NODE *old_node; if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) { old_node = (NODE *)data; if (old_node) { if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) { rb_vm_check_redefinition_opt_method(old_node); } if (RTEST(ruby_verbose) && node && old_node->nd_cnt == 0 && old_node->nd_body) { rb_warning("method redefined; discarding old %s", rb_id2name(mid)); } } } if (klass == rb_cObject && node && mid == idInitialize) { rb_warn("redefining Object#initialize may cause infinite loop"); } if (mid == object_id || mid == __send__) { if (node && nd_type(node) == RUBY_VM_METHOD_NODE) { rb_warn("redefining `%s' may cause serious problem", rb_id2name(mid)); } } } st_insert(RCLASS_M_TBL(klass), mid, (st_data_t) body); if (node && mid != ID_ALLOCATOR && ruby_running) { if (FL_TEST(klass, FL_SINGLETON)) { rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1, ID2SYM(mid)); } else { rb_funcall(klass, added, 1, ID2SYM(mid)); } } }