rubocop 1.35.1 → 1.37.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +32 -1
  4. data/lib/rubocop/arguments_env.rb +17 -0
  5. data/lib/rubocop/arguments_file.rb +17 -0
  6. data/lib/rubocop/cli/command/execute_runner.rb +7 -7
  7. data/lib/rubocop/cop/generator.rb +1 -2
  8. data/lib/rubocop/cop/layout/block_alignment.rb +14 -12
  9. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
  10. data/lib/rubocop/cop/layout/indentation_width.rb +4 -2
  11. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
  12. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +25 -9
  13. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +28 -3
  14. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -2
  15. data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
  16. data/lib/rubocop/cop/lint/duplicate_methods.rb +11 -1
  17. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
  18. data/lib/rubocop/cop/lint/duplicate_require.rb +1 -1
  19. data/lib/rubocop/cop/lint/empty_class.rb +3 -1
  20. data/lib/rubocop/cop/lint/empty_conditional_body.rb +46 -4
  21. data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
  22. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  23. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
  24. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
  25. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +12 -1
  26. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
  27. data/lib/rubocop/cop/lint/redundant_require_statement.rb +29 -9
  28. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  29. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
  30. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  31. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +17 -2
  32. data/lib/rubocop/cop/lint/unreachable_loop.rb +2 -2
  33. data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
  34. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  35. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  36. data/lib/rubocop/cop/mixin/allowed_methods.rb +10 -5
  37. data/lib/rubocop/cop/mixin/allowed_pattern.rb +13 -5
  38. data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
  39. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
  40. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -3
  41. data/lib/rubocop/cop/mixin/hash_transform_method.rb +9 -5
  42. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
  43. data/lib/rubocop/cop/mixin/surrounding_space.rb +6 -5
  44. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
  45. data/lib/rubocop/cop/style/access_modifier_declarations.rb +97 -1
  46. data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
  47. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  48. data/lib/rubocop/cop/style/case_equality.rb +40 -10
  49. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  50. data/lib/rubocop/cop/style/collection_compact.rb +6 -1
  51. data/lib/rubocop/cop/style/each_for_simple_loop.rb +40 -5
  52. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  53. data/lib/rubocop/cop/style/endless_method.rb +1 -1
  54. data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
  55. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  56. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  57. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
  58. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
  59. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  60. data/lib/rubocop/cop/style/operator_method_call.rb +39 -0
  61. data/lib/rubocop/cop/style/perl_backrefs.rb +22 -1
  62. data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
  63. data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
  64. data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
  65. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  66. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
  67. data/lib/rubocop/cop/style/redundant_string_escape.rb +173 -0
  68. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  69. data/lib/rubocop/cop/style/static_class.rb +32 -1
  70. data/lib/rubocop/cop/style/symbol_array.rb +2 -0
  71. data/lib/rubocop/cop/style/symbol_proc.rb +6 -5
  72. data/lib/rubocop/cop/style/word_array.rb +2 -0
  73. data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
  74. data/lib/rubocop/options.rb +13 -13
  75. data/lib/rubocop/rspec/shared_contexts.rb +13 -1
  76. data/lib/rubocop/runner.rb +4 -0
  77. data/lib/rubocop/server/cache.rb +5 -1
  78. data/lib/rubocop/server/cli.rb +9 -2
  79. data/lib/rubocop/server/client_command/exec.rb +5 -0
  80. data/lib/rubocop/server/core.rb +2 -1
  81. data/lib/rubocop/server/socket_reader.rb +5 -1
  82. data/lib/rubocop/server.rb +1 -1
  83. data/lib/rubocop/version.rb +8 -2
  84. data/lib/rubocop.rb +3 -0
  85. metadata +10 -5
@@ -92,13 +92,17 @@ module RuboCop
92
92
  end
93
93
 
94
94
  def remove_empty_branch(corrector, node)
95
- corrector.remove(deletion_range(branch_range(node)))
95
+ if empty_if_branch?(node) && else_branch?(node)
96
+ corrector.remove(branch_range(node))
97
+ else
98
+ corrector.remove(deletion_range(branch_range(node)))
99
+ end
96
100
  end
97
101
 
98
102
  def correct_other_branches(corrector, node)
99
- return unless (node.if? || node.unless?) && node.else_branch
103
+ return unless require_other_branches_correction?(node)
100
104
 
101
- if node.else_branch.if_type?
105
+ if node.else_branch&.if_type?
102
106
  # Replace an orphaned `elsif` with `if`
103
107
  corrector.replace(node.else_branch.loc.keyword, 'if')
104
108
  else
@@ -107,13 +111,51 @@ module RuboCop
107
111
  end
108
112
  end
109
113
 
114
+ def require_other_branches_correction?(node)
115
+ return false unless node.if_type? && node.else?
116
+ return false if !empty_if_branch?(node) && node.elsif?
117
+
118
+ !empty_elsif_branch?(node)
119
+ end
120
+
121
+ def empty_if_branch?(node)
122
+ return false unless (parent = node.parent)
123
+ return true unless parent.if_type?
124
+ return true unless (if_branch = parent.if_branch)
125
+
126
+ if_branch.if_type? && !if_branch.body
127
+ end
128
+
129
+ def empty_elsif_branch?(node)
130
+ return false unless (else_branch = node.else_branch)
131
+
132
+ else_branch.if_type? && !else_branch.body
133
+ end
134
+
135
+ def else_branch?(node)
136
+ node.else_branch && !node.else_branch.if_type?
137
+ end
138
+
139
+ # rubocop:disable Metrics/AbcSize
110
140
  def branch_range(node)
111
- if node.loc.else
141
+ if empty_if_branch?(node) && else_branch?(node)
142
+ node.source_range.with(end_pos: node.loc.else.begin_pos)
143
+ elsif node.loc.else
112
144
  node.source_range.with(end_pos: node.loc.else.begin_pos - 1)
145
+ elsif all_branches_body_missing?(node)
146
+ if_node = node.ancestors.detect(&:if?)
147
+ node.source_range.with(end_pos: if_node.loc.end.end_pos)
113
148
  else
114
149
  node.source_range
115
150
  end
116
151
  end
152
+ # rubocop:enable Metrics/AbcSize
153
+
154
+ def all_branches_body_missing?(node)
155
+ return false unless node.parent&.if_type?
156
+
157
+ node.parent.branches.compact.empty?
158
+ end
117
159
 
118
160
  def deletion_range(range)
119
161
  # Collect a range between the start of the `if` node and the next relevant node,
@@ -30,6 +30,9 @@ module RuboCop
30
30
  #
31
31
  # # good
32
32
  #
33
+ # # `class_eval`, `instance_eval`, `module_eval`, `class_exec`, `instance_exec`, and
34
+ # # `module_exec` blocks are allowed by default.
35
+ #
33
36
  # def foo
34
37
  # self.class.class_eval do
35
38
  # def bar
@@ -54,7 +57,47 @@ module RuboCop
54
57
  # end
55
58
  # end
56
59
  # end
60
+ #
61
+ # @example AllowedMethods: [] (default)
62
+ # # bad
63
+ # def do_something
64
+ # has_many :articles do
65
+ # def find_or_create_by_name(name)
66
+ # end
67
+ # end
68
+ # end
69
+ #
70
+ # @example AllowedMethods: ['has_many']
71
+ # # bad
72
+ # def do_something
73
+ # has_many :articles do
74
+ # def find_or_create_by_name(name)
75
+ # end
76
+ # end
77
+ # end
78
+ #
79
+ # @example AllowedPatterns: [] (default)
80
+ # # bad
81
+ # def foo(obj)
82
+ # obj.do_baz do
83
+ # def bar
84
+ # end
85
+ # end
86
+ # end
87
+ #
88
+ # @example AllowedPatterns: ['baz']
89
+ # # good
90
+ # def foo(obj)
91
+ # obj.do_baz do
92
+ # def bar
93
+ # end
94
+ # end
95
+ # end
96
+ #
57
97
  class NestedMethodDefinition < Base
98
+ include AllowedMethods
99
+ include AllowedPattern
100
+
58
101
  MSG = 'Method definitions must not be nested. Use `lambda` instead.'
59
102
 
60
103
  def on_def(node)
@@ -77,7 +120,13 @@ module RuboCop
77
120
 
78
121
  def scoping_method_call?(child)
