rubocop 1.86.1 → 1.86.2

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +8 -1
  3. data/lib/rubocop/cli/command/auto_generate_config.rb +27 -1
  4. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  5. data/lib/rubocop/cli/command/show_docs_url.rb +3 -7
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  7. data/lib/rubocop/cli.rb +4 -7
  8. data/lib/rubocop/comment_config.rb +12 -15
  9. data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
  10. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  11. data/lib/rubocop/cop/correctors.rb +28 -0
  12. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  13. data/lib/rubocop/cop/gemspec/require_mfa.rb +3 -3
  14. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  15. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  16. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +26 -1
  17. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
  18. data/lib/rubocop/cop/lint/require_relative_self_path.rb +2 -0
  19. data/lib/rubocop/cop/lint/useless_assignment.rb +3 -8
  20. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +18 -7
  21. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  22. data/lib/rubocop/cop/mixin.rb +85 -0
  23. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  24. data/lib/rubocop/cop/offense.rb +8 -0
  25. data/lib/rubocop/cop/registry.rb +19 -24
  26. data/lib/rubocop/cop/style/copyright.rb +21 -10
  27. data/lib/rubocop/cop/style/date_time.rb +2 -2
  28. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  29. data/lib/rubocop/cop/style/hash_lookup_method.rb +12 -7
  30. data/lib/rubocop/cop/style/if_inside_else.rb +15 -2
  31. data/lib/rubocop/cop/style/module_member_existence_check.rb +6 -3
  32. data/lib/rubocop/cop/style/reduce_to_hash.rb +16 -0
  33. data/lib/rubocop/cop/style/redundant_self.rb +2 -2
  34. data/lib/rubocop/cop/style/regexp_literal.rb +29 -0
  35. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
  36. data/lib/rubocop/cop/style/symbol_proc.rb +3 -3
  37. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
  38. data/lib/rubocop/cop/team.rb +86 -35
  39. data/lib/rubocop/formatter/disabled_config_formatter.rb +4 -1
  40. data/lib/rubocop/lsp/runtime.rb +1 -2
  41. data/lib/rubocop/options.rb +8 -4
  42. data/lib/rubocop/rspec/shared_contexts.rb +21 -0
  43. data/lib/rubocop/runner.rb +77 -55
  44. data/lib/rubocop/target_finder.rb +13 -6
  45. data/lib/rubocop/version.rb +1 -1
  46. data/lib/rubocop.rb +7 -96
  47. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e7e3463c6020de496396b13ecf80f691f532af83ac8f8627286f3887f07b11b2
4
- data.tar.gz: 9e8c332d0f33ea078abcc71e0ddb7cd009497842a026dfdcae103a63fc909ba6
3
+ metadata.gz: dfb5d2d113d00eb380202a0e76f462318033838aa240febe88bd2861b1bf6609
4
+ data.tar.gz: 9463407310a9babcc5869f9b1db0ca273ed036a3b440b5c27438cba855bee4ec
5
5
  SHA512:
6
- metadata.gz: 0f0d7cff4de9dc7d8f04cdea8f8f28d6e45d5c0676a40ca67daa4e3fd6e3397363d2c2f4b368b5bcbb165d7478bdfb33c5352c49d2fd52896f8aa6d488e017cc
7
- data.tar.gz: 357c3047ffea023a5c10162e4e2f2ee782796b5ca87d7c4413bde296d284c41362033ca9d997609ac6d9eceea7227b46e240150340a8a26cad8071bc5cce33c7
6
+ metadata.gz: 5084465b6aa455c8ecd75e8b8f1e52f92e966d64117d2d88ad343ca535eb6fdc02f05056e6f21ac86e2344ec52cc1db2d69f8bf14a76b76bdee86a2bd5971520
7
+ data.tar.gz: 2101bc8bb5b392fa971f9a881e96b03321442b5067b4952413d806363bb89389cb2631671bfa6af0e30203800cff947d587ac0c68ef1651fdec455cc453faa18
data/config/default.yml CHANGED
@@ -529,6 +529,10 @@ Layout/ClosingParenthesisIndentation:
529
529
  Description: 'Checks the indentation of hanging closing parentheses.'
530
530
  Enabled: true
531
531
  VersionAdded: '0.49'
532
+ VersionChanged: '1.86'
533
+ # By default the indentation width from `Layout/IndentationWidth` is used,
534
+ # but it can be overridden by setting this parameter.
535
+ IndentationWidth: ~
532
536
 
