зеркало из 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();
|
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_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
|
||||||
st_insert(vm->unused_block_warning_table, key, 1);
|
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_deprecated;
|
||||||
static ID id_experimental;
|
static ID id_experimental;
|
||||||
static ID id_performance;
|
static ID id_performance;
|
||||||
|
static ID id_strict_unused_block;
|
||||||
static VALUE sym_category;
|
static VALUE sym_category;
|
||||||
static VALUE sym_highlight;
|
static VALUE sym_highlight;
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -3584,6 +3585,7 @@ Init_Exception(void)
|
||||||
id_deprecated = rb_intern_const("deprecated");
|
id_deprecated = rb_intern_const("deprecated");
|
||||||
id_experimental = rb_intern_const("experimental");
|
id_experimental = rb_intern_const("experimental");
|
||||||
id_performance = rb_intern_const("performance");
|
id_performance = rb_intern_const("performance");
|
||||||
|
id_strict_unused_block = rb_intern_const("strict_unused_block");
|
||||||
id_top = rb_intern_const("top");
|
id_top = rb_intern_const("top");
|
||||||
id_bottom = rb_intern_const("bottom");
|
id_bottom = rb_intern_const("bottom");
|
||||||
id_iseq = rb_make_internal_id();
|
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_deprecated, RB_WARN_CATEGORY_DEPRECATED);
|
||||||
st_add_direct(warning_categories.id2enum, id_experimental, RB_WARN_CATEGORY_EXPERIMENTAL);
|
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_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();
|
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_NONE, 0);
|
||||||
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_DEPRECATED, id_deprecated);
|
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_EXPERIMENTAL, id_experimental);
|
||||||
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_PERFORMANCE, id_performance);
|
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
|
void
|
||||||
|
|
|
@ -53,6 +53,9 @@ typedef enum {
|
||||||
/** Warning is for performance issues (not enabled by -w). */
|
/** Warning is for performance issues (not enabled by -w). */
|
||||||
RB_WARN_CATEGORY_PERFORMANCE,
|
RB_WARN_CATEGORY_PERFORMANCE,
|
||||||
|
|
||||||
|
/** Warning is for checking unused block strictly */
|
||||||
|
RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK,
|
||||||
|
|
||||||
RB_WARN_CATEGORY_DEFAULT_BITS = (
|
RB_WARN_CATEGORY_DEFAULT_BITS = (
|
||||||
(1U << RB_WARN_CATEGORY_DEPRECATED) |
|
(1U << RB_WARN_CATEGORY_DEPRECATED) |
|
||||||
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
|
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
|
||||||
|
@ -62,6 +65,7 @@ typedef enum {
|
||||||
(1U << RB_WARN_CATEGORY_DEPRECATED) |
|
(1U << RB_WARN_CATEGORY_DEPRECATED) |
|
||||||
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
|
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
|
||||||
(1U << RB_WARN_CATEGORY_PERFORMANCE) |
|
(1U << RB_WARN_CATEGORY_PERFORMANCE) |
|
||||||
|
(1U << RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK) |
|
||||||
0)
|
0)
|
||||||
} rb_warning_category_t;
|
} 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("deprecated", "", "Deprecated features."),
|
||||||
M("experimental", "", "Experimental features."),
|
M("experimental", "", "Experimental features."),
|
||||||
M("performance", "", "Performance issues."),
|
M("performance", "", "Performance issues."),
|
||||||
|
M("strict_unused_block", "", "Warning unused block strictly"),
|
||||||
};
|
};
|
||||||
#if USE_RJIT
|
#if USE_RJIT
|
||||||
extern const struct ruby_opt_message rb_rjit_option_messages[];
|
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)) {
|
else if (NAME_MATCH_P("performance", s, len)) {
|
||||||
bits = 1U << RB_WARN_CATEGORY_PERFORMANCE;
|
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 {
|
else {
|
||||||
rb_warn("unknown warning category: '%s'", s);
|
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(-We) + ['p $-W'], "", %w(2), [])
|
||||||
assert_in_out_err(%w(-w -W0 -e) + ['p $-W'], "", %w(0), [])
|
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
|
assert_equal categories.keys.sort, Warning.categories.sort
|
||||||
|
|
||||||
categories.each do |category, level|
|
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->constant_cache = rb_id_table_create(0);
|
||||||
vm->unused_block_warning_table = st_init_numtable();
|
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
|
// setup main thread
|
||||||
th->nt = ZALLOC(struct rb_native_thread);
|
th->nt = ZALLOC(struct rb_native_thread);
|
||||||
th->vm = vm;
|
th->vm = vm;
|
||||||
|
|
|
@ -799,7 +799,6 @@ typedef struct rb_vm_struct {
|
||||||
struct rb_id_table *negative_cme_table;
|
struct rb_id_table *negative_cme_table;
|
||||||
st_table *overloaded_cme_table; // cme -> overloaded_cme
|
st_table *overloaded_cme_table; // cme -> overloaded_cme
|
||||||
st_table *unused_block_warning_table;
|
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
|
// 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
|
// 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();
|
rb_vm_t *vm = GET_VM();
|
||||||
st_table *dup_check_table = vm->unused_block_warning_table;
|
st_table *dup_check_table = vm->unused_block_warning_table;
|
||||||
st_data_t key;
|
st_data_t key;
|
||||||
|
bool strict_unused_block = rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
VALUE v;
|
VALUE v;
|
||||||
|
@ -3046,7 +3047,7 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
|
||||||
};
|
};
|
||||||
|
|
||||||
// relax check
|
// relax check
|
||||||
if (!vm->unused_block_warning_strict) {
|
if (!strict_unused_block) {
|
||||||
key = (st_data_t)cme->def->original_id;
|
key = (st_data_t)cme->def->original_id;
|
||||||
|
|
||||||
if (st_lookup(dup_check_table, key, NULL)) {
|
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)) {
|
if (st_insert(dup_check_table, key, 1)) {
|
||||||
// already shown
|
// 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 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);
|
VALUE name = rb_gen_method_name(cme->defined_class, ISEQ_BODY(iseq)->location.base_label);
|
||||||
|
|
||||||
if (!NIL_P(m_loc)) {
|
if (!NIL_P(m_loc)) {
|
||||||
rb_warning("the block passed to '%"PRIsVALUE"' defined at %"PRIsVALUE":%"PRIsVALUE" may be ignored",
|
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));
|
name, RARRAY_AREF(m_loc, 0), RARRAY_AREF(m_loc, 1));
|
||||||
}
|
}
|
||||||
else {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче