зеркало из https://github.com/github/ruby.git
`Warning[:strict_unused_block]`
to show unused block warning strictly. ```ruby class C def f = nil end class D def f = yield end [C.new, D.new].each{|obj| obj.f{}} ``` In this case, `D#f` accepts a block. However `C#f` doesn't accept a block. There are some cases passing a block with `obj.f{}` where `obj` is `C` or `D`. To avoid warnings on such cases, "unused block warning" will be warned only if there is not same name which accepts a block. On the above example, `C.new.f{}` doesn't show any warnings because there is a same name `D#f` which accepts a block. We call this default behavior as "relax mode". `strict_unused_block` new warning category changes from "relax mode" to "strict mode", we don't check same name methods and `C.new.f{}` will be warned. [Feature #15554]
This commit is contained in:
Родитель
4203c70dfa
Коммит
ab7ab9e450
|
@ -2007,7 +2007,7 @@ iseq_set_use_block(rb_iseq_t *iseq)
|
|||
|
||||
rb_vm_t *vm = GET_VM();
|
||||
|
||||
if (!vm->unused_block_warning_strict) {
|
||||
if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
|
||||
st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
|
||||
st_insert(vm->unused_block_warning_table, key, 1);
|
||||
}
|
||||
|
|
4
error.c
4
error.c
|
@ -86,6 +86,7 @@ static ID id_category;
|
|||
static ID id_deprecated;
|
||||
static ID id_experimental;
|
||||
static ID id_performance;
|
||||
static ID id_strict_unused_block;
|
||||
static VALUE sym_category;
|
||||
static VALUE sym_highlight;
|
||||
static struct {
|
||||
|
@ -3584,6 +3585,7 @@ Init_Exception(void)
|
|||
id_deprecated = rb_intern_const("deprecated");
|
||||
id_experimental = rb_intern_const("experimental");
|
||||
id_performance = rb_intern_const("performance");
|
||||
id_strict_unused_block = rb_intern_const("strict_unused_block");
|
||||
id_top = rb_intern_const("top");
|
||||
id_bottom = rb_intern_const("bottom");
|
||||
id_iseq = rb_make_internal_id();
|
||||
|
@ -3596,12 +3598,14 @@ Init_Exception(void)
|
|||
st_add_direct(warning_categories.id2enum, id_deprecated, RB_WARN_CATEGORY_DEPRECATED);
|
||||
st_add_direct(warning_categories.id2enum, id_experimental, RB_WARN_CATEGORY_EXPERIMENTAL);
|
||||
st_add_direct(warning_categories.id2enum, id_performance, RB_WARN_CATEGORY_PERFORMANCE);
|
||||
st_add_direct(warning_categories.id2enum, id_strict_unused_block, RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK);
|
||||
|
||||
warning_categories.enum2id = rb_init_identtable();
|
||||
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_NONE, 0);
|
||||
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_DEPRECATED, id_deprecated);
|
||||
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_EXPERIMENTAL, id_experimental);
|
||||
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_PERFORMANCE, id_performance);
|
||||
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK, id_strict_unused_block);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -53,6 +53,9 @@ typedef enum {
|
|||
/** Warning is for performance issues (not enabled by -w). */
|
||||
RB_WARN_CATEGORY_PERFORMANCE,
|
||||
|
||||
/** Warning is for checking unused block strictly */
|
||||
RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK,
|
||||
|
||||
RB_WARN_CATEGORY_DEFAULT_BITS = (
|
||||
(1U << RB_WARN_CATEGORY_DEPRECATED) |
|
||||
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
|
||||
|
@ -62,6 +65,7 @@ typedef enum {
|
|||
(1U << RB_WARN_CATEGORY_DEPRECATED) |
|
||||
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
|
||||
(1U << RB_WARN_CATEGORY_PERFORMANCE) |
|
||||
(1U << RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK) |
|
||||
0)
|
||||
} rb_warning_category_t;
|
||||
|
||||
|
|
4
ruby.c
4
ruby.c
|
@ -398,6 +398,7 @@ usage(const char *name, int help, int highlight, int columns)
|
|||
M("deprecated", "", "Deprecated features."),
|
||||
M("experimental", "", "Experimental features."),
|
||||
M("performance", "", "Performance issues."),
|
||||
M("strict_unused_block", "", "Warning unused block strictly"),
|
||||
};
|
||||
#if USE_RJIT
|
||||
extern const struct ruby_opt_message rb_rjit_option_messages[];
|
||||
|
@ -1233,6 +1234,9 @@ proc_W_option(ruby_cmdline_options_t *opt, const char *s, int *warning)
|
|||
else if (NAME_MATCH_P("performance", s, len)) {
|
||||
bits = 1U << RB_WARN_CATEGORY_PERFORMANCE;
|
||||
}
|
||||
else if (NAME_MATCH_P("strict_unused_block", s, len)) {
|
||||
bits = 1U << RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK;
|
||||
}
|
||||
else {
|
||||
rb_warn("unknown warning category: '%s'", s);
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ class TestRubyOptions < Test::Unit::TestCase
|
|||
assert_in_out_err(%w(-We) + ['p $-W'], "", %w(2), [])
|
||||
assert_in_out_err(%w(-w -W0 -e) + ['p $-W'], "", %w(0), [])
|
||||
|
||||
categories = {deprecated: 1, experimental: 0, performance: 2}
|
||||
categories = {deprecated: 1, experimental: 0, performance: 2, strict_unused_block: 3}
|
||||
assert_equal categories.keys.sort, Warning.categories.sort
|
||||
|
||||
categories.each do |category, level|
|
||||
|
|
6
vm.c
6
vm.c
|
@ -4271,12 +4271,6 @@ Init_BareVM(void)
|
|||
vm->constant_cache = rb_id_table_create(0);
|
||||
vm->unused_block_warning_table = st_init_numtable();
|
||||
|
||||
// TODO: remove before Ruby 3.4.0 release
|
||||
const char *s = getenv("RUBY_TRY_UNUSED_BLOCK_WARNING_STRICT");
|
||||
if (s && strcmp(s, "1") == 0) {
|
||||
vm->unused_block_warning_strict = true;
|
||||
}
|
||||
|
||||
// setup main thread
|
||||
th->nt = ZALLOC(struct rb_native_thread);
|
||||
th->vm = vm;
|
||||
|
|
|
@ -799,7 +799,6 @@ typedef struct rb_vm_struct {
|
|||
struct rb_id_table *negative_cme_table;
|
||||
st_table *overloaded_cme_table; // cme -> overloaded_cme
|
||||
st_table *unused_block_warning_table;
|
||||
bool unused_block_warning_strict;
|
||||
|
||||
// This id table contains a mapping from ID to ICs. It does this with ID
|
||||
// keys and nested st_tables as values. The nested tables have ICs as keys
|
||||
|
|
|
@ -3035,6 +3035,7 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
|
|||
rb_vm_t *vm = GET_VM();
|
||||
st_table *dup_check_table = vm->unused_block_warning_table;
|
||||
st_data_t key;
|
||||
bool strict_unused_block = rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK);
|
||||
|
||||
union {
|
||||
VALUE v;
|
||||
|
@ -3046,7 +3047,7 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
|
|||
};
|
||||
|
||||
// relax check
|
||||
if (!vm->unused_block_warning_strict) {
|
||||
if (!strict_unused_block) {
|
||||
key = (st_data_t)cme->def->original_id;
|
||||
|
||||
if (st_lookup(dup_check_table, key, NULL)) {
|
||||
|
@ -3072,16 +3073,16 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
|
|||
if (st_insert(dup_check_table, key, 1)) {
|
||||
// already shown
|
||||
}
|
||||
else {
|
||||
else if (RTEST(ruby_verbose) || strict_unused_block) {
|
||||
VALUE m_loc = rb_method_entry_location((const rb_method_entry_t *)cme);
|
||||
VALUE name = rb_gen_method_name(cme->defined_class, ISEQ_BODY(iseq)->location.base_label);
|
||||
|
||||
if (!NIL_P(m_loc)) {
|
||||
rb_warning("the block passed to '%"PRIsVALUE"' defined at %"PRIsVALUE":%"PRIsVALUE" may be ignored",
|
||||
name, RARRAY_AREF(m_loc, 0), RARRAY_AREF(m_loc, 1));
|
||||
rb_warn("the block passed to '%"PRIsVALUE"' defined at %"PRIsVALUE":%"PRIsVALUE" may be ignored",
|
||||
name, RARRAY_AREF(m_loc, 0), RARRAY_AREF(m_loc, 1));
|
||||
}
|
||||
else {
|
||||
rb_warning("the block may be ignored because '%"PRIsVALUE"' does not use a block", name);
|
||||
rb_warn("the block may be ignored because '%"PRIsVALUE"' does not use a block", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче