rubocop 1.86.2 → 1.87.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +7 -0
  3. data/lib/rubocop/cli.rb +2 -0
  4. data/lib/rubocop/config_loader.rb +17 -2
  5. data/lib/rubocop/config_loader_resolver.rb +11 -3
  6. data/lib/rubocop/config_store.rb +1 -1
  7. data/lib/rubocop/cop/base.rb +8 -2
  8. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
  9. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  10. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  11. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  12. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  13. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  14. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +14 -5
  15. data/lib/rubocop/cop/layout/end_alignment.rb +2 -2
  16. data/lib/rubocop/cop/layout/indentation_width.rb +13 -1
  17. data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
  18. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
  19. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  20. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  21. data/lib/rubocop/cop/lint/constant_reassignment.rb +36 -4
  22. data/lib/rubocop/cop/lint/constant_resolution.rb +5 -5
  23. data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
  24. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  25. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
  26. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  27. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  28. data/lib/rubocop/cop/lint/number_conversion.rb +5 -5
  29. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  30. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  31. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -2
  32. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
  33. data/lib/rubocop/cop/lint/require_relative_self_path.rb +1 -1
  34. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  35. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
  36. data/lib/rubocop/cop/lint/unreachable_code.rb +2 -2
  37. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  38. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  39. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  40. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  41. data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
  42. data/lib/rubocop/cop/mixin.rb +1 -0
  43. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  44. data/lib/rubocop/cop/naming/predicate_method.rb +2 -2
  45. data/lib/rubocop/cop/naming/predicate_prefix.rb +1 -1
  46. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  47. data/lib/rubocop/cop/registry.rb +28 -6
  48. data/lib/rubocop/cop/security/io_methods.rb +1 -1
  49. data/lib/rubocop/cop/style/alias.rb +10 -1
  50. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  51. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -0
  52. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
  53. data/lib/rubocop/cop/style/file_write.rb +18 -16
  54. data/lib/rubocop/cop/style/format_string.rb +4 -3
  55. data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
  56. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  57. data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
  58. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  59. data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
  60. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
  61. data/lib/rubocop/cop/style/regexp_literal.rb +2 -2
  62. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
  63. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  64. data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
  65. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
  66. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  67. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  68. data/lib/rubocop/file_patterns.rb +9 -1
  69. data/lib/rubocop/options.rb +18 -0
  70. data/lib/rubocop/project_index_loader.rb +66 -0
  71. data/lib/rubocop/runner.rb +47 -3
  72. data/lib/rubocop/version.rb +20 -2
  73. data/lib/rubocop.rb +1 -0
  74. metadata +5 -3
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for Regexpes (both literals and via `Regexp.new` / `Regexp.compile`)
6
+ # Checks for Regexps (both literals and via `Regexp.new` / `Regexp.compile`)
7
7
  # that contain unescaped `]` characters.
8
8
  #
9
9
  # It emulates the following Ruby warning:
@@ -4,8 +4,8 @@ module RuboCop
4
4
  module Cop
5
5
  module Lint
6
6
  # Checks for unreachable code.
7
- # The check are based on the presence of flow of control
8
- # statement in non-final position in `begin` (implicit) blocks.
7
+ # The check is based on the presence of flow-of-control
8
+ # statements in non-final position in `begin` (implicit) blocks.
9
9
  #
10
10
  # @example
11
11
  #
@@ -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 have explicit keyword arguments (`k:` or `k: true`) or
10
10
  # a keyword splat (`**kwargs`).
11
11
  #
12
12
  # @example
@@ -17,7 +17,7 @@ module RuboCop
17
17
  #
18
18
  # NOTE: The `ExcludedMethods` configuration is deprecated and only kept
19
19
  # for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns`
20
- # instead. By default, there are no methods to allowed.
20
+ # instead. By default, there are no allowed methods.
21
21
  #
22
22
  # @example CountAsOne: ['array', 'hash', 'heredoc', 'method_call']
23
23
  #
@@ -15,7 +15,7 @@ module RuboCop
15
15
  # NOTE: The `ExcludedMethods` and `IgnoredMethods` configuration is
16
16
  # deprecated and only kept for backwards compatibility.
