rubocop 1.62.1 → 1.63.5

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +22 -3
  4. data/lib/rubocop/cached_data.rb +11 -3
  5. data/lib/rubocop/cli.rb +4 -0
  6. data/lib/rubocop/config.rb +33 -10
  7. data/lib/rubocop/config_obsoletion.rb +1 -1
  8. data/lib/rubocop/cop/base.rb +40 -1
  9. data/lib/rubocop/cop/internal_affairs/example_description.rb +2 -1
  10. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  11. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -0
  12. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
  13. data/lib/rubocop/cop/lint/debugger.rb +27 -2
  14. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  15. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  16. data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
  17. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  18. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  19. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -2
  20. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  21. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  22. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  23. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  24. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  25. data/lib/rubocop/cop/naming/block_forwarding.rb +31 -12
  26. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  27. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
  28. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  29. data/lib/rubocop/cop/style/alias.rb +1 -0
  30. data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -1
  31. data/lib/rubocop/cop/style/collection_compact.rb +3 -3
  32. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  33. data/lib/rubocop/cop/style/copyright.rb +16 -11
  34. data/lib/rubocop/cop/style/eval_with_location.rb +3 -1
  35. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  36. data/lib/rubocop/cop/style/format_string.rb +9 -9
  37. data/lib/rubocop/cop/style/map_into_array.rb +175 -0
  38. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  39. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  40. data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
  41. data/lib/rubocop/cop/style/redundant_argument.rb +24 -1
  42. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +1 -1
  43. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  44. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  45. data/lib/rubocop/cop/style/redundant_line_continuation.rb +11 -15
  46. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  47. data/lib/rubocop/cop/style/require_order.rb +1 -1
  48. data/lib/rubocop/cop/style/send.rb +4 -4
  49. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  50. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  51. data/lib/rubocop/cop/team.rb +3 -0
  52. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  53. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  54. data/lib/rubocop/lockfile.rb +56 -7
  55. data/lib/rubocop/lsp/routes.rb +3 -4
  56. data/lib/rubocop/lsp/server.rb +2 -0
  57. data/lib/rubocop/options.rb +3 -3
  58. data/lib/rubocop/rake_task.rb +1 -1
  59. data/lib/rubocop/rspec/expect_offense.rb +8 -0
  60. data/lib/rubocop/rspec/shared_contexts.rb +13 -1
  61. data/lib/rubocop/runner.rb +5 -1
  62. data/lib/rubocop/version.rb +5 -5
  63. data/lib/rubocop.rb +1 -0
  64. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8daa4ef7dd74b8608039d7dfda5f1e3fe739738949390a6f1347acaccf7bd1c4
4
- data.tar.gz: 271a978db956def596a5b06a7fd69d189d807b27db0acdda03fd6200b95ef541
3
+ metadata.gz: 1911c884de81dd524490fea5075e7605d3ccf82fad85ebc9d09adbe5d29637ca
4
+ data.tar.gz: 8206c237dd18bbcd9769d55b1206d160ce766a21caa5c8f8ea956ae845371ea2
5
5
  SHA512:
6
- metadata.gz: 484294f43781f114ba01470b22331ef17648219e26dc4ba2f28073f609c909af2997c47e1f1aad62860124f6f4594a2e536cd793f05352a78d588f979732a290
7
- data.tar.gz: 6a8313e61422bcd568eea747c0f9a88f61f50620b4dd4f478da0bdd3e067c1aa8bcf70e15744e02118d4c525eb0632fae3cc19caf73db6db1f63ea76dbb84b45
6
+ metadata.gz: 429dfdfda489516f4856fa00ad50c062a172588ca4bb1006baa25213c2fb949b0781af446d689200f0a87017f47708ad49324a6644cce104f79dd42b129dd680
7
+ data.tar.gz: ce8363fa68a56f9c5f36c40d1596932b1233854823c54bfb9dc36a669256dca64459186037fe10e9723a550cec0a6f11df2e1d802e4471d8c9d1e98db8c528f3
data/README.md CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
53
53
  in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 1.62', require: false
56
+ gem 'rubocop', '~> 1.63', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -156,13 +156,14 @@ AllCops:
156
156
  # included.
