rubocop 0.92.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -7
  3. data/config/default.yml +169 -59
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop.rb +15 -3
  6. data/lib/rubocop/cached_data.rb +2 -1
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  8. data/lib/rubocop/cli/command/version.rb +1 -1
  9. data/lib/rubocop/comment_config.rb +1 -1
  10. data/lib/rubocop/config.rb +4 -0
  11. data/lib/rubocop/config_loader.rb +19 -2
  12. data/lib/rubocop/config_loader_resolver.rb +7 -5
  13. data/lib/rubocop/config_validator.rb +7 -6
  14. data/lib/rubocop/cop/badge.rb +9 -24
  15. data/lib/rubocop/cop/base.rb +16 -1
  16. data/lib/rubocop/cop/bundler/duplicated_gem.rb +23 -3
  17. data/lib/rubocop/cop/commissioner.rb +36 -22
  18. data/lib/rubocop/cop/corrector.rb +3 -1
  19. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  20. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  21. data/lib/rubocop/cop/force.rb +1 -1
  22. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
  23. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  24. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  25. data/lib/rubocop/cop/layout/dot_position.rb +6 -9
  26. data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
  27. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +7 -7
  28. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  29. data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
  30. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
  31. data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
  32. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
  33. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -11
  34. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  35. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
  36. data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
  37. data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
  38. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
  39. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +18 -1
  40. data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
  41. data/lib/rubocop/cop/lint/debugger.rb +2 -3
  42. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
  43. data/lib/rubocop/cop/lint/else_layout.rb +29 -3
  44. data/lib/rubocop/cop/lint/empty_block.rb +59 -0
  45. data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
  46. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
  47. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +17 -3
  48. data/lib/rubocop/cop/lint/loop.rb +0 -4
  49. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  50. data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
  51. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
  52. data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
  53. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
  54. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  55. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
  56. data/lib/rubocop/cop/lint/to_enum_arguments.rb +95 -0
  57. data/lib/rubocop/cop/lint/to_json.rb +1 -1
  58. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +185 -0
  59. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  60. data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
  61. data/lib/rubocop/cop/metrics/block_length.rb +3 -1
  62. data/lib/rubocop/cop/metrics/class_length.rb +14 -6
  63. data/lib/rubocop/cop/metrics/parameter_lists.rb +4 -1
  64. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
  65. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  66. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  67. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +12 -2
  68. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
  69. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
  70. data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
  71. data/lib/rubocop/cop/naming/variable_number.rb +82 -8
  72. data/lib/rubocop/cop/offense.rb +18 -5
  73. data/lib/rubocop/cop/security/open.rb +12 -10
  74. data/lib/rubocop/cop/style/access_modifier_declarations.rb +6 -2
  75. data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
  76. data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
  77. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
  78. data/lib/rubocop/cop/style/case_like_if.rb +18 -6
  79. data/lib/rubocop/cop/style/class_equality_comparison.rb +64 -0
  80. data/lib/rubocop/cop/style/collection_compact.rb +85 -0
  81. data/lib/rubocop/cop/style/combinable_loops.rb +8 -1
  82. data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
  83. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +67 -0
  84. data/lib/rubocop/cop/style/double_negation.rb +6 -1
  85. data/lib/rubocop/cop/style/explicit_block_argument.rb +6 -2
  86. data/lib/rubocop/cop/style/for.rb +0 -4
  87. data/lib/rubocop/cop/style/format_string_token.rb +48 -3
  88. data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
  89. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
  90. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
  91. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -11
  92. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
  93. data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
  94. data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
  95. data/lib/rubocop/cop/style/multiple_comparison.rb +54 -7
  96. data/lib/rubocop/cop/style/negated_if_else_condition.rb +99 -0
  97. data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
  98. data/lib/rubocop/cop/style/raise_args.rb +21 -9
  99. data/lib/rubocop/cop/style/redundant_begin.rb +36 -8
  100. data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
  101. data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
  102. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  103. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +45 -24
  104. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
  105. data/lib/rubocop/cop/style/redundant_self.rb +3 -0
  106. data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
  107. data/lib/rubocop/cop/style/semicolon.rb +3 -0
  108. data/lib/rubocop/cop/style/string_concatenation.rb +14 -2
  109. data/lib/rubocop/cop/style/swap_values.rb +108 -0
  110. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  111. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  112. data/lib/rubocop/cop/team.rb +6 -1
  113. data/lib/rubocop/cop/util.rb +5 -1
  114. data/lib/rubocop/cop/variable_force/branch.rb +0 -4
  115. data/lib/rubocop/ext/regexp_node.rb +35 -11
  116. data/lib/rubocop/ext/regexp_parser.rb +84 -0
  117. data/lib/rubocop/formatter/formatter_set.rb +2 -1
  118. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
  119. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  120. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  121. data/lib/rubocop/magic_comment.rb +2 -2
  122. data/lib/rubocop/options.rb +6 -1
  123. data/lib/rubocop/result_cache.rb +8 -2
  124. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  125. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  126. data/lib/rubocop/runner.rb +4 -4
  127. data/lib/rubocop/target_finder.rb +23 -25
  128. data/lib/rubocop/version.rb +56 -6
  129. metadata +22 -8
  130. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