533
537
  Layout/CommentIndentation:
534
538
  Description: 'Indentation of comments.'
@@ -537,7 +541,10 @@ Layout/CommentIndentation:
537
541
  # with a comment on the preceding line.
538
542
  AllowForAlignment: false
539
543
  VersionAdded: '0.49'
540
- VersionChanged: '1.24'
544
+ VersionChanged: '1.86'
545
+ # By default the indentation width from `Layout/IndentationWidth` is used,
546
+ # but it can be overridden by setting this parameter.
547
+ IndentationWidth: ~
541
548
 
542
549
  Layout/ConditionPosition:
543
550
  Description: >-
@@ -24,13 +24,39 @@ module RuboCop
24
24
 
25
25
  def run
26
26
  add_formatter
27
+ use_temporary_cache
28
+ reset_auto_gen_tmp_dir
27
29
  reset_config_and_auto_gen_file
28
30
  line_length_contents = maybe_run_line_length_cop
29
- run_all_cops(line_length_contents)
31
+ result = run_all_cops(line_length_contents)
32
+ reset_auto_gen_tmp_dir
33
+ result
30
34
  end
31
35
 
32
36
  private
33
37
 
38
+ def use_temporary_cache
39
+ # Use a separate cache directory to ensure MinDigits and Max values are calculated.
40
+ # This allows parallel execution (which requires cache) while ensuring MinDigits
41
+ # and Max values are computed, since the cache starts empty.
42
+ @options[:cache_root] = auto_gen_tmp_dir.join('cache').to_s
43
+ end
44
+
45
+ def reset_auto_gen_tmp_dir
46
+ auto_gen_tmp_dir.rmtree if auto_gen_tmp_dir.exist?
47
+ auto_gen_tmp_dir.mkpath
48
+ end
49
+
50
+ def auto_gen_tmp_dir
51
+ @auto_gen_tmp_dir ||= Pathname.new(
52
+ RuboCop::CacheConfig.root_dir_from_toplevel_config
53
+ ).join('auto-gen-tmp').tap do |path|
54
+ path.mkpath
55
+ # Set the temp directory path for ExcludeLimit to use
56
+ RuboCop::ExcludeLimit.tmp_dir = path
57
+ end
58
+ end
59
+
34
60
  def maybe_run_line_length_cop
35
61
  if only_exclude?
36
62
  skip_line_length_cop(PHASE_1_SKIPPED_ONLY_EXCLUDE)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class CLI
5
+ module Command
6
+ # Lists the cops that will inspect the given file or directory.
7
+ # @api private
8
+ class ListEnabledCopsFor < Base
9
+ self.command_name = :list_enabled_cops_for
10
+
11
+ def initialize(env)
12
+ super
13
+
14
+ # Load the configs so the require()s are done for custom cops
15
+ @config = @config_store.for(@options[:list_enabled_cops_for])
16
+ end
17
+
18
+ def run
19
+ print_available_cops
20
+ end
21
+
22
+ private
23
+
24
+ def print_available_cops
25
+ registry = Cop::Registry.global
26
+
27
+ registry.departments.sort.each do |department|
28
+ puts cops_of_department(registry, department).sort
29
+ end
30
+ end
31
+
32
+ def cops_of_department(registry, department)
33
+ registry.with_department(department)
34
+ .map(&:cop_name)
35
+ .select { |cop_name| @config.cop_enabled?(cop_name) }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -25,10 +25,10 @@ module RuboCop
25
25
  puts Cop::Documentation.default_base_url if cops_array.empty?
26
26
 
27
27
  cops_array.each do |cop_name|
28
- cop = registry_hash[cop_name]
29
- next if cop.empty?
28
+ cop = Cop::Registry.global.find_by_cop_name(cop_name)
29
+ next unless cop
30
30
 
31
- url = Cop::Documentation.url_for(cop.first, @config)
31
+ url = Cop::Documentation.url_for(cop, @config)
32
32
  puts url if url
33
33
  end
34
34
 
@@ -38,10 +38,6 @@ module RuboCop
38
38
  def cops_array
39
39
  @cops_array ||= @options[:show_docs_url]
40
40
  end
41
-
42
- def registry_hash
43
- @registry_hash ||= Cop::Registry.global.to_h
44
- end
45
41
  end
46
42
  end
47
43
  end
@@ -60,7 +60,7 @@ module RuboCop
60
60
  def print_opt_out_instruction
61
61
  puts
62
62
  puts 'You can opt out of this message by adding the following to your config ' \
63
- '(see https://docs.rubocop.org/rubocop/extensions.html#extension-suggestions ' \
63
+ '(see https://docs.rubocop.org/rubocop/plugins.html#plugin-suggestions ' \
64
64
  'for more options):'
65
65
  puts ' AllCops:'
66
66
  puts ' SuggestExtensions: false'
data/lib/rubocop/cli.rb CHANGED
@@ -13,7 +13,7 @@ module RuboCop
13
13
  DEFAULT_PARALLEL_OPTIONS = %i[
14
14
  color config debug display_style_guide display_time display_only_fail_level_offenses
15
15
  display_only_failed editor_mode except extra_details fail_level fix_layout format formatters
16
- ignore_disable_comments lint only only_guide_cops require safe
16
+ ignore_disable_comments lint only only_guide_cops out require safe
17
17
  autocorrect safe_autocorrect autocorrect_all
18
18
  ].freeze
19
19
 
@@ -200,18 +200,15 @@ module RuboCop
200
200
  RuboCop::LSP.enable if @options[:editor_mode]
201
201
  end
202
202
 
203
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
204
203
  def handle_exiting_options
205
204
  return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }
206
205
 
207
206
  run_command(:version) if @options[:version] || @options[:verbose_version]
208
- run_command(:show_cops) if @options[:show_cops]
209
- run_command(:show_docs_url) if @options[:show_docs_url]
210
- run_command(:lsp) if @options[:lsp]
211
- run_command(:mcp) if @options[:mcp]
207
+ %i[show_cops list_enabled_cops_for show_docs_url lsp mcp].each do |name|
208
+ run_command(name) if @options[name]
209
+ end
212
210
  raise Finished
213
211
  end
214
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
215
212
 
216
213
  def apply_default_formatter
217
214
  # This must be done after the options have already been processed,
@@ -95,7 +95,8 @@ module RuboCop
95
95
  end
96
96
  end
97
97
 
98
- def analyze # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
98
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
99
+ def analyze
99
100
  return {} if @no_directives
100
101
 
101
102
  analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
@@ -103,9 +104,9 @@ module RuboCop
103
104
 
104
105
  each_directive do |directive|
105
106
  if directive.push?
106
- resolved = resolve_push_cops(directive)
107
- @stack.push(snapshot_cops(analyses, resolved.values.flatten))
108
- apply_push(analyses, resolved, directive.line_number)
107
+ restore_point = analyses.transform_values(&:dup)
108
+ @stack.push(restore_point)
109
+ apply_push(analyses, resolve_push_cops(directive), directive.line_number)
109
110
  elsif directive.pop?
110
111
  pop_state(analyses, directive.line_number) if @stack.any?
111
112
  else
@@ -121,10 +122,7 @@ module RuboCop
121
122
  hash[cop_name] = cop_line_ranges(analysis)
122
123
  end
123
124
  end
124
-
125
- def snapshot_cops(analyses, cop_names)
126
- cop_names.to_h { |name| [name, analyses[name].dup] }
127
- end
125
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
128
126
 
129
127
  def resolve_push_cops(directive)
130
128
  directive.push_args.transform_values do |names|
@@ -155,13 +153,12 @@ module RuboCop
155
153
  end
156
154
 
157
155
  def pop_state(analyses, line)
158
- saved = @stack.pop
159
- saved.each do |cop, old|
160
- cur = analyses[cop]
161
- new_range = cur.start_line_number ? [cur.start_line_number..(line - 1)] : []
162
- ranges = cur.line_ranges + new_range
163
- new_start = old.start_line_number ? line : nil
164
- analyses[cop] = CopAnalysis.new(ranges, new_start)
156
+ restore_point = @stack.pop
157
+ (restore_point.keys | analyses.keys).each do |cop|
158
+ current = analyses[cop]
159
+ new_range = current.start_line_number ? [current.start_line_number..(line - 1)] : []
160
+ new_start = restore_point[cop]&.start_line_number ? line : nil
161
+ analyses[cop] = CopAnalysis.new(current.line_ranges + new_range, new_start)
165
162
  end
166
163
  end
167
164
 
@@ -50,7 +50,8 @@ module RuboCop
50
50
 
51
51
  def disable_offense(offense_range)
52
52
  unbreakable_range = multiline_ranges(offense_range)&.find do |range|