17
17
  # Please use `AllowedMethods` and `AllowedPatterns` instead.
18
- # By default, there are no methods to allowed.
18
+ # By default, there are no allowed methods.
19
19
  #
20
20
  # @example CountAsOne: ['array', 'hash', 'heredoc', 'method_call']
21
21
  #
@@ -43,7 +43,7 @@ module RuboCop
43
43
  end
44
44
  end
45
45
 
46
- # Returns true iff name is a known iterating type (e.g. :each, :transform_values)
46
+ # Returns true only when name is a known iterating type (e.g. :each, :transform_values).
47
47
  def iterating_method?(name)
48
48
  KNOWN_ITERATING_METHODS.include? name
49
49
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common helpers for cops that consult the project-wide static-analysis index
6
+ # via `Cop::Base#project_index`.
7
+ #
8
+ # Mixed-in cops gain the `external_dependency_checksum` override that invalidates
9
+ # the `ResultCache` whenever the indexed project files change on disk.
10
+ # To run index-backed analysis, cops should simply check whether `project_index` is non-nil;
11
+ # the runner only exposes a non-nil index when the user opted in via `AllCops/UseProjectIndex`
12
+ # and the underlying gem is available.
13
+ module ProjectIndexHelp
14
+ BUILTIN_DOCUMENT_URI = 'rubydex:built-in'
15
+ FILE_URI_PREFIX = 'file://'
16
+ # Matches the spurious leading slash before a Windows drive letter that
17
+ # remains after stripping `file://` from a `file:///C:/...` URI.
18
+ WINDOWS_DRIVE_PREFIX = %r{\A/(?=[A-Za-z]:[/\\])}.freeze
19
+
20
+ def external_dependency_checksum
21
+ return nil unless project_index
22
+
23
+ @external_dependency_checksum ||= Digest::SHA1.hexdigest(
24
+ project_index_signature.join("\n")
25
+ )
26
+ end
27
+
28
+ private
29
+
30
+ def project_index_signature
31
+ project_index.documents.filter_map do |doc|
32
+ uri = doc.uri
33
+ next if uri == BUILTIN_DOCUMENT_URI
34
+
35
+ path = uri.delete_prefix(FILE_URI_PREFIX).sub(WINDOWS_DRIVE_PREFIX, '')
36
+ mtime, size = begin
37
+ stat = File.stat(path)
38
+ [stat.mtime.to_f, stat.size]
39
+ rescue StandardError
40
+ [0, 0]
41
+ end
42
+
43
+ "#{path}:#{mtime}:#{size}"
44
+ end.sort
45
+ end
46
+ end
47
+ end
48
+ end
@@ -28,6 +28,7 @@ module RuboCop
28
28
  autoload :DocumentationComment, 'rubocop/cop/mixin/documentation_comment'
29
29
  autoload :Duplication, 'rubocop/cop/mixin/duplication'
30
30
  autoload :RangeHelp, 'rubocop/cop/mixin/range_help'
31
+ autoload :ProjectIndexHelp, 'rubocop/cop/mixin/project_index_help'
31
32
  autoload :AnnotationComment, 'rubocop/cop/mixin/annotation_comment'
32
33
  autoload :EmptyParameter, 'rubocop/cop/mixin/empty_parameter'
33
34
  autoload :EndKeywordAlignment, 'rubocop/cop/mixin/end_keyword_alignment'
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Naming
6
6
  # Makes sure that certain binary operator methods have their
7
- # sole parameter named `other`.
7
+ # sole parameter named `other`.
8
8
  #
9
9
  # @example
10
10
  #
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks that predicate methods end with `?` and non-predicate methods do not.
7
7
  #
8
8
  # The names of predicate methods (methods that return a boolean value) should end
9
- # in a question mark. Methods that don't return a boolean, shouldn't
9
+ # in a question mark. Methods that don't return a boolean shouldn't
10
10
  # end in a question mark.
11
11
  #
12
12
  # The cop assesses a predicate method as one that returns boolean values. Likewise,
@@ -22,7 +22,7 @@ module RuboCop
22
22
  # return values are detected.
23
23
  #
24
24
  # The cop also has `AllowedMethods` configuration in order to prevent the cop from