79
122
  child.sclass_type? || eval_call?(child) || exec_call?(child) ||
80
- class_or_module_or_struct_new_call?(child)
123
+ class_or_module_or_struct_new_call?(child) || allowed_method_name?(child)
124
+ end
125
+
126
+ def allowed_method_name?(node)
127
+ name = node.method_name
128
+
129
+ allowed_method?(name) || matches_allowed_pattern?(name)
81
130
  end
82
131
 
83
132
  # @!method eval_call?(node)
@@ -61,7 +61,7 @@ module RuboCop
61
61
  # # bad
62
62
  # 10.minutes.to_i
63
63
  #
64
- # @example AllowedPatterns: [/min*/]
64
+ # @example AllowedPatterns: ['min*']
65
65
  #
66
66
  # # good
67
67
  # 10.minutes.to_i
@@ -7,6 +7,9 @@ module RuboCop
7
7
  # Checks the proper ordering of magic comments and whether
8
8
  # a magic comment is not placed before a shebang.
9
9
  #
10
+ # @safety
11
+ # This cop's autocorrection is unsafe because file encoding may change.
12
+ #
10
13
  # @example
11
14
  # # bad
12
15
  #
@@ -61,7 +64,7 @@ module RuboCop
61
64
  def magic_comment_lines
62
65
  lines = [nil, nil]
63
66
 
64
- magic_comments.each.with_index do |comment, index|
67
+ leading_magic_comments.each.with_index do |comment, index|
65
68
  if comment.encoding_specified?
66
69
  lines[0] = index
67
70
  elsif comment.frozen_string_literal_specified?
@@ -73,10 +76,6 @@ module RuboCop
73
76
 
74
77
  lines
75
78
  end
76
-
77
- def magic_comments
78
- leading_comment_lines.map { |line| MagicComment.parse(line) }
79
- end
80
79
  end
81
80
  end
82
81
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # This cops looks for references of Regexp captures that are out of range
6
+ # Looks for references of Regexp captures that are out of range
7
7
  # and thus always returns nil.
8
8
  #
9
9
  # @safety
@@ -209,7 +209,12 @@ module RuboCop
209
209
 
210
210
  add_offense(location, message: message(cop_names)) do |corrector|
211
211
  range = comment_range_with_surrounding_space(location, comment.loc.expression)
212
- corrector.remove(range)
212
+
213
+ if leave_free_comment?(comment, range)
214
+ corrector.replace(range, ' # ')
215
+ else
216
+ corrector.remove(range)
217
+ end
213
218
  end
214
219
  end
215
220
 
@@ -227,6 +232,12 @@ module RuboCop
227
232
  end
228
233
  end
229
234
 
235
+ def leave_free_comment?(comment, range)
236
+ free_comment = comment.text.gsub(range.source.strip, '')
237
+
238
+ !free_comment.empty? && !free_comment.start_with?('#')
239
+ end
240
+
230
241
  def cop_range(comment, cop)
231
242
  cop = remove_department_marker(cop)
232
243
  matching_range(comment.loc.expression, cop) ||
@@ -41,6 +41,7 @@ module RuboCop
41
41
  return unless (receiver = node.receiver)
42
42
  return unless receiver.receiver&.const_type? && receiver.receiver.short_name == :Dir
43
43
  return unless GLOB_METHODS.include?(receiver.method_name)
44
+ return if multiple_argument?(receiver)
44
45
 
45
46
  selector = node.loc.selector
46
47
 
@@ -49,6 +50,12 @@ module RuboCop
49
50
  corrector.remove(node.loc.dot)
50
51
  end
51
52
  end
53
+
54
+ private
55
+
56
+ def multiple_argument?(glob_method)
57
+ glob_method.arguments.count >= 2 || glob_method.first_argument&.splat_type?
58
+ end
52
59
  end
53
60
  end
54
61
  end
@@ -6,13 +6,22 @@ module RuboCop
6
6
  # Checks for unnecessary `require` statement.
7
7
  #
8
8
  # The following features are unnecessary `require` statement because
9
- # they are already loaded.
9
+ # they are already loaded. e.g. Ruby 2.2:
10
10
  #
11
11
  # ruby -ve 'p $LOADED_FEATURES.reject { |feature| %r|/| =~ feature }'