53
- eol_comment_would_be_inside_literal?(offense_range, range)
53
+ offense_range.overlaps?(range) &&
54
+ eol_comment_would_be_inside_literal?(offense_range, range)
54
55
  end
55
56
 
56
57
  if unbreakable_range
@@ -59,11 +59,7 @@ module RuboCop
59
59
  end
60
60
 
61
61
  def content_if_comment_present(corrector, node)
62
- range = range_with_surrounding_space(
63
- children(node).last.source_range,
64
- side: :right
65
- ).end.resize(1)
66
- if range.source == '#'
62
+ if processed_source.comment_at_line(children(node).last.last_line)
67
63
  select_content_to_be_inserted_after_last_element(corrector, node)
68
64
  else
69
65
  node.loc.end.source
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop # rubocop:disable Style/Documentation
5
+ # Autoloads corrector classes used by cops. Classes are autoloaded to reduce the number of
6
+ # required classes because they're referenced only when autocorrection is performed.
7
+
8
+ # rubocop:disable Layout/LineLength
9
+ autoload :AlignmentCorrector, 'rubocop/cop/correctors/alignment_corrector'
10
+ autoload :ConditionCorrector, 'rubocop/cop/correctors/condition_corrector'
11
+ autoload :EachToForCorrector, 'rubocop/cop/correctors/each_to_for_corrector'
12
+ autoload :EmptyLineCorrector, 'rubocop/cop/correctors/empty_line_corrector'
13
+ autoload :ForToEachCorrector, 'rubocop/cop/correctors/for_to_each_corrector'
14
+ autoload :IfThenCorrector, 'rubocop/cop/correctors/if_then_corrector'
15
+ autoload :LambdaLiteralToMethodCorrector, 'rubocop/cop/correctors/lambda_literal_to_method_corrector'
16
+ autoload :LineBreakCorrector, 'rubocop/cop/correctors/line_break_corrector'
17
+ autoload :MultilineLiteralBraceCorrector, 'rubocop/cop/correctors/multiline_literal_brace_corrector'
18
+ autoload :OrderedGemCorrector, 'rubocop/cop/correctors/ordered_gem_corrector'
19
+ autoload :ParenthesesCorrector, 'rubocop/cop/correctors/parentheses_corrector'
20
+ autoload :PercentLiteralCorrector, 'rubocop/cop/correctors/percent_literal_corrector'
21
+ autoload :PunctuationCorrector, 'rubocop/cop/correctors/punctuation_corrector'
22
+ autoload :RequireLibraryCorrector, 'rubocop/cop/correctors/require_library_corrector'
23
+ autoload :SpaceCorrector, 'rubocop/cop/correctors/space_corrector'
24
+ autoload :StringLiteralCorrector, 'rubocop/cop/correctors/string_literal_corrector'
25
+ autoload :UnusedArgCorrector, 'rubocop/cop/correctors/unused_arg_corrector'
26
+ # rubocop:enable Layout/LineLength
27
+ end
28
+ end
@@ -4,16 +4,42 @@ module RuboCop
4
4
  # Allows specified configuration options to have an exclude limit
5
5
  # ie. a maximum value tracked that it can be used by `--auto-gen-config`.
6
6
  module ExcludeLimit
7
+ class << self
8
+ attr_accessor :tmp_dir
9
+
10
+ # Reads the aggregated exclude limit values for a cop from tmp files.
11
+ # Returns a hash like { 'Max' => 81 } or an empty hash if no values were written.
12
+ def read_limits(cop_name)
13
+ cop_dir = cop_dir_for(cop_name)
14
+ return {} unless cop_dir&.directory?
15
+
16
+ limits = {}
17
+ cop_dir.children.each do |filepath|
18
+ next unless filepath.file?
19
+
20
+ values = filepath.readlines.map(&:to_i)
21
+ limits[filepath.basename.to_s] = values.max unless values.empty?
22
+ end
23
+ limits
24
+ end
25
+
26
+ # Returns the tmp directory path for a given cop, or nil if tmp_dir is not set.
27
+ def cop_dir_for(cop_name)
28
+ tmp_dir&.join(cop_name.tr('/', '-'))
29
+ end
30
+ end
31
+
7
32
  # Sets up a configuration option to have an exclude limit tracked.
8
33
  # The parameter name given is transformed into a method name (eg. `Max`
9
34
  # becomes `self.max=` and `MinDigits` becomes `self.min_digits=`).