25
- # registering an offense from a method name that does not confirm to the naming
25
+ # registering an offense from a method name that does not conform to the naming
26
26
  # guidelines. By default, `call` is allowed. The cop also has `AllowedPatterns`
27
27
  # configuration to allow method names by regular expression.
28
28
  #
@@ -17,7 +17,7 @@ module RuboCop
17
17
  # they end with a `?`. These methods should be changed to remove the
18
18
  # prefix.
19
19
  #
20
- # When `UseSorbetSigs` set to true (optional), the cop will only report
20
+ # When `UseSorbetSigs` is set to true (optional), the cop will only report
21
21
  # offenses if the method has a Sorbet `sig` with a return type of
22
22
  # `T::Boolean`. Dynamic methods are not supported with this configuration.
23
23
  #
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # Makes sure that rescued exceptions variables are named as
6
+ # Makes sure that rescued exception variables are named as
7
7
  # expected.
8
8
  #
9
9
  # The `PreferredName` config option takes a `String`. It represents
@@ -51,6 +51,7 @@ module RuboCop
51
51
  def initialize(cops = [], options = {})
52
52
  @departments = Set.new
53
53
  @cops_by_badge = {}
54
+ @lazy_loaded_cops_by_badge = {}
54
55
 
55
56
  @enrollment_queue = cops
56
57
  @options = options
@@ -60,6 +61,12 @@ module RuboCop
60
61
  @warnings = {}
61
62
  end
62
63
 
64
+ def lazy_load(cop_name, constant_name)
65
+ badge = Badge.parse(cop_name)
66
+ @departments << badge.department
67
+ @lazy_loaded_cops_by_badge[badge] = constant_name
68
+ end
69
+
63
70
  def enlist(cop)
64
71
  @enrollment_queue << cop
65
72
  end
@@ -154,8 +161,8 @@ module RuboCop
154
161
  def unqualified_cop_names
155
162
  clear_enrollment_queue
156
163
  @unqualified_cop_names ||=
157
- Set.new(@cops_by_badge.keys.map { |badge| File.basename(badge.to_s) }) <<
158
- 'RedundantCopDisableDirective'
164
+ (@cops_by_badge.keys | @lazy_loaded_cops_by_badge.keys)
165
+ .to_set { |badge| File.basename(badge.to_s) } << 'RedundantCopDisableDirective'
159
166
  end
160
167
 
161
168
  def qualify_badge(badge)
@@ -168,17 +175,19 @@ module RuboCop
168
175
  # @return [Hash{String => Array<Class>}]
169
176
  def to_h
170
177
  clear_enrollment_queue
178
+ load_all_lazy_cops
171
179
  @cops_by_badge.to_h { |_badge, cop| [cop.cop_name, [cop]] }
172
180
  end
173
181
 
174
182
  def cops
175
183
  clear_enrollment_queue
184
+ load_all_lazy_cops
176
185
  @cops_by_badge.values
177
186
  end
178
187
 
179
188
  def length
180
189
  clear_enrollment_queue
181
- @cops_by_badge.size
190
+ @cops_by_badge.size + @lazy_loaded_cops_by_badge.size
182
191
  end
183
192
 
184
193
  def enabled(config)
@@ -214,7 +223,7 @@ module RuboCop
214
223
 
215
224
  def names
216
225
  clear_enrollment_queue
217
- @cops_by_badge.keys.map(&:to_s)
226
+ @cops_by_badge.keys.map(&:to_s) | @lazy_loaded_cops_by_badge.keys.map(&:to_s)
218
227
  end
219
228
 
220
229
  def cops_for_department(department)
@@ -231,6 +240,7 @@ module RuboCop
231
240
 
232
241
  def sort!
233
242
  clear_enrollment_queue
243
+ load_all_lazy_cops
234
244
  @cops_by_badge = @cops_by_badge.sort_by { |badge, _cop| badge.cop_name }.to_h
235
245
 
236
246
  self
@@ -249,7 +259,7 @@ module RuboCop
249
259
  def find_by_cop_name(cop_name)
250
260
  clear_enrollment_queue
251
261
  badge = Badge.parse(cop_name)