157
157
  SuggestExtensions:
158
158
  rubocop-rails: [rails]
159
- rubocop-rspec: [rspec, rspec-rails]
159
+ rubocop-rspec: [rspec]
160
160
  rubocop-minitest: [minitest]
161
161
  rubocop-sequel: [sequel]
162
162
  rubocop-rake: [rake]
163
163
  rubocop-graphql: [graphql]
164
164
  rubocop-capybara: [capybara]
165
165
  rubocop-factory_bot: [factory_bot, factory_bot_rails]
166
+ rubocop-rspec_rails: [rspec-rails]
166
167
  # Enable/Disable checking the methods extended by Active Support.
167
168
  ActiveSupportExtensionsEnabled: false
168
169
 
@@ -1657,7 +1658,7 @@ Lint/Debugger:
1657
1658
  Description: 'Check for debugger calls.'
1658
1659
  Enabled: true
1659
1660
  VersionAdded: '0.14'
1660
- VersionChanged: '1.46'
1661
+ VersionChanged: '1.63'
1661
1662
  DebuggerMethods:
1662
1663
  # Groups are available so that a specific group can be disabled in
1663
1664
  # a user's configuration, but are otherwise not significant.
@@ -1670,8 +1671,14 @@ Lint/Debugger:
1670
1671
  - Kernel.byebug
1671
1672
  - Kernel.remote_byebug
1672
1673
  Capybara:
1674
+ - page.save_and_open_page
1675
+ - page.save_and_open_screenshot
1676
+ - page.save_page
1677
+ - page.save_screenshot
1673
1678
  - save_and_open_page
1674
1679
  - save_and_open_screenshot
1680
+ - save_page
1681
+ - save_screenshot
1675
1682
  debug.rb:
1676
1683
  - binding.b
1677
1684
  - binding.break
@@ -1693,6 +1700,10 @@ Lint/Debugger:
1693
1700
  - jard
1694
1701
  WebConsole:
1695
1702
  - binding.console
1703
+ DebuggerRequires:
1704
+ debug.rb:
1705
+ - debug/open
1706
+ - debug/start
1696
1707
 
1697
1708
  Lint/DeprecatedClassMethods:
1698
1709
  Description: 'Check for deprecated class method calls.'
@@ -2762,7 +2773,8 @@ Naming/FileName:
2762
2773
  VersionChanged: '1.23'
2763
2774
  # Camel case file names listed in `AllCops:Include` and all file names listed
2764
2775
  # in `AllCops:Exclude` are excluded by default. Add extra excludes here.
2765
- Exclude: []
2776
+ Exclude:
2777
+ - Rakefile.rb
2766
2778
  # When `true`, requires that each source file should define a class or module
2767
2779
  # with a name which matches the file name (converted to ... case).
2768
2780
  # It further expects it to be nested inside modules which match the names
@@ -4276,6 +4288,13 @@ Style/MapCompactWithConditionalBlock:
4276
4288
  Enabled: pending
4277
4289
  VersionAdded: '1.30'
4278
4290
 
4291
+ Style/MapIntoArray:
4292
+ Description: 'Checks for usages of `each` with `<<`, `push`, or `append` which can be replaced by `map`.'
4293
+ StyleGuide: '#functional-code'
4294
+ Enabled: pending
4295
+ VersionAdded: '1.63'
4296
+ Safe: false
4297
+
4279
4298
  Style/MapToHash:
4280
4299
  Description: 'Prefer `to_h` with a block over `map.to_h`.'
4281
4300
  Enabled: pending
@@ -48,11 +48,19 @@ module RuboCop
48
48
  source_buffer = Parser::Source::Buffer.new(@filename)
49
49
  source_buffer.source = File.read(@filename, encoding: Encoding::UTF_8)
50
50
  offenses.map! do |o|
51
- location = Parser::Source::Range.new(source_buffer,
52
- o['location']['begin_pos'],
53
- o['location']['end_pos'])
51
+ location = location_from_source_buffer(o, source_buffer)
54
52
  Cop::Offense.new(o['severity'], location, o['message'], o['cop_name'], o['status'].to_sym)