12
12
  # ruby 2.2.8p477 (2017-09-14 revision 59906) [x86_64-darwin13]
13
13
  # ["enumerator.so", "rational.so", "complex.so", "thread.rb"]
14
14
  #
15
- # This cop targets Ruby 2.2 or higher containing these 4 features.
15
+ # Below are the features that each `TargetRubyVersion` targets.
16
+ #
17
+ # * 2.0+ ... `enumerator`
18
+ # * 2.1+ ... `thread`
19
+ # * 2.2+ ... Add `rational` and `complex` above
20
+ # * 2.5+ ... Add `pp` above
21
+ # * 2.7+ ... Add `ruby2_keywords` above
22
+ # * 3.1+ ... Add `fiber` above
23
+ #
24
+ # This cop target those features.
16
25
  #
17
26
  # @example
18
27
  # # bad
@@ -24,21 +33,19 @@ module RuboCop
24
33
  class RedundantRequireStatement < Base
25
34
  include RangeHelp
26
35
  extend AutoCorrector
27
- extend TargetRubyVersion
28
-
29
- minimum_target_ruby_version 2.2
30
36
 
31
37
  MSG = 'Remove unnecessary `require` statement.'
32
38
  RESTRICT_ON_SEND = %i[require].freeze
39
+ RUBY_22_LOADED_FEATURES = %w[rational complex].freeze
33
40
 