252
- @cops_by_badge[badge]
262
+ @cops_by_badge[badge] || load_lazy_cop(badge)
253
263
  end
254
264
 
255
265
  # When a cop name is given returns a single-element array with the cop class.
@@ -262,6 +272,7 @@ module RuboCop
262
272
 
263
273
  def freeze
264
274
  clear_enrollment_queue
275
+ load_all_lazy_cops
265
276
  unqualified_cop_names # build cache
266
277
  super
267
278
  end
@@ -292,6 +303,17 @@ module RuboCop
292
303
  @enrollment_queue = []
293
304
  end
294
305
 
306
+ def load_all_lazy_cops
307
+ @lazy_loaded_cops_by_badge.each_key { |badge| load_lazy_cop(badge) }
308
+ end
309
+
310
+ def load_lazy_cop(badge)
311
+ constant_name = @lazy_loaded_cops_by_badge.delete(badge)
312
+ return unless constant_name
313
+
314
+ @cops_by_badge[badge] = Kernel.const_get(constant_name)
315
+ end
316
+
295
317
  def with(cops)
296
318
  self.class.new(cops)
297
319
  end
@@ -313,7 +335,7 @@ module RuboCop
313
335
 
314
336
  def registered?(badge)
315
337
  clear_enrollment_queue
316
- @cops_by_badge.key?(badge)
338
+ @cops_by_badge.key?(badge) || @lazy_loaded_cops_by_badge.key?(badge)
317
339
  end
318
340
  end
319
341
  end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # a subprocess is created in the same way as `Kernel#open`, and its output is returned.
11
11
  # `Kernel#open` may allow unintentional command injection, which is the reason these
12
12
  # `IO` methods are a security risk.
13
- # Consider to use `File.read` to disable the behavior of subprocess invocation.
13
+ # Consider using `File.read` to disable the behavior of subprocess invocation.
14
14
  #
15
15
  # @safety
16
16
  # This cop is unsafe because false positive will occur if the variable passed as
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # is resolved at runtime).
11
11
  # It also flags uses of `alias :symbol` rather than `alias bareword`.
12
12
  #
13
- # However, it will always enforce `method_alias` when used `alias`
13
+ # However, it will always enforce `alias_method` when `alias` is used
14
14
  # in an instance method definition and in a singleton method definition.
15
15
  # If used in a block, always enforce `alias_method`
16
16
  # unless it is an `instance_eval` block.
@@ -45,6 +45,7 @@ module RuboCop
45
45
  return unless node.command?(:alias_method)
46
46
  return unless style == :prefer_alias && alias_keyword_possible?(node)
47
47
  return unless node.arguments.count == 2
48
+ return if alias_method_value_used?(node)
48
49
 
49
50
  msg = format(MSG_ALIAS_METHOD, current: lexical_scope_type(node))
50
51
  add_offense(node.loc.selector, message: msg) do |corrector|
@@ -80,6 +81,14 @@ module RuboCop
80
81
  scope_type(node) != :dynamic && node.arguments.all?(&:sym_type?)
81
82
  end
82
83
 
84
+ # `alias_method` is a method call whose return value can be used
85
+ # (e.g., as an argument to `public`/`module_function`, or as an assignment),
86
+ # but `alias` is a keyword statement that cannot appear in such positions.
87
+ # Detect these positions so the conversion does not produce a syntax error.
88
+ def alias_method_value_used?(node)
89
+ node.argument? || node.parent&.assignment?
90
+ end
91
+
83
92
  def alias_method_possible?(node)
84
93
  scope_type(node) != :instance_eval &&
85
94
  node.children.none?(&:gvar_type?) &&
@@ -8,8 +8,8 @@ module RuboCop
8
8
  # essentially one-character strings, so this syntax
9
9
  # is mostly redundant at this point.
10
10
  #
11
- # ? character literal can be used to express meta and control character.
12
- # That's a good use case of ? literal so it doesn't count it as an offense.
11
+ # A `?` character literal can be used to express meta and control characters.
12
+ # That's a good use case of a `?` literal so it doesn't count as an offense.
13
13
  #
14
14
  # @example
15
15
  # # bad
@@ -181,6 +181,7 @@ module RuboCop
181
181
 