10
35
  def exclude_limit(parameter_name, method_name: transform(parameter_name))
11
36
  define_method(:"#{method_name}=") do |value|
12
- cfg = config_to_allow_offenses
13
- cfg[:exclude_limit] ||= {}
14
- current_max = cfg[:exclude_limit][parameter_name]
15
- value = [current_max, value].max if current_max
16
- cfg[:exclude_limit][parameter_name] = value
37
+ cop_dir = RuboCop::ExcludeLimit.cop_dir_for(self.class.badge.to_s)
38
+ return unless cop_dir
39
+
40
+ cop_dir.mkpath
41
+ filepath = cop_dir.join(parameter_name)
42
+ filepath.write("#{value}\n", mode: 'a')
17
43
  end
18
44
  end
19
45
 
@@ -70,7 +70,7 @@ module RuboCop
70
70
  def_node_matcher :metadata, <<~PATTERN
71
71
  `{
72
72
  (send _ :metadata= $_)
73
- (send (send _ :metadata) :[]= (str "rubygems_mfa_required") $_)
73
+ (send (send _ :metadata) :[]= {(str "rubygems_mfa_required") (sym :rubygems_mfa_required)} $_)
74
74
  }
75
75
  PATTERN
76
76
 
@@ -78,13 +78,13 @@ module RuboCop
78
78
  def_node_search :metadata_assignment, <<~PATTERN
79
79
  `{
80
80
  (send _ :metadata= _)
81
- (send (send _ :metadata) :[]= (str _) _)
81
+ (send (send _ :metadata) :[]= {str sym} _)
82
82
  }
83
83
  PATTERN
84
84
 
85
85
  # @!method rubygems_mfa_required(node)
86
86
  def_node_search :rubygems_mfa_required, <<~PATTERN
87
- (pair (str "rubygems_mfa_required") $_)
87
+ (pair {(str "rubygems_mfa_required") (sym :rubygems_mfa_required)} $_)
88
88
  PATTERN
89
89
 
90
90
  # @!method true_string?(node)
@@ -25,6 +25,7 @@ module RuboCop
25
25
  def_node_matcher :line_send, <<~PATTERN
26
26
  {
27
27
  (send (send _ {:loc :source_range}) {:line :first_line})
28
+ (send (send (send _ :loc) {:begin :end}) :line)
28
29
  (send _ :first_line)
29
30
  }
30
31
  PATTERN
@@ -124,7 +124,7 @@ module RuboCop
124
124
  def single_line_ignoring_receiver?(node)
125
125
  return false unless node.loc.begin && node.loc.end
126
126
 
127
- node.loc.begin.line == node.loc.end.line
127
+ same_line?(node.loc.begin, node.loc.end)
128
128
  end
129
129
  end
130
130
  end
@@ -158,7 +158,7 @@ module RuboCop
158
158
  @base = find_hash_pair_alignment_base(node)
159
159
  return false if !@base && inside_multiline_chain_arg?(node)
160
160
 
161
- @base ||= lhs.source_range
161
+ @base ||= first_dot_alignment_base(node, rhs) || lhs.source_range
162
162
  return if aligned_with_first_line_dot?(node, rhs)
163
163
 
164
164
  calculate_column_delta_offense(rhs, @base.column)
@@ -172,6 +172,31 @@ module RuboCop
172
172
  first_call.loc.dot.join(first_call.loc.selector)
173
173
  end
174
174
 
175
+ def first_dot_alignment_base(node, rhs)
176
+ return unless rhs.source.start_with?('.', '&.')
177
+
178
+ first_call = first_call_has_a_dot(node)
179
+ dot = first_call.loc.dot
180
+ return unless dot
181
+ return if first_call == node
182
+
183
+ after_block_base = after_multiline_block_base(first_call, node)
184
+ return after_block_base if after_block_base
185
+
186
+ return unless same_line?(dot, first_call.receiver.source_range)
187
+
188
+ dot.join(first_call.loc.selector)
189
+ end
190
+
191
+ def after_multiline_block_base(first_call, node)
192
+ return unless first_call.block_node&.multiline?
193
+
194
+ after_block = first_call.block_node.parent
195
+ return unless after_block&.call_type? && after_block.loc?(:dot) && after_block != node
196
+
197
+ after_block.loc.dot.join(after_block.loc.selector)
198
+ end
199
+
175
200
  def inside_multiline_chain_arg?(node)
176
201
  enclosing_call = find_enclosing_chain_call(node)