55
53
  end
56
54
  end
55
+
56
+ def location_from_source_buffer(offense, source_buffer)
57
+ begin_pos = offense['location']['begin_pos']
58
+ end_pos = offense['location']['end_pos']
59
+ if begin_pos.zero? && end_pos.zero?
60
+ Cop::Offense::NO_LOCATION
61
+ else
62
+ Parser::Source::Range.new(source_buffer, begin_pos, end_pos)
63
+ end
64
+ end
57
65
  end
58
66
  end
data/lib/rubocop/cli.rb CHANGED
@@ -57,6 +57,10 @@ module RuboCop
57
57
  rescue RuboCop::Error => e
58
58
  warn Rainbow("Error: #{e.message}").red
59
59
  STATUS_ERROR
60
+ rescue Interrupt
61
+ warn ''
62
+ warn 'Exiting...'
63
+ STATUS_INTERRUPTED
60
64
  rescue Finished
61
65
  STATUS_SUCCESS
62
66
  rescue OptionParser::InvalidOption => e
@@ -263,6 +263,7 @@ module RuboCop
263
263
  PathUtil.smart_path(@loaded_path)
264
264
  end
265
265
 
266
+ # @return [String, nil]
266
267
  def bundler_lock_file_path
267
268
  return nil unless loaded_path
268
269
 
@@ -286,27 +287,49 @@ module RuboCop
286
287
  end
287
288
  end
288
289
 
290
+ # Returns target's locked gem versions (i.e. from Gemfile.lock or gems.locked)
291
+ # @returns [Hash{String => Gem::Version}] The locked gem versions, keyed by the gems' names.
292
+ def gem_versions_in_target
293
+ @gem_versions_in_target ||= read_gem_versions_from_target_lockfile
294
+ end
295
+
289
296
  def inspect # :nodoc:
290
297
  "#<#{self.class.name}:#{object_id} @loaded_path=#{loaded_path}>"
291
298
  end
292
299
 
293
300
  private
294
301
 
302
+ # @return [Float, nil] The Rails version as a `major.minor` Float.
295
303
  def target_rails_version_from_bundler_lock_file
296
304
  @target_rails_version_from_bundler_lock_file ||= read_rails_version_from_bundler_lock_file
297
305
  end
298
306
 
307
+ # @return [Float, nil] The Rails version as a `major.minor` Float.
299
308
  def read_rails_version_from_bundler_lock_file
