Skip to content

Commit 9180e33

Browse files
committed
show warning for unused block
With verbopse mode (-w), the interpreter shows a warning if a block is passed to a method which does not use the given block. Warning on: * the invoked method is written in C * the invoked method is not `initialize` * not invoked with `super` * the first time on the call-site with the invoked method (`obj.foo{}` will be warned once if `foo` is same method) [Feature #15554] `Primitive.attr! :use_block` is introduced to declare that primitive functions (written in C) will use passed block. For minitest, test needs some tweak, so use minitest/minitest@ea9caaf for `test-bundled-gems`.
1 parent 515e52a commit 9180e33

18 files changed

+165
-13
lines changed

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,14 @@ See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/log
111111

112112
## JIT
113113

114+
## Miscellaneous changes
115+
116+
* Passing a block to a method which doesn't use the passed block will show
117+
a warning on verbose mode (`-w`).
118+
[[Feature #15554]]
119+
114120
[Feature #13557]: https://bugs.ruby-lang.org/issues/13557
121+
[Feature #15554]: https://bugs.ruby-lang.org/issues/15554
115122
[Feature #16495]: https://bugs.ruby-lang.org/issues/16495
116123
[Feature #18290]: https://bugs.ruby-lang.org/issues/18290
117124
[Feature #18980]: https://bugs.ruby-lang.org/issues/18980

array.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class Array
4343
# Related: #each_index, #reverse_each.
4444
def each
4545
Primitive.attr! :inline_block
46+
Primitive.attr! :use_block
47+
4648
unless defined?(yield)
4749
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
4850
end

compile.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2098,6 +2098,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
20982098
if (block_id) {
20992099
body->param.block_start = arg_size++;
21002100
body->param.flags.has_block = TRUE;
2101+
body->param.flags.use_block = 1;
21012102
}
21022103

21032104
iseq_calc_param_size(iseq);
@@ -5918,6 +5919,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
59185919
ADD_INSN(ret, line_node, putnil);
59195920
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
59205921
PUSH_VAL(DEFINED_YIELD));
5922+
ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
59215923
return;
59225924

59235925
case NODE_BACK_REF:
@@ -8628,6 +8630,9 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
86288630
else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
86298631
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
86308632
}
8633+
else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
8634+
ISEQ_BODY(iseq)->param.flags.use_block = 1;
8635+
}
86318636
else {
86328637
goto unknown_arg;
86338638
}
@@ -9377,6 +9382,8 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
93779382
}
93789383
else {
93799384
/* NODE_ZSUPER */
9385+
ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
9386+
93809387
int i;
93819388
const rb_iseq_t *liseq = body->local_iseq;
93829389
const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
@@ -9510,6 +9517,7 @@ compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
95109517

95119518
ADD_SEQ(ret, args);
95129519
ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9520+
ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
95139521

95149522
if (popped) {
95159523
ADD_INSN(ret, node, pop);
@@ -12935,7 +12943,10 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
1293512943
(body->param.flags.has_block << 6) |
1293612944
(body->param.flags.ambiguous_param0 << 7) |
1293712945
(body->param.flags.accepts_no_kwarg << 8) |
12938-
(body->param.flags.ruby2_keywords << 9);
12946+
(body->param.flags.ruby2_keywords << 9) |
12947+
(body->param.flags.anon_rest << 10) |
12948+
(body->param.flags.anon_kwrest << 11) |
12949+
(body->param.flags.use_block << 12);
1293912950

1294012951
#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
1294112952
# define IBF_BODY_OFFSET(x) (x)
@@ -13151,6 +13162,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
1315113162
load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
1315213163
load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
1315313164
load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13165+
load_body->param.flags.use_block = (param_flags >> 12) & 1;
1315413166
load_body->param.size = param_size;
1315513167
load_body->param.lead_num = param_lead_num;
1315613168
load_body->param.opt_num = param_opt_num;

dir.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ def self.[](*args, base: nil, sort: true)
408408
# specifies that patterns may match short names if they exist; Windows only.
409409
#
410410
def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true)
411+
Primitive.attr! :use_block
411412
Primitive.dir_s_glob(pattern, flags, base, sort)
412413
end
413414
end

gems/bundled_gems

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# - revision: revision in repository-url to test
77
# if `revision` is not given, "v"+`version` or `version` will be used.
88

9-
minitest 5.22.3 https://github.com/minitest/minitest 287b35d60c8e19c11ba090efc6eeb225325a8520
9+
minitest 5.22.3 https://github.com/minitest/minitest ea9caafc0754b1d6236a490d59e624b53209734a
1010
power_assert 2.0.3 https://github.com/ruby/power_assert 84e85124c5014a139af39161d484156cfe87a9ed
1111
rake 13.2.1 https://github.com/ruby/rake
1212
test-unit 3.6.2 https://github.com/test-unit/test-unit

iseq.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,11 @@ iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, int
538538
RB_OBJ_WRITE(iseq, &loc->label, name);
539539
RB_OBJ_WRITE(iseq, &loc->base_label, name);
540540
loc->first_lineno = first_lineno;
541+
542+
if (ISEQ_BODY(iseq)->local_iseq == iseq && strcmp(RSTRING_PTR(name), "initialize") == 0) {
543+
ISEQ_BODY(iseq)->param.flags.use_block = 1;
544+
}
545+
541546
if (code_location) {
542547
loc->node_id = node_id;
543548
loc->code_location = *code_location;
@@ -1011,6 +1016,7 @@ pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpa
10111016
{
10121017
rb_iseq_t *iseq = iseq_alloc();
10131018
ISEQ_BODY(iseq)->prism = true;
1019+
ISEQ_BODY(iseq)->param.flags.use_block = true; // unused block warning is not supported yet
10141020

10151021
if (!option) option = &COMPILE_OPTION_DEFAULT;
10161022

lib/optparse.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ def self.candidate(key, icase = false, pat = nil, &block)
461461
candidates
462462
end
463463

464-
def candidate(key, icase = false, pat = nil)
464+
def candidate(key, icase = false, pat = nil, &_)
465465
Completion.candidate(key, icase, pat, &method(:each))
466466
end
467467

@@ -739,7 +739,7 @@ class RequiredArgument < self
739739
#
740740
# Raises an exception if argument is not present.
741741
#
742-
def parse(arg, argv)
742+
def parse(arg, argv, &_)
743743
unless arg
744744
raise MissingArgument if argv.empty?
745745
arg = argv.shift

lib/rdoc/context.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ def display(method_attr) # :nodoc:
710710
# This method exists to make it easy to work with Context subclasses that
711711
# aren't part of RDoc.
712712

713-
def each_ancestor # :nodoc:
713+
def each_ancestor(&_) # :nodoc:
714714
end
715715

716716
##

pack.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class String
1717
# returns that array.
1818
# See {Packed Data}[rdoc-ref:packed_data.rdoc].
1919
def unpack(fmt, offset: 0)
20+
Primitive.attr! :use_block
2021
Primitive.pack_unpack(fmt, offset)
2122
end
2223

rjit_c.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,7 @@ def C.rb_iseq_constant_body
10931093
ruby2_keywords: [CType::BitField.new(1, 1), 9],
10941094
anon_rest: [CType::BitField.new(1, 2), 10],
10951095
anon_kwrest: [CType::BitField.new(1, 3), 11],
1096+
use_block: [CType::BitField.new(1, 4), 12],
10961097
), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, flags)")],
10971098
size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, size)")],
10981099
lead_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, lead_num)")],

0 commit comments

Comments
 (0)