# frozen_string_literal: true module RuboCop module Cop module Style # Checks for a redundant argument passed to certain methods. # # NOTE: This cop is limited to methods with single parameter. # # Method names and their redundant arguments can be configured like this: # # [source,yaml] # ---- # Methods: # join: '' # split: ' ' # chomp: "\n" # chomp!: "\n" # foo: 2 # ---- # # @safety # This cop is unsafe because of the following limitations: # # 1. This cop matches by method names only and hence cannot tell apart # methods with same name in different classes. # 2. This cop may be unsafe if certain special global variables (e.g. `$;`, `$/`) are set. # That depends on the nature of the target methods, of course. For example, the default # argument to join is `$OUTPUT_FIELD_SEPARATOR` (or `$,`) rather than `''`, and if that # global is changed, `''` is no longer a redundant argument. # # @example # # bad # array.join('') # [1, 2, 3].join("") # string.split(" ") # "first\nsecond".split(" ") # string.chomp("\n") # string.chomp!("\n") # A.foo(2) # # # good # array.join # [1, 2, 3].join # string.split # "first second".split # string.chomp # string.chomp! # A.foo class RedundantArgument < Base include RangeHelp extend AutoCorrector MSG = 'Argument %s is redundant because it is implied by default.' def on_send(node) return if node.receiver.nil? return if node.arguments.count != 1 return unless redundant_argument?(node) offense_range = argument_range(node) message = format(MSG, arg: node.arguments.first.source) add_offense(offense_range, message: message) do |corrector| corrector.remove(offense_range) end end private def redundant_argument?(node) redundant_argument = redundant_arg_for_method(node.method_name.to_s) return false if redundant_argument.nil? node.arguments.first == redundant_argument end def redundant_arg_for_method(method_name) arg = cop_config['Methods'].fetch(method_name) { return } @mem ||= {} @mem[method_name] ||= parse(arg.inspect).ast end def argument_range(node) if node.parenthesized? range_between(node.loc.begin.begin_pos, node.loc.end.end_pos) else range_with_surrounding_space(node.first_argument.source_range, newlines: false) end end end end end end