300
- lock_file_path = bundler_lock_file_path
301
- return nil unless lock_file_path
302
-
303
- File.foreach(lock_file_path) do |line|
304
- # If Rails (or one of its frameworks) is in Gemfile.lock or gems.lock, there should be
305
- # a line like:
306
- # railties (X.X.X)
307
- result = line.match(/^\s+railties\s+\((\d+\.\d+)/)
308
- return result.captures.first.to_f if result
309
- end
309
+ return nil unless gem_versions_in_target
310
+
311
+ # Look for `railties` instead of `rails`, to support apps that only use a subset of `rails`
312
+ # See https://github.com/rubocop/rubocop/pull/11289
313
+ rails_version_in_target = gem_versions_in_target['railties']
314
+ return nil unless rails_version_in_target
315
+
316
+ gem_version_to_major_minor_float(rails_version_in_target)
317
+ end
318
+
319
+ # @param [Gem::Version] gem_version an object like `Gem::Version.new("7.1.2.3")`
320
+ # @return [Float] The major and minor version, like `7.1`
321
+ def gem_version_to_major_minor_float(gem_version)
322
+ segments = gem_version.canonical_segments
323
+ # segments.fetch(0).to_f + (segments.fetch(1, 0.0).to_f / 10)
324
+ Float("#{segments.fetch(0)}.#{segments.fetch(1, 0)}")
325
+ end
326
+
327
+ # @returns [Hash{String => Gem::Version}] The locked gem versions, keyed by the gems' names.
328
+ def read_gem_versions_from_target_lockfile
329
+ lockfile_path = bundler_lock_file_path
330
+ return nil unless lockfile_path
331
+
332
+ Lockfile.new(lockfile_path).gem_versions
310
333
  end
311
334
 
312
335
  def enable_cop?(qualified_cop_name, cop_options)
@@ -52,7 +52,7 @@ module RuboCop
52
52
  def load_rules # rubocop:disable Metrics/AbcSize
53
53
  rules = LOAD_RULES_CACHE[self.class.files] ||=
54
54
  self.class.files.each_with_object({}) do |filename, hash|
55
- hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
55
+ hash.merge!(YAML.safe_load(File.read(filename)) || {}) do |_key, first, second|
56
56
  case first
57
57
  when Hash
58
58
  first.merge(second)
@@ -70,6 +70,7 @@ module RuboCop
70
70
 
71
71
  def self.inherited(subclass)
72
72
  super
73
+ subclass.instance_variable_set(:@gem_requirements, gem_requirements.dup)
73
74
  Registry.global.enlist(subclass)
74
75
  end
75
76
 
@@ -126,6 +127,29 @@ module RuboCop
126
127
  false
127
128
  end
128
129
 
130
+ ## Gem requirements
131
+
132
+ @gem_requirements = {}
133
+
134
+ class << self
135
+ attr_reader :gem_requirements
136
+
137
+ # Register a version requirement for the given gem name.
138
+ # This cop will be skipped unless the target satisfies *all* requirements.
139
+ # @param [String] gem_name
140
+ # @param [Array<String>] version_requirements The version requirements,
141
+ # using the same syntax as a Gemfile, e.g. ">= 1.2.3"
142
+ #
143
+ # If omitted, any version of the gem will be accepted.
144
+ #
145
+ # https://guides.rubygems.org/patterns/#declaring-dependencies
146
+ #
147
+ # @api public
148
+ def requires_gem(gem_name, *version_requirements)
149
+ @gem_requirements[gem_name] = Gem::Requirement.new(version_requirements)
150
+ end
151
+ end
152
+
129
153
  def initialize(config = nil, options = nil)
130
154
  @config = config || Config.new
131
155
  @options = options || { debug: false }
@@ -162,7 +186,9 @@ module RuboCop
162
186
  def add_global_offense(message = nil, severity: nil)
163
187
  severity = find_severity(nil, severity)
164
188
  message = find_message(nil, message)
165
- current_offenses << Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported)
189
+ range = Offense::NO_LOCATION
190
+ status = enabled_line?(range.line) ? :unsupported : :disabled
191
+ current_offenses << Offense.new(severity, range, message, name, status)
166
192
  end
167
193
 
168
194
  # Adds an offense on the specified range (or node with an expression)
@@ -245,6 +271,7 @@ module RuboCop
245
271
  end
246
272
 
247
273
  def relevant_file?(file)
274
+ return false unless target_satisfies_all_gem_version_requirements?
248
275
  return true unless @config.clusivity_config_for_badge?(self.class.badge)
249
276
 
250
277
  file == RuboCop::AST::ProcessedSource::STRING_SOURCE_NAME ||
@@ -496,6 +523,18 @@ module RuboCop
496
523
  range.end_pos + @current_offset
497
524
  )
498
525
  end
526
+
527
+ def target_satisfies_all_gem_version_requirements?
528
+ self.class.gem_requirements.all? do |gem_name, version_req|
529
+ all_gem_versions_in_target = @config.gem_versions_in_target
530
+ next false unless all_gem_versions_in_target
531
+
532
+ gem_version_in_target = all_gem_versions_in_target[gem_name]
533
+ next false unless gem_version_in_target
534
+
535
+ version_req.satisfied_by?(gem_version_in_target)
536
+ end
537
+ end
499
538
  end
500
539
  end
501
540
  end