177
202
  return false unless enclosing_call
@@ -63,19 +63,9 @@ module RuboCop
63
63
  end
64
64
 
65
65
  def spaces_before_left_parenthesis(node)
66
- receiver = node.receiver
67
- receiver_length = if receiver
68
- receiver.source.length
69
- else
70
- 0
71
- end
72
- without_receiver = node.source[receiver_length..]
73
-
74
- # Escape question mark if any.
75
- method_regexp = Regexp.escape(node.method_name)
76
-
77
- match = without_receiver.match(/^\s*&?\.?\s*#{method_regexp}(\s+)\(/)
78
- match ? match.captures[0].length : 0
66
+ return 0 if node.parenthesized?
67
+
68
+ node.first_argument.source_range.begin_pos - node.loc.selector.end_pos
79
69
  end
80
70
 
81
71
  def space_range(expr, space_length)
@@ -38,6 +38,8 @@ module RuboCop
38
38
  private
39
39
 
40
40
  def same_file?(file_path, required_feature)
41
+ return false unless File.extname(file_path) == '.rb'
42
+
41
43
  file_path == required_feature || remove_ext(file_path) == required_feature
42
44
  end
43
45
 
@@ -40,8 +40,6 @@ module RuboCop
40
40
  class UselessAssignment < Base
41
41
  extend AutoCorrector
42
42
 
43
- include RangeHelp
44
-
45
43
  MSG = 'Useless assignment to variable - `%<variable>s`.'
46
44
 
47
45
  def self.joining_forces
@@ -189,12 +187,9 @@ module RuboCop
189
187
  # rubocop:enable Metrics/AbcSize
190
188
 
191
189
  def remove_exception_assignment_part(corrector, node)
192
- corrector.remove(
193
- range_between(
194
- (node.parent.children.first&.source_range || node.parent.location.keyword).end_pos,
195
- node.source_range.end_pos
196
- )
197
- )
190
+ range = node.parent.children.first&.source_range || node.parent.location.keyword
191
+
192
+ corrector.remove(range.end.join(node.source_range.end))
198
193
  end
199
194
 
200
195
  def rename_variable_with_underscore(corrector, node)
@@ -60,9 +60,7 @@ module RuboCop
60
60
  return true if _cant_be_nil?(node.expression, receiver)
61
61
  end
62
62
 
63
- # Due to how `if/else` are implemented (`elsif` is a child of `if` or another `elsif`),
64
- # using left_siblings will not work correctly for them.
65
- if !else_branch?(node) || (node.if_type? && !node.elsif?)
63
+ if sequentially_reached?(node)
66
64
  node.left_siblings.reverse_each do |sibling|
67
65
  next unless sibling.is_a?(AST::Node)
68
66
 
@@ -82,15 +80,17 @@ module RuboCop
82
80
  !NIL_METHODS.include?(method_name) && !@additional_nil_methods.include?(method_name)
83
81
  end
84
82
 
85
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
83
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
86
84
  def sole_condition_of_parent_if?(node)
87
85
  child = node
88
86
  parent = node.parent
89
87
 
90
88
  while parent
91
89
  if parent.if_type?
92
- condition = parent.condition
93
- return true if !child.equal?(condition) && non_nil_condition?(condition, node)
90
+ unless parent.unless?
91
+ condition = parent.condition
92
+ return true if !child.equal?(condition) && non_nil_condition?(condition, node)
93
+ end
94
94
 
95
95
  parent = find_top_if(parent) if parent.elsif?
96
96
  elsif else_branch?(parent)
@@ -104,7 +104,7 @@ module RuboCop
104
104
 
105
105
  false
106
106
  end
107
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
107
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
108
108
 
109
109
  def non_nil_condition?(condition, node)
110
110
  return true if condition == node
@@ -112,6 +112,17 @@ module RuboCop
112
112
  condition.csend_type? && csend_root_receiver(condition) == node
113
113
  end
114
114
 
115
+ # Whether control reaches `node` by falling through its left siblings rather than by
116
+ # a non-sequential entry. A `resbody` is entered via an exception, the `ensure` branch
117
+ # runs even after a partway raise, and the `else` arm of an `if/elsif` chain is reached by
118
+ # branching (its `if/case` siblings are walked via parent recursion instead).
119
+ def sequentially_reached?(node)
120
+ return false if node.resbody_type?
121
+ return false if node.parent&.ensure_type? && node.parent.branch.equal?(node)
122
+
123
+ !else_branch?(node) || (node.if_type? && !node.elsif?)
124
+ end
125
+
115
126
  def else_branch?(node)
116
127
  node.parent&.if_type? && node.parent.else_branch == node
117
128
  end
@@ -13,11 +13,12 @@ module RuboCop
13
13
  `max=` is deprecated. Use `exclude_limit <ParameterName>` instead.
14
14
  WARNING
15
15
 
16
- cfg = config_to_allow_offenses
17
- cfg[:exclude_limit] ||= {}
18
- current_max = cfg[:exclude_limit][max_parameter_name]
19
- value = [current_max, value].max if current_max
20
- cfg[:exclude_limit][max_parameter_name] = value
16
+ cop_dir = RuboCop::ExcludeLimit.cop_dir_for(self.class.badge.to_s)
17
+ return unless cop_dir
18
+
19
+ cop_dir.mkpath
20
+ filepath = cop_dir.join(max_parameter_name)
21
+ filepath.write("#{value}\n", mode: 'a')
21
22
  end
22
23
 
23
24
  def max_parameter_name
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop # rubocop:disable Style/Documentation
5
+ # Autoloads mixin modules included by cops. Mixins are autoloaded to reduce the number of
6
+ # requires because they're used only when the relevant cop class is loaded.
7
+
8
+ autoload :ArrayMinSize, 'rubocop/cop/mixin/array_min_size'
9
+ autoload :ArraySyntax, 'rubocop/cop/mixin/array_syntax'
10
+ autoload :Alignment, 'rubocop/cop/mixin/alignment'
11
+ autoload :AllowedIdentifiers, 'rubocop/cop/mixin/allowed_identifiers'
12
+ autoload :AllowedMethods, 'rubocop/cop/mixin/allowed_methods'
13
+ autoload :AllowedPattern, 'rubocop/cop/mixin/allowed_pattern'
14
+ autoload :AllowedReceivers, 'rubocop/cop/mixin/allowed_receivers'
15
+ autoload :ForbiddenIdentifiers, 'rubocop/cop/mixin/forbidden_identifiers'
16
+ autoload :ForbiddenPattern, 'rubocop/cop/mixin/forbidden_pattern'
17
+ autoload :AutoCorrector, 'rubocop/cop/mixin/auto_corrector' # rubocop:todo Naming/InclusiveLanguage
18
+ autoload :CheckAssignment, 'rubocop/cop/mixin/check_assignment'
19
+ autoload :CheckLineBreakable, 'rubocop/cop/mixin/check_line_breakable'
20
+ autoload :CheckSingleLineSuitability, 'rubocop/cop/mixin/check_single_line_suitability'
21
+ autoload :ConfigurableMax, 'rubocop/cop/mixin/configurable_max'
22
+ autoload :CodeLength, 'rubocop/cop/mixin/code_length'
23
+ autoload :ConfigurableEnforcedStyle, 'rubocop/cop/mixin/configurable_enforced_style'
24
+ autoload :ConfigurableFormatting, 'rubocop/cop/mixin/configurable_formatting'
25
+ autoload :ConfigurableNaming, 'rubocop/cop/mixin/configurable_naming'
26
+ autoload :ConfigurableNumbering, 'rubocop/cop/mixin/configurable_numbering'
27
+ autoload :DigHelp, 'rubocop/cop/mixin/dig_help'
28
+ autoload :DocumentationComment, 'rubocop/cop/mixin/documentation_comment'
29
+ autoload :Duplication, 'rubocop/cop/mixin/duplication'
30
+ autoload :RangeHelp, 'rubocop/cop/mixin/range_help'
31
+ autoload :AnnotationComment, 'rubocop/cop/mixin/annotation_comment'
32
+ autoload :EmptyParameter, 'rubocop/cop/mixin/empty_parameter'
33
+ autoload :EndKeywordAlignment, 'rubocop/cop/mixin/end_keyword_alignment'
34
+ autoload :EndlessMethodRewriter, 'rubocop/cop/mixin/endless_method_rewriter'
35
+ autoload :EnforceSuperclass, 'rubocop/cop/mixin/enforce_superclass'
36
+ autoload :FirstElementLineBreak, 'rubocop/cop/mixin/first_element_line_break'
37
+ autoload :FrozenStringLiteral, 'rubocop/cop/mixin/frozen_string_literal'
38
+ autoload :GemDeclaration, 'rubocop/cop/mixin/gem_declaration'
39
+ autoload :GemspecHelp, 'rubocop/cop/mixin/gemspec_help'
40
+ autoload :HashAlignmentStyles, 'rubocop/cop/mixin/hash_alignment_styles'
41
+ autoload :HashSubset, 'rubocop/cop/mixin/hash_subset'
42
+ autoload :HashTransformMethod, 'rubocop/cop/mixin/hash_transform_method'
43
+ autoload :IntegerNode, 'rubocop/cop/mixin/integer_node'
44
+ autoload :Interpolation, 'rubocop/cop/mixin/interpolation'
45
+ autoload :LineLengthHelp, 'rubocop/cop/mixin/line_length_help'
46
+ autoload :MatchRange, 'rubocop/cop/mixin/match_range'
47
+ autoload :HashShorthandSyntax, 'rubocop/cop/mixin/hash_shorthand_syntax'
48
+ autoload :MethodComplexity, 'rubocop/cop/mixin/method_complexity'
49
+ autoload :MethodPreference, 'rubocop/cop/mixin/method_preference'
50
+ autoload :MinBodyLength, 'rubocop/cop/mixin/min_body_length'
51
+ autoload :MinBranchesCount, 'rubocop/cop/mixin/min_branches_count'
52
+ autoload :MultilineElementIndentation, 'rubocop/cop/mixin/multiline_element_indentation'
53
+ autoload :MultilineElementLineBreaks, 'rubocop/cop/mixin/multiline_element_line_breaks'
54
+ autoload :MultilineExpressionIndentation, 'rubocop/cop/mixin/multiline_expression_indentation'
55
+ autoload :MultilineLiteralBraceLayout, 'rubocop/cop/mixin/multiline_literal_brace_layout'
56
+ autoload :NegativeConditional, 'rubocop/cop/mixin/negative_conditional'
57
+ autoload :Heredoc, 'rubocop/cop/mixin/heredoc'
58
+ autoload :NilMethods, 'rubocop/cop/mixin/nil_methods'
59
+ autoload :OnNormalIfUnless, 'rubocop/cop/mixin/on_normal_if_unless'
60
+ autoload :OrderedGemNode, 'rubocop/cop/mixin/ordered_gem_node'
61
+ autoload :Parentheses, 'rubocop/cop/mixin/parentheses'
62
+ autoload :PercentArray, 'rubocop/cop/mixin/percent_array'
63
+ autoload :PercentLiteral, 'rubocop/cop/mixin/percent_literal'
64
+ autoload :PrecedingFollowingAlignment, 'rubocop/cop/mixin/preceding_following_alignment'
65
+ autoload :PreferredDelimiters, 'rubocop/cop/mixin/preferred_delimiters'
66
+ autoload :RationalLiteral, 'rubocop/cop/mixin/rational_literal'
67
+ autoload :RequireLibrary, 'rubocop/cop/mixin/require_library'
68
+ autoload :RescueNode, 'rubocop/cop/mixin/rescue_node'
69
+ autoload :SafeAssignment, 'rubocop/cop/mixin/safe_assignment'
70
+ autoload :SpaceAfterPunctuation, 'rubocop/cop/mixin/space_after_punctuation'
71
+ autoload :SpaceBeforePunctuation, 'rubocop/cop/mixin/space_before_punctuation'
72
+ autoload :SurroundingSpace, 'rubocop/cop/mixin/surrounding_space'
73
+ autoload :StatementModifier, 'rubocop/cop/mixin/statement_modifier'
74
+ autoload :StringHelp, 'rubocop/cop/mixin/string_help'
75
+ autoload :StringLiteralsHelp, 'rubocop/cop/mixin/string_literals_help'
76
+ autoload :SymbolHelp, 'rubocop/cop/mixin/symbol_help'
77
+ autoload :TargetRubyVersion, 'rubocop/cop/mixin/target_ruby_version'
78
+ autoload :TrailingBody, 'rubocop/cop/mixin/trailing_body'
79
+ autoload :TrailingComma, 'rubocop/cop/mixin/trailing_comma'
80
+ autoload :UncommunicativeName, 'rubocop/cop/mixin/uncommunicative_name'
81
+ autoload :VisibilityHelp, 'rubocop/cop/mixin/visibility_help'
82
+ autoload :CommentsHelp, 'rubocop/cop/mixin/comments_help'
83
+ autoload :DefNode, 'rubocop/cop/mixin/def_node'
84
+ end
85
+ end