@@ -76,10 +76,6 @@ module RuboCop
76
76
  conditional_keyword = node.while_post_type? ? 'unless' : 'if'
77
77
  "break #{conditional_keyword} #{node.condition.source}\n#{indent(node)}"
78
78
  end
79
-
80
- def indent(node)
81
- ' ' * node.loc.column
82
- end
83
79
  end
84
80
  end
85
81
  end
@@ -25,6 +25,7 @@ module RuboCop
25
25
  'in a Regexp literal.'
26
26
 
27
27
  def on_regexp(node)
28
+ return if node.interpolation?
28
29
  return if node.each_capture(named: false).none?
29
30
  return if node.each_capture(named: true).none?
30
31
 
@@ -15,6 +15,20 @@ module RuboCop
15
15
  # valid_attributes: %i[name content],
16
16
  # nested_attributes: %i[name content %i[incorrectly nested]]
17
17
  # }
18
+ #
19
+ # # good
20
+ #
21
+ # # Neither is incompatible with the bad case, but probably the intended code.
22
+ # attributes = {
23
+ # valid_attributes: %i[name content],
24
+ # nested_attributes: [:name, :content, %i[incorrectly nested]]
25
+ # }
26
+ #
27
+ # attributes = {
28
+ # valid_attributes: %i[name content],
29
+ # nested_attributes: [:name, :content, [:incorrectly, :nested]]
30
+ # }
31
+ #
18
32
  class NestedPercentLiteral < Base
19
33
  include PercentLiteral
20
34
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for the presence of a `return` inside a `begin..end` block
7
+ # in assignment contexts.
8
+ # In this situation, the `return` will result in an exit from the current
9
+ # method, possibly leading to unexpected behavior.
10
+ #
11
+ # @example
12
+ #
13
+ # # bad
14
+ #
15
+ # @some_variable ||= begin
16
+ # return some_value if some_condition_is_met
17
+ #
18
+ # do_something
19
+ # end
20
+ #
21
+ # @example
22
+ #
23
+ # # good
24
+ #
25
+ # @some_variable ||= begin
26
+ # if some_condition_is_met
27
+ # some_value
28
+ # else
29
+ # do_something
30
+ # end
31
+ # end
32
+ #
33
+ # # good
34
+ #
35
+ # some_variable = if some_condition_is_met
36
+ # return if another_condition_is_met
37
+ #
38
+ # some_value
39
+ # else
40
+ # do_something
41
+ # end
42
+ #
43
+ class NoReturnInBeginEndBlocks < Cop
44
+ MSG = 'Do not `return` in `begin..end` blocks in assignment contexts.'
45
+
46
+ def on_lvasgn(node)
47
+ node.each_node(:kwbegin) do |kwbegin_node|
48
+ kwbegin_node.each_node(:return) do |return_node|
49
+ add_offense(return_node)
50
+ end
51
+ end
52
+ end
53
+ alias on_or_asgn on_lvasgn
54
+ alias on_op_asgn on_lvasgn
55
+ end
56
+ end
57
+ end
58
+ end
@@ -7,6 +7,17 @@ module RuboCop
7
7
  # number conversion can cause unexpected error if auto type conversion