@@ -45,7 +45,8 @@ module RuboCop
45
45
  EXPECT_OFFENSE_DESCRIPTION_MAPPING = {
46
46
  /\A(does not|doesn't) (register|find|flag|report)/ => 'registers',
47
47
  /\A(does not|doesn't) add (a|an|any )?offense/ => 'registers an offense',
48
- /\Aaccepts\b/ => 'registers'
48
+ /\Aregisters no offense/ => 'registers an offense',
49
+ /\A(accepts|register)\b/ => 'registers'
49
50
  }.freeze
50
51
 
51
52
  EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
@@ -160,7 +160,7 @@ module RuboCop
160
160
  end
161
161
 
162
162
  def two_alternatives?(line)
163
- /^\s*(else|elsif|when|rescue|ensure)\b/.match?(line)
163
+ /^\s*(else|elsif|when|in|rescue|ensure)\b/.match?(line)
164
164
  end
165
165
  end
166
166
  end
@@ -92,6 +92,8 @@ module RuboCop
92
92
  'in an array, relative to %<base_description>s.'
93
93
 
94
94
  def on_array(node)
95
+ return if style != :consistent && enforce_first_argument_with_fixed_indentation?
96
+
95
97
  check(node, nil) if node.loc.begin
96
98
  end
97
99
 
@@ -50,7 +50,7 @@ module RuboCop
50
50
  MSG_WITHOUT_SAFE_ASSIGNMENT_ALLOWED =
51
51
  'Use `==` if you meant to do a comparison or move the assignment ' \
52
52
  'up out of the condition.'
53
- ASGN_TYPES = [:begin, *AST::Node::EQUALS_ASSIGNMENTS, :send].freeze
53
+ ASGN_TYPES = [:begin, *AST::Node::EQUALS_ASSIGNMENTS, :send, :csend].freeze
54
54
 
55
55
  def on_if(node)
56
56
  return if node.condition.block_type?
@@ -88,7 +88,7 @@ module RuboCop
88
88
  end
89
89
 
90
90
  def skip_children?(asgn_node)
91
- (asgn_node.send_type? && !asgn_node.assignment_method?) ||
91
+ (asgn_node.call_type? && !asgn_node.assignment_method?) ||
92
92
  empty_condition?(asgn_node) ||
93
93
  (safe_assignment_allowed? && safe_assignment?(asgn_node))
94
94
  end
@@ -29,6 +29,11 @@ module RuboCop
29
29
  # MyDebugger.debug_this
30
30
  # ----
31
31
  #
32
+ # Some gems also ship files that will start a debugging session when required,
33
+ # for example `require 'debug/start'` from `ruby/debug`. These requires can
34
+ # be configured through `DebuggerRequires`. It has the same structure as
35
+ # `DebuggerMethods`, which you can read about above.
36
+ #
32
37
  # @example
33
38
  #
34
39
  # # bad (ok during development)
@@ -64,14 +69,20 @@ module RuboCop
64
69
  # def some_method
65
70
  # my_debugger
66
71
  # end
72
+ #
73
+ # @example DebuggerRequires: [my_debugger/start]
74
+ #
75
+ # # bad (ok during development)
76
+ #
77
+ # require 'my_debugger/start'
67
78
  class Debugger < Base
68
79
  MSG = 'Remove debugger entry point `%<source>s`.'
69
80
  BLOCK_TYPES = %i[block numblock kwbegin].freeze
70
81
 
71
82
  def on_send(node)
72
- return if !debugger_method?(node) || assumed_usage_context?(node)
83
+ return if assumed_usage_context?(node)
73
84
 
74
- add_offense(node)
85
+ add_offense(node) if debugger_method?(node) || debugger_require?(node)
75
86
  end
76
87
 
77
88
  private
@@ -87,12 +98,26 @@ module RuboCop
87
98
  end
88
99
  end
89
100
 
101
+ def debugger_requires
102
+ @debugger_requires ||= begin
103
+ config = cop_config.fetch('DebuggerRequires', [])
104
+ config.is_a?(Array) ? config : config.values.flatten
105
+ end
106
+ end
107
+
90
108
  def debugger_method?(send_node)
91
109
  return false if send_node.parent&.send_type? && send_node.parent.receiver == send_node
92
110
 
93
111
  debugger_methods.include?(chained_method_name(send_node))
94
112
  end
95
113
 
114
+ def debugger_require?(send_node)
115
+ return false unless send_node.method?(:require) && send_node.arguments.one?
116
+ return false unless (argument = send_node.first_argument).str_type?
117
+
118
+ debugger_requires.include?(argument.value)
119
+ end
120
+
96
121
  def assumed_usage_context?(node)
97
122
  # Basically, debugger methods are not used as a method argument without arguments.
98
123
  return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any?
@@ -52,7 +52,7 @@ module RuboCop
52
52
  # @!method deprecated_class_method?(node)
53
53
  def_node_matcher :deprecated_class_method?, <<~PATTERN
54
54
  {
55
- (send (const {cbase nil?} {:ENV}) {:clone :dup :freeze})
55
+ (send (const {cbase nil?} :ENV) {:clone :dup :freeze})
56
56
  (send (const {cbase nil?} {:File :Dir}) :exists? _)
57
57
  (send (const {cbase nil?} :Socket) {:gethostbyaddr :gethostbyname} ...)
58
58
  (send nil? :attr _ boolean)
@@ -146,7 +146,7 @@ module RuboCop
146
146
  node.source_range.with(end_pos: node.condition.source_range.end_pos)
147
147
  elsif all_branches_body_missing?(node)
148
148
  if_node = node.ancestors.detect(&:if?)
149
- node.source_range.with(end_pos: if_node.loc.end.end_pos)
149
+ node.source_range.join(if_node.loc.end.end)
150
150
  else
151
151
  node.source_range
152
152
  end
@@ -47,8 +47,10 @@ module RuboCop
47
47
 
48
48
  def on_regexp(node)
49
49
  each_unsafe_regexp_range(node) do |loc|
50
+ next unless (replacement = regexp_range(loc.source))
51
+
50
52
  add_offense(loc) do |corrector|
51
- corrector.replace(loc, rewrite_regexp_range(loc.source))
53
+ corrector.replace(loc, replacement)
52
54
  end
53
55
  end
54
56
  end
@@ -99,10 +101,13 @@ module RuboCop
99
101
  end
100
102
  end
101
103
 
102
- def rewrite_regexp_range(source)
104
+ def regexp_range(source)
103
105
  open, close = source.split('-')
104
- first = [open, range_for(open).end]
105
- second = [range_for(close).begin, close]
106
+ return unless (open_range = range_for(open))
107
+ return unless (close_range = range_for(close))
108
+
109
+ first = [open, open_range.end]
110
+ second = [close_range.begin, close]
106
111
  "#{first.uniq.join('-')}#{second.uniq.join('-')}"
107
112
  end
108
113
  end
@@ -130,7 +130,7 @@ module RuboCop
130
130
  # @return [Parser::Source::Range]
131
131
  #
132
132
  def last_arg_range(node)
133
- node.last_argument.source_range.with(begin_pos: node.arguments[-2].source_range.end_pos)
133
+ node.last_argument.source_range.join(node.arguments[-2].source_range.end)
134
134
  end
135
135
 
136
136
  def unsorted_dir_loop?(node)
@@ -33,8 +33,10 @@ module RuboCop
33
33
  MSG_EACH_WITH_INDEX = 'Use `each` instead of `each_with_index`.'
34
34
  MSG_WITH_INDEX = 'Remove redundant `with_index`.'
35
35
 
36
+ # rubocop:disable Metrics/AbcSize
36
37
  def on_block(node)
37
38
  return unless node.receiver
39
+ return if node.method?(:with_index) && !node.receiver.receiver
38
40
  return unless (send = redundant_with_index?(node))
39
41
 
40
42
  range = with_index_range(send)
@@ -48,6 +50,7 @@ module RuboCop
48
50
  end
49
51
  end
50
52
  end
53
+ # rubocop:enable Metrics/AbcSize
51
54
 
52
55
  alias on_numblock on_block
53
56
 
@@ -71,7 +71,7 @@ module RuboCop
71
71
  expressions.any? { |expr| flow_expression?(expr) }
72
72
  when :if
73
73
  check_if(node)
74
- when :case
74
+ when :case, :case_match
75
75
  check_case(node)
76
76
  else
77
77
  false
@@ -89,7 +89,9 @@ module RuboCop
89
89
  return false unless else_branch
90
90
  return false unless flow_expression?(else_branch)
91
91
 
92
- node.when_branches.all? { |branch| branch.body && flow_expression?(branch.body) }
92
+ branches = node.case_type? ? node.when_branches : node.in_pattern_branches
93
+
94
+ branches.all? { |branch| branch.body && flow_expression?(branch.body) }
93
95
  end
94
96
  end
95
97
  end
@@ -160,7 +160,7 @@ module RuboCop
160
160
  break_statement && !preceded_by_continue_statement?(break_statement)
161
161
  when :if
162
162
  check_if(node)
163
- when :case
163
+ when :case, :case_match
164
164
  check_case(node)
165
165
  else
166
166
  false
@@ -178,7 +178,13 @@ module RuboCop
178
178
  return false unless else_branch
179
179
  return false unless break_statement?(else_branch)
180
180
 
181
- node.when_branches.all? { |branch| branch.body && break_statement?(branch.body) }
181
+ branches = if node.case_type?
182
+ node.when_branches
183
+ else
184
+ node.in_pattern_branches
185
+ end
186
+
187
+ branches.all? { |branch| branch.body && break_statement?(branch.body) }
182
188
  end
183
189
 
184
190
  def preceded_by_continue_statement?(break_statement)
@@ -51,8 +51,8 @@ module RuboCop
51
51
  when :method_call
52
52
  ->(node) { node.call_type? }
53
53
  else
54
- raise ArgumentError, "Unknown foldable type: #{type.inspect}. " \
55
- "Valid foldable types are: #{FOLDABLE_TYPES.join(', ')}."
54
+ raise Warning, "Unknown foldable type: #{type.inspect}. " \
55
+ "Valid foldable types are: #{FOLDABLE_TYPES.join(', ')}."
56
56
  end
57
57
  end
58
58
  end
@@ -36,7 +36,7 @@ module RuboCop
36
36
  length = calculator.calculate
37
37
  return if length <= max_length
38
38
 
39
- location = node.casgn_type? ? node.loc.name : node.source_range
39
+ location = location(node)
40
40
 
41
41
  add_offense(location, message: message(length, max_length)) { self.max = length }
42
42
  end
@@ -54,6 +54,17 @@ module RuboCop
54
54
  foldable_types: count_as_one
55
55
  )
56
56
  end
57
+
58
+ def location(node)
59
+ return node.loc.name if node.casgn_type?
60
+
61
+ if LSP.enabled?
62
+ end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
63
+ node.source_range.begin.join(end_range)
64
+ else
65
+ node.source_range
66
+ end
67
+ end
57
68
  end
58
69
  end
59
70
  end
@@ -49,13 +49,13 @@ module RuboCop
49
49
 
50
50
  return unless complexity > max
51
51
 
52
- msg = format(self.class::MSG,
53
- method: method_name,
54
- complexity: complexity,
55
- abc_vector: abc_vector,
56
- max: max)
52
+ msg = format(
53
+ self.class::MSG,
54
+ method: method_name, complexity: complexity, abc_vector: abc_vector, max: max
55
+ )
56
+ location = location(node)
57
57
 
58
- add_offense(node, message: msg) { self.max = complexity.ceil }
58
+ add_offense(location, message: msg) { self.max = complexity.ceil }
59
59
  end
60
60
 
61
61
  def complexity(body)
@@ -69,6 +69,15 @@ module RuboCop
69
69
  end
70
70
  score
71
71
  end
72
+
73
+ def location(node)
74
+ if LSP.enabled?
75
+ end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
76
+ node.source_range.begin.join(end_range)
77
+ else
78
+ node.source_range
79
+ end
80
+ end
72
81
  end
73
82
  end
74
83
  end
@@ -14,7 +14,7 @@ module RuboCop
14
14
  def_node_matcher :empty_condition?, '(begin)'
15
15
 
16
16
  # @!method setter_method?(node)
17
- def_node_matcher :setter_method?, '[(send ...) setter_method?]'
17
+ def_node_matcher :setter_method?, '[(call ...) setter_method?]'
18
18
 
19
19
  # @!method safe_assignment?(node)
20
20
  def_node_matcher :safe_assignment?, '(begin {equals_asgn? #setter_method?})'