182
182
  def check_style(node, body, style)
183
183
  return if node.identifier.namespace&.cbase_type?
184
+ return unless const_namespace?(node.identifier.namespace)
184
185
 
185
186
  if style == :nested
186
187
  check_nested_style(node)
@@ -189,6 +190,13 @@ module RuboCop
189
190
  end
190
191
  end
191
192
 
193
+ def const_namespace?(node)
194
+ return true if node.nil? || node.cbase_type?
195
+ return false unless node.const_type?
196
+
197
+ const_namespace?(node.namespace)
198
+ end
199
+
192
200
  def check_nested_style(node)
193
201
  return unless compact_node_name?(node)
194
202
  return if node.parent&.type?(:class, :module)
@@ -6,7 +6,7 @@ module RuboCop
6
6
  module Cop
7
7
  module Style
8
8
  # Detects comments to enable/disable RuboCop.
9
- # This is useful if want to make sure that every RuboCop error gets fixed
9
+ # This is useful if you want to make sure that every RuboCop error gets fixed
10
10
  # and not quickly disabled with a comment.
11
11
  #
12
12
  # Specific cops can be allowed with the `AllowedCops` configuration. Note that
@@ -104,28 +104,30 @@ module RuboCop
104
104
 
105
105
  def replacement(mode, filename, content, write_node)
106
106
  replacement = "#{write_method(mode)}(#{filename.source}, #{content.source})"
107
+ heredoc = heredoc_in_write(write_node)
108
+ return replacement unless heredoc
107
109
 
108
- if heredoc?(write_node)
109
- first_argument = write_node.body.first_argument
110
+ <<~REPLACEMENT.chomp
111
+ #{replacement}
112
+ #{heredoc_range(heredoc).source}
113
+ REPLACEMENT
114
+ end
110
115
 
111
- <<~REPLACEMENT.chomp
112
- #{replacement}
113
- #{heredoc_range(first_argument).source}
114
- REPLACEMENT
115
- else
116
- replacement
117
- end
116
+ def heredoc_in_write(write_node)
117
+ return unless write_node.block_type? && (first_argument = write_node.body.first_argument)
118
+
119
+ find_heredoc(first_argument)
118
120
  end
119
121
 
120
- def heredoc?(write_node)
121
- write_node.block_type? && (first_argument = write_node.body.first_argument) &&
122
- first_argument.respond_to?(:heredoc?) && first_argument.heredoc?
122
+ def heredoc_range(heredoc)
123
+ range_between(heredoc.loc.heredoc_body.begin_pos, heredoc.loc.heredoc_end.end_pos)
123
124
  end
124
125
 
125
- def heredoc_range(first_argument)
126
- range_between(
127
- first_argument.loc.heredoc_body.begin_pos, first_argument.loc.heredoc_end.end_pos
128
- )
126
+ def find_heredoc(node)
127
+ return node if node.respond_to?(:heredoc?) && node.heredoc?
128
+ return if node.send_type? && !(receiver = node.receiver)
129
+
130
+ find_heredoc(receiver)
129
131
  end
130
132
  end
131
133
  end
@@ -11,9 +11,10 @@ module RuboCop
11
11
  # if the first argument is a string literal and if the second
12
12
  # argument is an array literal.
13
13
  #
14
- # Autocorrection will be applied when using argument is a literal or known built-in conversion
15
- # methods such as `to_d`, `to_f`, `to_h`, `to_i`, `to_r`, `to_s`, and `to_sym` on variables,
16
- # provided that their return value is not an array. For example, when using `to_s`,
14
+ # Autocorrection will be applied when the argument is a literal or uses a known
15
+ # built-in conversion method such as `to_d`, `to_f`, `to_h`, `to_i`, `to_r`, `to_s`,
16
+ # and `to_sym` on variables, provided that their return value is not an array.
17
+ # For example, when using `to_s`,
17
18
  # `'%s' % [1, 2, 3].to_s` can be autocorrected without any incompatibility:
18
19
  #
19
20
  # [source,ruby]
@@ -73,7 +73,7 @@ module RuboCop
73
73
  first_argument = node.first_argument
74
74
  if first_argument.hash_type?