34
- # @!method unnecessary_require_statement?(node)
35
- def_node_matcher :unnecessary_require_statement?, <<~PATTERN
41
+ # @!method redundant_require_statement?(node)
42
+ def_node_matcher :redundant_require_statement?, <<~PATTERN
36
43
  (send nil? :require
37
- (str {"enumerator" "rational" "complex" "thread"}))
44
+ (str #redundant_feature?))
38
45
  PATTERN
39
46
 
40
47
  def on_send(node)
41
- return unless unnecessary_require_statement?(node)
48
+ return unless redundant_require_statement?(node)
42
49
 
43
50
  add_offense(node) do |corrector|
44
51
  range = range_with_surrounding_space(node.loc.expression, side: :right)
@@ -46,6 +53,19 @@ module RuboCop
46
53
  corrector.remove(range)
47
54
  end
48
55
  end
56
+
57
+ private
58
+
59
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
60
+ def redundant_feature?(feature_name)
61
+ feature_name == 'enumerator' ||
62
+ (target_ruby_version >= 2.1 && feature_name == 'thread') ||
63
+ (target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
64
+ (target_ruby_version >= 2.5 && feature_name == 'pp') ||
65
+ (target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
66
+ (target_ruby_version >= 3.1 && feature_name == 'fiber')
67
+ end
68
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
49
69
  end
50
70
  end
51
71
  end
@@ -46,7 +46,7 @@ module RuboCop
46
46
  private
47
47
 
48
48
  def check_ternary(ternary, node)
49
- return unless ternary.condition.operator_keyword?
49
+ return if node.method?(:[]) || !ternary.condition.operator_keyword?
50
50
 
51
51
  range = range_between(node.source_range.begin_pos, ternary.condition.source_range.end_pos)
52
52
 
@@ -31,6 +31,7 @@ module RuboCop
31
31
  minimum_target_ruby_version 2.3
32
32
 
33
33
  MSG = 'Do not chain ordinary method call after safe navigation operator.'
34
+ PLUS_MINUS_METHODS = %i[+@ -@].freeze
34
35
 
35
36
  # @!method bad_method?(node)
36
37
  def_node_matcher :bad_method?, <<~PATTERN
@@ -42,7 +43,7 @@ module RuboCop
42
43
 
43
44
  def on_send(node)
44
45
  bad_method?(node) do |safe_nav, method|
45
- return if nil_methods.include?(method)
46
+ return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
46
47
 
47
48
  method_chain = method_chain(node)
48
49
  location =
@@ -71,7 +72,7 @@ module RuboCop
71
72
  else
72
73
  offense_range.source.dup
73
74
  end
74
- source.prepend('.') unless send_node.dot?
75
+ source.prepend('.') unless source.start_with?('.')
75
76
  source.prepend('&')
76
77
  end
77
78
 
@@ -12,7 +12,7 @@ module RuboCop
12
12
  # same `rescue` statement. In both cases, the more specific rescue is
13
13
  # unnecessary because it is covered by rescuing the less specific
14
14
  # exception. (ie. `rescue Exception, StandardError` has the same behavior
15
- # whether `StandardError` is included or not, because all `StandardError`s
15
+ # whether `StandardError` is included or not, because all ``StandardError``s
16
16
  # are rescued by `rescue Exception`).
17
17
  #
18
18
  # @example
@@ -155,16 +155,6 @@ module RuboCop
155
155
  end
156
156
  end
157
157
 
158
- # @param [RuboCop::AST::Node] rescue_group is a node of array_type
159
- def rescued_exceptions(rescue_group)
160
- klasses = *rescue_group
161
- klasses.map do |klass|
162
- next unless klass.const_type?
163
-
164
- klass.source
165
- end.compact
166
- end
167
-
168
158
  def find_shadowing_rescue(rescues)
169
159
  rescued_groups = rescued_groups_for(rescues)
170
160
  rescued_groups.zip(rescues).each do |group, res|
@@ -12,9 +12,12 @@ module RuboCop
12
12
  # because `Ractor` should not access outer variables.
13
13
  # eg. following style is encouraged:
14
14
  #
15
+ # [source,ruby]
16
+ # ----
15
17
  # worker_id, pipe = env
16
18
  # Ractor.new(worker_id, pipe) do |worker_id, pipe|
17
19
  # end
20
+ # ----
18
21
  #
19
22
  # @example
20
23
  #
@@ -64,14 +67,26 @@ module RuboCop
64
67
  end
65
68
 
66
69
  def same_conditions_node_different_branch?(variable, outer_local_variable)
67
- variable_node = variable.scope.node.parent
70
+ variable_node = variable_node(variable)
68
71
  return false unless variable_node.conditional?
69
72
 
70
73
  outer_local_variable_node =
71
74
  find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
72
75
  return true unless outer_local_variable_node
73
76
 
74
- outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
77
+ outer_local_variable_node.conditional? &&
78
+ (variable_node == outer_local_variable_node ||
79
+ variable_node == outer_local_variable_node.else_branch)
80
+ end
81
+
82
+ def variable_node(variable)
83
+ parent_node = variable.scope.node.parent
84
+
85
+ if parent_node.when_type?
86
+ parent_node.parent
87
+ else
88
+ parent_node
89
+ end
75
90
  end
76
91
 
77
92
  def find_conditional_node_from_ascendant(node)
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # In rare cases where only one iteration (or at most one iteration) is intended behavior,
10
10
  # the code should be refactored to use `if` conditionals.
11
11
  #
12
- # NOTE: Block methods that are used with `Enumerable`s are considered to be loops.
12
+ # NOTE: Block methods that are used with ``Enumerable``s are considered to be loops.
13
13
  #
14
14
  # `AllowedPatterns` can be used to match against the block receiver in order to allow
15
15
  # code that would otherwise be registered as an offense (eg. `times` used not in an
@@ -79,7 +79,7 @@ module RuboCop
79
79
  # # bad
80
80
  # 2.times { raise ArgumentError }
81
81
  #
82
- # @example AllowedPatterns: [/(exactly|at_least|at_most)\(\d+\)\.times/] (default)
82
+ # @example AllowedPatterns: ['(exactly|at_least|at_most)\(\d+\)\.times'] (default)
83
83
  #
84
84
  # # good
85
85
  # exactly(2).times { raise StandardError }
@@ -68,6 +68,10 @@ module RuboCop
68
68
  (send nil? :fail ...)}
69
69
  PATTERN
70
70
 
71
+ def self.autocorrect_incompatible_with
72
+ [Style::ExplicitBlockArgument]
73
+ end
74
+
71
75
  def self.joining_forces
72
76
  VariableForce
73
77
  end
@@ -31,8 +31,8 @@ module RuboCop
31
31
  # # bad
32
32
  # class Foo
33
33
  # # The following is redundant (methods defined on the class'
34
- # # singleton class are not affected by the public modifier)
35
- # public
34
+ # # singleton class are not affected by the private modifier)
35
+ # private
36
36
  #
37
37
  # def self.method3
38
38
  # end
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Looks for `ruby2_keywords` calls for methods that do not need it.
7
7
  #
8
8
  # `ruby2_keywords` should only be called on methods that accept an argument splat
9
- # (`*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
9
+ # (`\*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
10
10
  # a keyword splat (`**kwargs`).
11
11
  #
12
12
  # @example
@@ -17,16 +17,21 @@ module RuboCop
17
17
 
18
18
  # @api public
19
19
  def allowed_methods
20
- deprecated_values = cop_config_deprecated_values
21
- if deprecated_values.any?(Regexp)
22
- cop_config.fetch('AllowedMethods', [])
20
+ if cop_config_deprecated_values.any?(Regexp)
21
+ cop_config_allowed_methods
23
22
  else
24
- Array(cop_config['AllowedMethods']).concat(deprecated_values)
23
+ cop_config_allowed_methods + cop_config_deprecated_values
25
24
  end
26
25
  end
27
26
 
27
+ def cop_config_allowed_methods
28
+ @cop_config_allowed_methods ||= Array(cop_config.fetch('AllowedMethods', []))
29
+ end
30
+
28
31
  def cop_config_deprecated_values
29
- Array(cop_config['IgnoredMethods']).concat(Array(cop_config['ExcludedMethods']))
32
+ @cop_config_deprecated_values ||=
33
+ Array(cop_config.fetch('IgnoredMethods', [])) +
34
+ Array(cop_config.fetch('ExcludedMethods', []))
30
35
  end
31
36
  end
32
37
  # @deprecated IgnoredMethods class has been replaced with AllowedMethods.
@@ -30,15 +30,23 @@ module RuboCop
30
30
  def allowed_patterns
31
31
  # Since there could be a pattern specified in the default config, merge the two
32
32
  # arrays together.
33
- patterns = Array(cop_config['AllowedPatterns']).concat(Array(cop_config['IgnoredPatterns']))
34
- deprecated_values = cop_config_deprecated_methods_values
35
- return patterns unless deprecated_values.any?(Regexp)
33
+ if cop_config_deprecated_methods_values.any?(Regexp)
34
+ cop_config_patterns_values + cop_config_deprecated_methods_values
35
+ else
36
+ cop_config_patterns_values
37
+ end
38
+ end
36
39
 
37
- Array(patterns.concat(deprecated_values))
40
+ def cop_config_patterns_values
41
+ @cop_config_patterns_values ||=
42
+ Array(cop_config.fetch('AllowedPatterns', [])) +
43
+ Array(cop_config.fetch('IgnoredPatterns', []))
38
44
  end
39
45
 
40
46
  def cop_config_deprecated_methods_values
41
- Array(cop_config['IgnoredMethods']).concat(Array(cop_config['ExcludedMethods']))
47
+ @cop_config_deprecated_methods_values ||=
48
+ Array(cop_config.fetch('IgnoredMethods', [])) +
49
+ Array(cop_config.fetch('ExcludedMethods', []))
42
50
  end
43
51
  end
44
52
 
@@ -22,6 +22,18 @@ module RuboCop
22
22
  processed_source.each_comment_in_lines(start_line...end_line)
23
23
  end
24
24
 
25
+ def comments_contain_disables?(node, cop_name)
26
+ disabled_ranges = processed_source.disabled_line_ranges[cop_name]
27
+
28
+ return unless disabled_ranges
29
+
30
+ node_range = node.source_range.line...find_end_line(node)
31
+
32
+ disabled_ranges.any? do |disable_range|
33
+ disable_range.cover?(node_range) || node_range.cover?(disable_range)
34
+ end
35
+ end
36
+
25
37
  private
26
38
 
27
39
  def end_position_for(node)
@@ -69,6 +69,10 @@ module RuboCop
69
69
  end
70
70
  end
71
71
 
72
+ def leading_magic_comments
73
+ leading_comment_lines.map { |line| MagicComment.parse(line) }
74
+ end
75
+
72
76
  def leading_comment_lines
73
77
  first_non_comment_token = processed_source.tokens.find { |token| !token.comment? }
74
78
 
@@ -96,11 +96,14 @@ module RuboCop
96
96
  end
97
97
 
98
98
  def without_parentheses_call_expr_follows?(ancestor)
99
+ return false unless ancestor.respond_to?(:parenthesized?) && !ancestor.parenthesized?
100
+
99
101
  right_sibling = ancestor.right_sibling
100
- right_sibling ||= ancestor.each_ancestor.find(&:assignment?)&.right_sibling
101
- return false unless right_sibling
102
+ right_sibling ||= ancestor.each_ancestor.find do |node|
103
+ node.assignment? || node.send_type?
104
+ end&.right_sibling
102
105
 
103
- ancestor.respond_to?(:parenthesized?) && !ancestor.parenthesized? && !!right_sibling
106
+ !!right_sibling
104
107
  end
105
108
 
106
109
  def breakdown_value_types_of_hash(hash_node)
@@ -68,6 +68,8 @@ module RuboCop
68
68
  # `transform_values` if value transformation uses key.
69
69
  return if captures.transformation_uses_both_args?
70
70
 
71
+ return unless captures.use_transformed_argname?
72
+
71
73
  message = "Prefer `#{new_method_name}` over `#{match_desc}`."
72
74
  add_offense(node, message: message) do |corrector|
73
75
  correction = prepare_correction(node)
@@ -113,11 +115,7 @@ module RuboCop
113
115
  end
114
116
 
115
117
  # Internal helper class to hold match data
116
- Captures = Struct.new(
117
- :transformed_argname,
118
- :transforming_body_expr,
119
- :unchanged_body_expr
120
- ) do
118
+ Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
121
119
  def noop_transformation?
122
120
  transforming_body_expr.lvar_type? &&
123
121
  transforming_body_expr.children == [transformed_argname]
@@ -126,6 +124,12 @@ module RuboCop
126
124
  def transformation_uses_both_args?
127
125
  transforming_body_expr.descendants.include?(unchanged_body_expr)
128
126
  end
127
+
128
+ def use_transformed_argname?
129
+ transforming_body_expr.each_descendant(:lvar).any? do |node|
130
+ node.source == transformed_argname.to_s
131
+ end
132
+ end
129
133
  end
130
134
 
131
135
  # Internal helper class to hold autocorrect data
@@ -11,7 +11,9 @@ module RuboCop
11
11
  private
12
12
 
13
13
  def rescue_modifier?(node)
14
- node&.resbody_type? && @modifier_locations.include?(node.loc.keyword)
14
+ return false unless node.respond_to?(:resbody_type?)
15
+
16
+ node.resbody_type? && @modifier_locations.include?(node.loc.keyword)
15
17
  end
16
18
 
17
19
  # @deprecated Use ResbodyNode#exceptions instead
@@ -13,7 +13,7 @@ module RuboCop
13
13
 
14
14
  private
15
15
 
16
- def side_space_range(range:, side:)
16
+ def side_space_range(range:, side:, include_newlines: false)
17
17
  buffer = processed_source.buffer
18
18
  src = buffer.source
19
19
 
@@ -21,11 +21,11 @@ module RuboCop
21
21
  end_pos = range.end_pos
22
22
  if side == :left
23
23
  end_pos = begin_pos
24
- begin_pos = reposition(src, begin_pos, -1)
24
+ begin_pos = reposition(src, begin_pos, -1, include_newlines: include_newlines)
25
25
  end
26
26
  if side == :right
27
27
  begin_pos = end_pos
28
- end_pos = reposition(src, end_pos, 1)
28
+ end_pos = reposition(src, end_pos, 1, include_newlines: include_newlines)
29
29
  end
30
30
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
31
31
  end
@@ -75,9 +75,10 @@ module RuboCop
75
75
  end
76
76
  end
77
77
 
78
- def reposition(src, pos, step)
78
+ def reposition(src, pos, step, include_newlines: false)
79
79
  offset = step == -1 ? -1 : 0
80
- pos += step while SINGLE_SPACE_REGEXP.match?(src[pos + offset])
80
+ pos += step while SINGLE_SPACE_REGEXP.match?(src[pos + offset]) ||
81
+ (include_newlines && src[pos + offset] == "\n")
81
82
  pos.negative? ? 0 : pos
82
83
  end
83
84