1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

NoMethodError#private_call?

* error.c (nometh_err_initialize): add private_call? parameter.
* error.c (nometh_err_private_call_p): add private_call? method,
  to tell if the exception raised in private form FCALL or VCALL.
  [Feature #12043]
* vm_eval.c (make_no_method_exception): append private_call?
  argument.
* vm_insnhelper.c (ci_missing_reason): copy FCALL flag.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53961 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2016-02-28 04:41:38 +00:00
parent 74e5e61849
commit 4d9f5482ae
7 changed files with 67 additions and 10 deletions

View file

@ -1,3 +1,16 @@
Sun Feb 28 13:40:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* error.c (nometh_err_initialize): add private_call? parameter.
* error.c (nometh_err_private_call_p): add private_call? method,
to tell if the exception raised in private form FCALL or VCALL.
[Feature #12043]
* vm_eval.c (make_no_method_exception): append private_call?
argument.
* vm_insnhelper.c (ci_missing_reason): copy FCALL flag.
Sun Feb 28 10:19:47 2016 Ryan T. Hosford <tad.hosford@gmail.com>
* array.c (rb_ary_and): clarify that set intersection returns the

11
error.c
View file

@ -697,6 +697,7 @@ static VALUE rb_eNOERROR;
static ID id_new, id_cause, id_message, id_backtrace;
static ID id_name, id_args, id_Errno, id_errno, id_i_path;
static ID id_receiver, id_iseq, id_local_variables;
static ID id_private_call_p;
extern ID ruby_static_id_status;
#define id_bt idBt
#define id_bt_locations idBt_locations
@ -1203,9 +1204,11 @@ name_err_local_variables(VALUE self)
static VALUE
nometh_err_initialize(int argc, VALUE *argv, VALUE self)
{
VALUE priv = (argc > 3) && (--argc, RTEST(argv[argc])) ? Qtrue : Qfalse;
VALUE args = (argc > 2) ? argv[--argc] : Qnil;
name_err_initialize(argc, argv, self);
rb_ivar_set(self, id_args, args);
rb_ivar_set(self, id_private_call_p, RTEST(priv) ? Qtrue : Qfalse);
return self;
}
@ -1392,6 +1395,12 @@ nometh_err_args(VALUE self)
return rb_attr_get(self, id_args);
}
static VALUE
nometh_err_private_call_p(VALUE self)
{
return rb_attr_get(self, id_private_call_p);
}
void
rb_invalid_str(const char *str, const char *type)
{
@ -2019,6 +2028,7 @@ Init_Exception(void)
rb_eNoMethodError = rb_define_class("NoMethodError", rb_eNameError);
rb_define_method(rb_eNoMethodError, "initialize", nometh_err_initialize, -1);
rb_define_method(rb_eNoMethodError, "args", nometh_err_args, 0);
rb_define_method(rb_eNoMethodError, "private_call?", nometh_err_private_call_p, 0);
rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError);
rb_eSecurityError = rb_define_class("SecurityError", rb_eException);
@ -2043,6 +2053,7 @@ Init_Exception(void)
id_name = rb_intern_const("name");
id_args = rb_intern_const("args");
id_receiver = rb_intern_const("receiver");
id_private_call_p = rb_intern_const("private_call?");
id_local_variables = rb_intern_const("local_variables");
id_Errno = rb_intern_const("Errno");
id_errno = rb_intern_const("errno");

View file

@ -762,6 +762,7 @@ end.join
assert_equal(:foo, e.name)
assert_equal([1, 2], e.args)
assert_same(obj, e.receiver)
assert_not_predicate(e, :private_call?)
e = assert_raise(NoMethodError) {
obj.instance_eval {foo(1, 2)}
@ -769,6 +770,7 @@ end.join
assert_equal(:foo, e.name)
assert_equal([1, 2], e.args)
assert_same(obj, e.receiver)
assert_predicate(e, :private_call?)
end
def test_name_error_info_local_variables
@ -787,6 +789,29 @@ end.join
assert_equal(%i[a b c d e f g], e.local_variables.sort)
end
def test_name_error_info_method_missing
obj = PrettyObject.new
def obj.method_missing(*)
super
end
e = assert_raise(NoMethodError) {
obj.foo(1, 2)
}
assert_equal(:foo, e.name)
assert_equal([1, 2], e.args)
assert_same(obj, e.receiver)
assert_not_predicate(e, :private_call?)
e = assert_raise(NoMethodError) {
obj.instance_eval {foo(1, 2)}
}
assert_equal(:foo, e.name)
assert_equal([1, 2], e.args)
assert_same(obj, e.receiver)
assert_predicate(e, :private_call?)
end
def test_name_error_info_parent_iseq_mark
assert_separately(['-', File.join(__dir__, 'bug-11928.rb')], <<-'end;')
-> {require ARGV[0]}.call

View file

@ -200,10 +200,11 @@ enum method_missing_reason {
MISSING_NOENTRY = 0x00,
MISSING_PRIVATE = 0x01,
MISSING_PROTECTED = 0x02,
MISSING_VCALL = 0x04,
MISSING_SUPER = 0x08,
MISSING_MISSING = 0x10,
MISSING_NONE = 0x20
MISSING_FCALL = 0x04,
MISSING_VCALL = 0x08,
MISSING_SUPER = 0x10,
MISSING_MISSING = 0x20,
MISSING_NONE = 0x40
};
struct rb_call_info {

View file

@ -682,13 +682,15 @@ rb_method_missing(int argc, const VALUE *argv, VALUE obj)
}
static VALUE
make_no_method_exception(VALUE exc, VALUE format, VALUE obj, int argc, const VALUE *argv)
make_no_method_exception(VALUE exc, VALUE format, VALUE obj,
int argc, const VALUE *argv, int priv)
{
int n = 0;
enum {
arg_mesg,
arg_name,
arg_args,
arg_priv,
args_size
};
VALUE args[args_size];
@ -700,6 +702,7 @@ make_no_method_exception(VALUE exc, VALUE format, VALUE obj, int argc, const VAL
args[n++] = argv[0];
if (exc == rb_eNoMethodError) {
args[n++] = rb_ary_new4(argc - 1, argv + 1);
args[n++] = priv ? Qtrue : Qfalse;
}
return rb_class_new_instance(n, args, exc);
}
@ -737,7 +740,8 @@ raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, VALUE obj,
}
{
exc = make_no_method_exception(exc, format, obj, argc, argv);
exc = make_no_method_exception(exc, format, obj, argc, argv,
last_call_status & (MISSING_FCALL|MISSING_VCALL));
if (!(last_call_status & MISSING_MISSING)) {
rb_vm_pop_cfunc_frame();
}
@ -929,7 +933,8 @@ send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
if (!id) {
if (rb_method_basic_definition_p(CLASS_OF(recv), idMethodMissing)) {
VALUE exc = make_no_method_exception(rb_eNoMethodError, 0,
recv, argc, argv);
recv, argc, argv,
scope != CALL_PUBLIC);
rb_exc_raise(exc);
}
if (!SYMBOL_P(*argv)) {

View file

@ -1782,6 +1782,7 @@ ci_missing_reason(const struct rb_call_info *ci)
{
enum method_missing_reason stat = MISSING_NOENTRY;
if (ci->flag & VM_CALL_VCALL) stat |= MISSING_VCALL;
if (ci->flag & VM_CALL_FCALL) stat |= MISSING_FCALL;
if (ci->flag & VM_CALL_SUPER) stat |= MISSING_SUPER;
return stat;
}
@ -1823,7 +1824,8 @@ vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling
if (!(ci->mid = rb_check_id(&sym))) {
if (rb_method_basic_definition_p(CLASS_OF(calling->recv), idMethodMissing)) {
VALUE exc = make_no_method_exception(rb_eNoMethodError, 0, calling->recv,
rb_long2int(calling->argc), &TOPN(i));
rb_long2int(calling->argc), &TOPN(i),
ci->flag & (VM_CALL_FCALL|VM_CALL_VCALL));
rb_exc_raise(exc);
}
TOPN(i) = rb_str_intern(sym);

View file

@ -185,8 +185,8 @@ enum vm_regan_acttype {
#define GET_GLOBAL_CONSTANT_STATE() (ruby_vm_global_constant_state)
#define INC_GLOBAL_CONSTANT_STATE() (++ruby_vm_global_constant_state)
static VALUE make_no_method_exception(VALUE exc, VALUE format,
VALUE obj, int argc, const VALUE *argv);
static VALUE make_no_method_exception(VALUE exc, VALUE format, VALUE obj,
int argc, const VALUE *argv, int priv);
static inline struct vm_throw_data *
THROW_DATA_NEW(VALUE val, rb_control_frame_t *cf, VALUE st)