75
75
  register_offense_for_hash(node, first_argument)
76
- elsif first_argument.splat_type?
76
+ elsif first_argument.type?(:splat, :forwarded_restarg)
77
77
  add_offense(node, message: MSG_SPLAT) unless allowed_splat_argument?
78
78
  elsif use_zip_method_without_argument?(first_argument)
79
79
  register_offense_for_zip_method(node, first_argument)
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # Required capitalization can be set with the `DirectiveCapitalization` and
11
11
  # `ValueCapitalization` configuration keys.
12
12
  #
13
- # NOTE: If one of these configuration is set to nil, any capitalization is allowed.
13
+ # NOTE: If one of these configurations is set to nil, any capitalization is allowed.
14
14
  #
15
15
  # @example EnforcedStyle: snake_case (default)
16
16
  # # The `snake_case` style will enforce that the frozen string literal
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Enforces the use of `max` or `min` instead of comparison for greater or less.
7
7
  #
8
8
  # NOTE: It can be used if you want to present limit or threshold in Ruby 2.7+.
9
- # That it is slow though. So autocorrection will apply generic `max` or `min`:
9
+ # It is slow though. So autocorrection will apply generic `max` or `min`:
10
10
  #
11
11
  # [source,ruby]
12
12
  # ----
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for the instantiation of array using redundant `Array` constructor.
7
- # Autocorrect replaces to array literal which is the simplest and fastest.
6
+ # Checks for the instantiation of an array using a redundant `Array` constructor.
7
+ # Autocorrect replaces it with an array literal which is the simplest and fastest.
8
8
  #
9
9
  # @example
10
10
  #
@@ -3,16 +3,16 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Avoid redundant `::` prefix on constant.
6
+ # Avoid redundant `::` prefix on a constant.
7
7
  #
8
- # How Ruby searches constant is a bit complicated, and it can often be difficult to
8
+ # How Ruby searches constants is a bit complicated, and it can often be difficult to
9
9
  # understand from the code whether the `::` is intended or not. Where `Module.nesting`
10
10
  # is empty, there is no need to prepend `::`, so it would be nice to consistently
11
11
  # avoid such meaningless `::` prefix to avoid confusion.
12
12
  #
13
- # NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled to prevent
14
- # conflicting rules. Because it respects user configurations that want to enable
15
- # `Lint/ConstantResolution` cop which is disabled by default.
13
+ # NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled,
14
+ # to prevent conflicting rules. This is because it respects user configurations
15
+ # that want to enable `Lint/ConstantResolution` cop which is disabled by default.
16
16
  #
17
17
  # @example
18
18
  # # bad
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`.
7
- # Autocorrect replaces to regexp literal which is the simplest and fastest.
6
+ # Checks for the instantiation of a regexp using a redundant `Regexp.new` or `Regexp.compile`.
7
+ # Autocorrect replaces it with a regexp literal which is the simplest and fastest.
8
8
  #
9
9
  # @example
10
10
  #
@@ -5,8 +5,8 @@ module RuboCop
5
5
  module Style
6
6
  # Enforces using `//` or `%r` around regular expressions.
7
7
  #
8
- # NOTE: The following `%r` cases using a regexp starts with a blank or `=`
9
- # as a method argument allowed to prevent syntax errors.
8
+ # NOTE: The following `%r` cases using a regexp that starts with a blank or `=`
9
+ # as a method argument are allowed to prevent syntax errors.
10
10
  #
11
11
  # [source,ruby]
12
12
  # ----
@@ -3,17 +3,17 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of `rescue` in its modifier form is added for following
6
+ # Checks for uses of `rescue` in its modifier form. It is added for the following
7
7
  # reasons:
8
8
  #
9
9
  # * The syntax of modifier form `rescue` can be misleading because it
10
10
  # might lead us to believe that `rescue` handles the given exception
11
- # but it actually rescue all exceptions to return the given rescue
11
+ # but it actually rescues all exceptions to return the given rescue
12
12
  # block. In this case, value returned by handle_error or
13
13
  # SomeException.
14
14
  #
15
15
  # * Modifier form `rescue` would rescue all the exceptions. It would