8
8
  # fails. Cop prefer parsing with number class instead.
9
9
  #
10
+ # Conversion with `Integer`, `Float`, etc. will raise an `ArgumentError`
11
+ # if given input that is not numeric (eg. an empty string), whereas
12
+ # `to_i`, etc. will try to convert regardless of input (`''.to_i => 0`).
13
+ # As such, this cop is disabled by default because it's not necessarily
14
+ # always correct to raise if a value is not numeric.
15
+ #
16
+ # NOTE: Some values cannot be converted properly using one of the `Kernel`
17
+ # method (for instance, `Time` and `DateTime` values are allowed by this
18
+ # cop by default). Similarly, Rails' duration methods do not work well
19
+ # with `Integer()` and can be ignored with `IgnoredMethods`.
20
+ #
10
21
  # @example
11
22
  #
12
23
  # # bad
@@ -20,8 +31,19 @@ module RuboCop
20
31
  # Integer('10', 10)
21
32
  # Float('10.2')
22
33
  # Complex('10')
34
+ #
35
+ # @example IgnoredMethods: [minutes]
36
+ #
37
+ # # good
38
+ # 10.minutes.to_i
39
+ #
40
+ # @example IgnoredClasses: [Time, DateTime] (default)
41
+ #
42
+ # # good
43
+ # Time.now.to_datetime.to_i
23
44
  class NumberConversion < Base
24
45
  extend AutoCorrector
46
+ include IgnoredMethods
25
47
 
