# frozen_string_literal: true module RuboCop module Cop module Lint # This cop checks for unused block arguments. # # @example # # #good # # do_something do |used, unused| # puts used # end # # do_something do # puts :foo # end # # define_method(:foo) do |_bar| # puts :baz # end # # # bad # # do_something do |used, _unused| # puts used # end # # do_something do |bar| # puts :foo # end # # define_method(:foo) do |bar| # puts :baz # end class UnusedBlockArgument < Cop include UnusedArgument private def check_argument(variable) return if allowed_block?(variable) || allowed_keyword_argument?(variable) super end def allowed_block?(variable) !variable.block_argument? || (ignore_empty_blocks? && empty_block?(variable)) end def allowed_keyword_argument?(variable) variable.keyword_argument? && allow_unused_keyword_arguments? end def message(variable) message = "Unused #{variable_type(variable)} - `#{variable.name}`." if variable.explicit_block_local_variable? message else augment_message(message, variable) end end def augment_message(message, variable) scope = variable.scope all_arguments = scope.variables.each_value.select(&:block_argument?) augmentation = if scope.node.lambda? message_for_lambda(variable, all_arguments) else message_for_normal_block(variable, all_arguments) end [message, augmentation].join(' ') end def variable_type(variable) if variable.explicit_block_local_variable? 'block local variable' else 'block argument' end end def message_for_normal_block(variable, all_arguments) if all_arguments.none?(&:referenced?) && !define_method_call?(variable) if all_arguments.count > 1 "You can omit all the arguments if you don't care about them." else "You can omit the argument if you don't care about it." end else message_for_underscore_prefix(variable) end end def message_for_lambda(variable, all_arguments) message = message_for_underscore_prefix(variable) if all_arguments.none?(&:referenced?) proc_message = 'Also consider using a proc without arguments ' \ 'instead of a lambda if you want it ' \ "to accept any arguments but don't care about them." end [message, proc_message].compact.join(' ') end def message_for_underscore_prefix(variable) "If it's necessary, use `_` or `_#{variable.name}` " \ "as an argument name to indicate that it won't be used." end def define_method_call?(variable) call, = *variable.scope.node _, method, = *call method == :define_method end def empty_block?(variable) _send, _args, body = *variable.scope.node body.nil? end def allow_unused_keyword_arguments? cop_config['AllowUnusedKeywordArguments'] end def ignore_empty_blocks? cop_config['IgnoreEmptyBlocks'] end end end end end