16
- # silently skip all exception or errors and handle the error.
16
+ # silently skip all exceptions or errors and handle the error.
17
17
  # Example: If `NoMethodError` is raised, modifier form rescue would
18
18
  # handle the exception.
19
19
  #
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Enforces the use the shorthand for self-assignment.
6
+ # Enforces the use of the shorthand for self-assignment.
7
7
  #
8
8
  # @example
9
9
  #
@@ -61,6 +61,8 @@ module RuboCop
61
61
  corrector.remove(range_with_surrounding_space(parent.loc.end, newlines: false))
62
62
  elsif (class_node = parent.parent).body.nil?
63
63
  corrector.remove(range_for_empty_class_body(class_node, parent))
64
+ elsif unparenthesized_struct_new?(parent)
65
+ wrap_unparenthesized_call_with_do(corrector, parent)
64
66
  else
65
67
  corrector.insert_after(parent, ' do')
66
68
  end
@@ -73,6 +75,17 @@ module RuboCop
73
75
  range_by_whole_lines(class_node.loc.end, include_final_newline: true)
74
76
  end
75
77
  end
78
+
79
+ def unparenthesized_struct_new?(parent)
80
+ parent.send_type? && parent.arguments.any? && !parent.parenthesized?
81
+ end
82
+
83
+ def wrap_unparenthesized_call_with_do(corrector, parent)
84
+ args_source = parent.arguments.map(&:source).join(', ')
85
+ range = parent.loc.selector.end.join(parent.source_range.end)
86
+
87
+ corrector.replace(range, "(#{args_source}) do")
88
+ end
76
89
  end
77
90
  end
78
91
  end
@@ -3,11 +3,11 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Newcomers to ruby applications may write top-level methods,
6
+ # Newcomers to Ruby applications may write top-level methods,
7
7
  # when ideally they should be organized in appropriate classes or modules.
8
8
  # This cop looks for definitions of top-level methods and warns about them.
9
9
  #
10
- # However for ruby scripts it is perfectly fine to use top-level methods.
10
+ # However, for Ruby scripts it is perfectly fine to use top-level methods.
11
11
  # Hence this cop is disabled by default.
12
12
  #
13
13
  # @example
@@ -14,11 +14,11 @@ module RuboCop
14
14
  #
15
15
  # `forbid_mixed_logical_operators` style forbids the use of more than one type
16
16
  # of logical operators. This makes the `unless` condition easier to read
17
- # because either all conditions need to be met or any condition need to be met
17
+ # because either all conditions need to be met or any condition needs to be met
18
18
  # in order for the expression to be truthy or falsey.
19
19
  #
20
- # `forbid_logical_operators` style forbids any use of logical operator.
21
- # This makes it even more easy to read the `unless` condition as
20
+ # `forbid_logical_operators` style forbids any use of logical operators.
21
+ # This makes it even easier to read the `unless` condition as
22
22
  # there is only one condition in the expression.
23
23
  #
24
24
  # @example EnforcedStyle: forbid_mixed_logical_operators (default)
@@ -147,7 +147,7 @@ module RuboCop
147
147
  end
148
148
 
149
149
  def constant_portion?(node)
150
- node.literal? || node.const_type?
150
+ node.recursive_literal? || node.const_type?
151
151
  end
152
152
 
153
153
  def actual_code_range(node)
@@ -21,11 +21,19 @@ module RuboCop
21
21
  def initialize(patterns)
22
22
  @strings = Set.new
23
23
  @patterns = []
24
+ @match_cache = {}
24
25
  partition_patterns(patterns)
25
26
  end
26
27
 
27
28
  def match?(path)
28
- @strings.include?(path) || @patterns.any? { |pattern| PathUtil.match_path?(pattern, path) }
29
+ # `FilePatterns.from` memoizes one instance per pattern array (by identity),
30
+ # so this cache is shared across every cop using the same Include/Exclude
31
+ # list. Patterns are immutable within a run, so caching by path is safe.
32
+ cached = @match_cache[path]
33
+ return cached unless cached.nil?
34
+
35
+ @match_cache[path] =
36
+ @strings.include?(path) || @patterns.any? { |pattern| PathUtil.match_path?(pattern, path) }
29
37
  end
30
38
 
31
39
  private