26
48
  CONVERSION_METHOD_CLASS_MAPPING = {
27
49
  to_i: "#{Integer.name}(%<number_object>s, 10)",
@@ -38,13 +60,9 @@ module RuboCop
38
60
  (send $_ ${:to_i :to_f :to_c})
39
61
  PATTERN
40
62
 
41
- def_node_matcher :datetime?, <<~PATTERN
42
- (send (const {nil? (cbase)} {:Time :DateTime}) ...)
43
- PATTERN
44
-
45
63
  def on_send(node)
46
64
  to_method(node) do |receiver, to_method|
47
- next if receiver.nil? || date_time_object?(receiver)
65
+ next if receiver.nil? || ignore_receiver?(receiver)
48
66
 
49
67
  message = format(
50
68
  MSG,
@@ -60,18 +78,33 @@ module RuboCop
60
78
 
61
79
  private
62
80
 
63
- def date_time_object?(node)
64
- child = node
65
- while child&.send_type?
66
- return true if datetime? child
81
+ def correct_method(node, receiver)
82
+ format(CONVERSION_METHOD_CLASS_MAPPING[node.method_name],
83
+ number_object: receiver.source)
84
+ end
67
85
 
68
- child = child.children[0]
86
+ def ignore_receiver?(receiver)
87
+ if receiver.send_type? && ignored_method?(receiver.method_name)
88
+ true
89
+ elsif (receiver = top_receiver(receiver))
90
+ receiver.const_type? && ignored_class?(receiver.const_name)
91
+ else
92
+ false
69
93
  end
70
94
  end
71
95
 
72
- def correct_method(node, receiver)
73
- format(CONVERSION_METHOD_CLASS_MAPPING[node.method_name],
74
- number_object: receiver.source)
96
+ def top_receiver(node)
97
+ receiver = node
98
+ receiver = receiver.receiver until receiver.receiver.nil?
99
+ receiver
100
+ end
101
+
102
+ def ignored_classes
103
+ cop_config.fetch('IgnoredClasses', [])
104
+ end
105
+
106
+ def ignored_class?(name)
107
+ ignored_classes.include?(name.to_s)
75
108
  end
76
109
  end
77
110
  end
@@ -19,7 +19,7 @@ module RuboCop
19
19
  # puts $1 # => foo
20
20
  #
21
21
  class OutOfRangeRegexpRef < Base
22
- MSG = 'Do not use out of range reference for the Regexp.'
22
+ MSG = '$%<backref>s is out of range (%<count>s regexp capture %<group>s detected).'
23
23
 
24
24
  REGEXP_RECEIVER_METHODS = %i[=~ === match].to_set.freeze
25
25
  REGEXP_ARGUMENT_METHODS = %i[=~ match grep gsub gsub! sub sub! [] slice slice! index rindex
@@ -35,14 +35,13 @@ module RuboCop
35
35
  check_regexp(node.children.first)
36
36
  end
37
37
 
38
- def on_send(node)
38
+ def after_send(node)
39
39
  @valid_ref = nil
40
40
 
41
- if node.receiver&.regexp_type?
42
- check_regexp(node.receiver)
43
- elsif node.first_argument&.regexp_type? \
44
- && REGEXP_ARGUMENT_METHODS.include?(node.method_name)
41
+ if regexp_first_argument?(node)
45
42
  check_regexp(node.first_argument)
43
+ elsif regexp_receiver?(node)
44
+ check_regexp(node.receiver)
46
45
  end
47
46
  end
48
47
 
@@ -56,9 +55,16 @@ module RuboCop
56
55
 
57
56
  def on_nth_ref(node)
58
57
  backref, = *node
59
- return if @valid_ref.nil?
58
+ return if @valid_ref.nil? || backref <= @valid_ref
59
+
60
+ message = format(
61
+ MSG,
62
+ backref: backref,
63
+ count: @valid_ref.zero? ? 'no' : @valid_ref,
64
+ group: @valid_ref == 1 ? 'group' : 'groups'
65
+ )
60
66
 
61
- add_offense(node) if backref > @valid_ref
67
+ add_offense(node, message: message)
62
68
  end
63
69
 
64
70
  private
@@ -73,6 +79,19 @@ module RuboCop
73
79
  node.each_capture(named: false).count
74
80
  end
75
81
  end
82
+
83
+ def regexp_first_argument?(send_node)
84
+ send_node.first_argument&.regexp_type? \
85
+ && REGEXP_ARGUMENT_METHODS.include?(send_node.method_name)
86
+ end
87
+
88
+ def regexp_receiver?(send_node)
89
+ send_node.receiver&.regexp_type?
90
+ end
91
+
92
+ def nth_ref_receiver?(send_node)
93
+ send_node.receiver&.nth_ref_type?
94
+ end
76
95
  end
77
96
  end
78
97
  end
@@ -43,7 +43,7 @@ module RuboCop
43
43
  end
44
44
 
45
45
  node.operator_method? || node.setter_method? || chained_calls?(node) ||
46
- operator_keyword?(node)
46
+ operator_keyword?(node) || node.first_argument.hash_type?
47
47
  end
48
48
 
49
49
  def first_argument_starts_with_left_parenthesis?(node)
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for redundant safe navigation calls.
7
+ # `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods
8
+ # are checked by default. These are customizable with `AllowedMethods` option.
9
+ #
10
+ # This cop is marked as unsafe, because auto-correction can change the
11
+ # return type of the expression. An offending expression that previously
12
+ # could return `nil` will be auto-corrected to never return `nil`.
13
+ #
14
+ # In the example below, the safe navigation operator (`&.`) is unnecessary
15
+ # because `NilClass` has methods like `respond_to?` and `is_a?`.
16
+ #
17
+ # @example
18
+ # # bad
19
+ # do_something if attrs&.respond_to?(:[])
20
+ #
21
+ # # good
22
+ # do_something if attrs.respond_to?(:[])
23
+ #
24
+ # # bad
25
+ # while node&.is_a?(BeginNode)
26
+ # node = node.parent
27
+ # end
28
+ #
29
+ # # good
30
+ # while node.is_a?(BeginNode)
31
+ # node = node.parent
32
+ # end
33
+ #
34
+ # # good - without `&.` this will always return `true`
35
+ # foo&.respond_to?(:to_a)
36
+ #
37
+ class RedundantSafeNavigation < Base
38
+ include AllowedMethods
39
+ include RangeHelp
40
+ extend AutoCorrector
41
+
42
+ MSG = 'Redundant safe navigation detected.'
43
+
44
+ NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
45
+
46
+ def_node_matcher :respond_to_nil_specific_method?, <<~PATTERN
47
+ (csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
48
+ PATTERN
49
+
50
+ def on_csend(node)
51
+ return unless check?(node) && allowed_method?(node.method_name)
52
+ return if respond_to_nil_specific_method?(node)
53
+
54
+ range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
55
+ add_offense(range) do |corrector|
56
+ corrector.replace(node.loc.dot, '.')
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def check?(node)
63
+ parent = node.parent
64
+ return false unless parent
65
+
66
+ condition?(parent, node) ||
67
+ parent.and_type? ||
68
+ parent.or_type? ||
69
+ (parent.send_type? && parent.negation_method?)
70
+ end
71
+
72
+ def condition?(parent, node)
73
+ (parent.conditional? || parent.post_condition_loop?) && parent.condition == node
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop ensures that `to_enum`/`enum_for`, called for the current method,
7
+ # has correct arguments.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # def method(x, y = 1)
12
+ # return to_enum(__method__, x) # `y` is missing
13
+ # end
14
+ #
15
+ # # good
16
+ # def method(x, y = 1)
17
+ # return to_enum(__method__, x, y)
18
+ # end
19
+ #
20
+ # # bad
21
+ # def method(required:)
22
+ # return to_enum(:method, required: something) # `required` has incorrect value
23
+ # end
24
+ #
25
+ # # good
26
+ # def method(required:)
27
+ # return to_enum(:method, required: required)
28
+ # end
29
+ #
30
+ class ToEnumArguments < Base
31
+ MSG = 'Ensure you correctly provided all the arguments.'
32
+
33
+ RESTRICT_ON_SEND = %i[to_enum enum_for].freeze
34
+
35
+ def_node_matcher :enum_conversion_call?, <<~PATTERN
36
+ (send {nil? self} {:to_enum :enum_for} $_ $...)
37
+ PATTERN
38
+
39
+ def_node_matcher :method_name?, <<~PATTERN
40
+ {(send nil? :__method__) (sym %1)}
41
+ PATTERN
42
+
43
+ def_node_matcher :passing_keyword_arg?, <<~PATTERN
44
+ (pair (sym %1) (lvar %1))
45
+ PATTERN
46
+
47
+ def on_send(node)
48
+ def_node = node.each_ancestor(:def, :defs).first
49
+ return unless def_node
50
+
51
+ enum_conversion_call?(node) do |method_node, arguments|
52
+ add_offense(node) unless method_name?(method_node, def_node.method_name) &&
53
+ arguments_match?(arguments, def_node)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def arguments_match?(arguments, def_node)
60
+ index = 0
61
+
62
+ def_node.arguments.reject(&:blockarg_type?).all? do |def_arg|
63
+ send_arg = arguments[index]
64
+ case def_arg.type
65
+ when :arg, :restarg, :optarg
66
+ index += 1
67
+ end
68
+
69
+ send_arg && argument_match?(send_arg, def_arg)
70
+ end
71
+ end
72
+
73
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
74
+ def argument_match?(send_arg, def_arg)
75
+ def_arg_name = def_arg.children[0]
76
+
77
+ case def_arg.type
78
+ when :arg, :restarg
79
+ send_arg.source == def_arg.source
80
+ when :optarg
81
+ send_arg.source == def_arg_name.to_s
82
+ when :kwoptarg, :kwarg
83
+ send_arg.hash_type? &&
84
+ send_arg.pairs.any? { |pair| passing_keyword_arg?(pair, def_arg_name) }
85
+ when :kwrestarg
86
+ send_arg.each_child_node(:kwsplat).any? { |child| child.source == def_arg.source }
87
+ when :forward_arg
88
+ send_arg.forwarded_args_type?
89
+ end
90
+ end
91
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
92
+ end
93
+ end
94
+ end
95
+ end
@@ -31,7 +31,7 @@ module RuboCop
31
31
  class ToJSON < Base
32
32
  extend AutoCorrector
33
33
 
34
- MSG = ' `#to_json` requires an optional argument to be parsable ' \
34
+ MSG = '`#to_json` requires an optional argument to be parsable ' \
35
35
  'via JSON.generate(obj).'
36
36
 
37
37
  def on_def(node)