rubocop 1.37.1 → 1.39.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +10 -2
  4. data/lib/rubocop/comment_config.rb +36 -1
  5. data/lib/rubocop/cop/commissioner.rb +3 -1
  6. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  7. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
  8. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  9. data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
  10. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -0
  11. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
  12. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +6 -2
  13. data/lib/rubocop/cop/lint/duplicate_methods.rb +17 -8
  14. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  15. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
  16. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +11 -0
  17. data/lib/rubocop/cop/lint/redundant_require_statement.rb +10 -2
  18. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  19. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  20. data/lib/rubocop/cop/mixin/range_help.rb +23 -0
  21. data/lib/rubocop/cop/mixin/surrounding_space.rb +4 -3
  22. data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
  23. data/lib/rubocop/cop/registry.rb +10 -4
  24. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -25
  25. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  26. data/lib/rubocop/cop/style/class_equality_comparison.rb +7 -5
  27. data/lib/rubocop/cop/style/collection_compact.rb +4 -2
  28. data/lib/rubocop/cop/style/guard_clause.rb +62 -21
  29. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
  30. data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
  31. data/lib/rubocop/cop/style/hash_except.rb +4 -0
  32. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +25 -2
  33. data/lib/rubocop/cop/style/module_function.rb +28 -6
  34. data/lib/rubocop/cop/style/object_then.rb +3 -0
  35. data/lib/rubocop/cop/style/operator_method_call.rb +13 -0
  36. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  37. data/lib/rubocop/cop/style/redundant_each.rb +116 -0
  38. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -3
  39. data/lib/rubocop/cop/team.rb +3 -4
  40. data/lib/rubocop/cop/util.rb +1 -1
  41. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  42. data/lib/rubocop/cops_documentation_generator.rb +2 -1
  43. data/lib/rubocop/ext/processed_source.rb +2 -0
  44. data/lib/rubocop/formatter/offense_count_formatter.rb +8 -5
  45. data/lib/rubocop/formatter/worst_offenders_formatter.rb +6 -3
  46. data/lib/rubocop/options.rb +6 -2
  47. data/lib/rubocop/rspec/cop_helper.rb +21 -1
  48. data/lib/rubocop/rspec/shared_contexts.rb +13 -12
  49. data/lib/rubocop/runner.rb +15 -11
  50. data/lib/rubocop/server/core.rb +16 -0
  51. data/lib/rubocop/version.rb +1 -1
  52. data/lib/rubocop.rb +1 -0
  53. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: caf1d6d45b2da199a82152b2c5b20ffa6a5f99df5115dbd8fbf4c4e895fd00c5
4
- data.tar.gz: 50520bd1d5496971e8b38347dfea57a3387a372b7a815b3c9ef2eb7c1fdc448a
3
+ metadata.gz: 881807be0f0f6eea20bd13bd8f08fdb158a5b155c8d3a22fd748683a68c1fef1
4
+ data.tar.gz: 2a8e7d4b02f1ba468e02a4c20f8e3b830ce2a1d8ff0210f86aaeafab597c8c88
5
5
  SHA512:
6
- metadata.gz: 0fa612429aa29b3ce4480fbbc7d77f1efc6862ac89098bfadf7c8f79a4e255709f6752f1b1075497b9ad17aa261afa006089152d10e0deb4f4361bce95537999
7
- data.tar.gz: b55827239ce8508d6f884f03838c7fe8ca89268c93ac7ab88409af176e527c74d0d24a14680fa3c7c84353eb078a97699429015b69e6efdb051582914d37ff30
6
+ metadata.gz: 11ea36bec754b07912e06b5481f964d10a6dbf5bfd56f99d8a8842ca46d56ae03a342a283d843336f977760c28a697ee995aa98268254a55b1218fa57a9fb5c7
7
+ data.tar.gz: b5096cb4589d9bafdab0b6ab409ea9e7841dc06b274aeb7f7d5a26e703cb216c2a428d695fb2a087637467f1cdd5ac005398c66ee3e7d28d49cb4b203a87667d
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.37', require: false
56
+ gem 'rubocop', '~> 1.39', 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
@@ -2808,6 +2808,7 @@ Naming/MethodParameterName:
2808
2808
  - by
2809
2809
  - db
2810
2810
  - id
2811
+ - if
2811
2812
  - in
2812
2813
  - io
2813
2814
  - ip
@@ -3448,7 +3449,7 @@ Style/Copyright:
3448
3449
 
3449
3450
  Style/DateTime:
3450
3451
  Description: 'Use Time over DateTime.'
3451
- StyleGuide: '#date--time'
3452
+ StyleGuide: '#date-time'
3452
3453
  Enabled: false
3453
3454
  VersionAdded: '0.51'
3454
3455
  VersionChanged: '0.92'
@@ -3819,8 +3820,9 @@ Style/HashExcept:
3819
3820
  Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
3820
3821
  that can be replaced with `Hash#except` method.
3821
3822
  Enabled: pending
3823
+ Safe: false
3822
3824
  VersionAdded: '1.7'
3823
- VersionChanged: '1.31'
3825
+ VersionChanged: '1.39'
3824
3826
 
3825
3827
  Style/HashLikeCase:
3826
3828
  Description: >-
@@ -4696,6 +4698,12 @@ Style/RedundantConditional:
4696
4698
  Enabled: true
4697
4699
  VersionAdded: '0.50'
4698
4700
 
4701
+ Style/RedundantEach:
4702
+ Description: 'Checks for redundant `each`.'
4703
+ Enabled: pending
4704
+ Safe: false
4705
+ VersionAdded: '1.38'
4706
+
4699
4707
  Style/RedundantException:
4700
4708
  Description: "Checks for an obsolete RuntimeException argument in raise/fail."
4701
4709
  StyleGuide: '#no-explicit-runtimeerror'
@@ -4,10 +4,31 @@ module RuboCop
4
4
  # This class parses the special `rubocop:disable` comments in a source
5
5
  # and provides a way to check if each cop is enabled at arbitrary line.
6
6
  class CommentConfig
7
+ extend Forwardable
8
+
9
+ CONFIG_DISABLED_LINE_RANGE_MIN = -Float::INFINITY
10
+
11
+ # This class provides an API compatible with RuboCop::DirectiveComment
12
+ # to be used for cops that are disabled in the config file
13
+ class ConfigDisabledCopDirectiveComment
14
+ attr_reader :text, :loc, :line_number
15
+
16
+ Loc = Struct.new(:expression)
17
+ Expression = Struct.new(:line)
18
+
19
+ def initialize(cop_name)
20
+ @text = "# rubocop:disable #{cop_name}"
21
+ @line_number = CONFIG_DISABLED_LINE_RANGE_MIN
22
+ @loc = Loc.new(Expression.new(CONFIG_DISABLED_LINE_RANGE_MIN))
23
+ end
24
+ end
25
+
7
26
  CopAnalysis = Struct.new(:line_ranges, :start_line_number)
8
27
 
9
28
  attr_reader :processed_source
10
29
 
30
+ def_delegators :@processed_source, :config, :registry
31
+
11
32
  def initialize(processed_source)
12
33
  @processed_source = processed_source
13
34
  end
@@ -25,7 +46,11 @@ module RuboCop
25
46
  end
26
47
 
27
48
  def extra_enabled_comments
28
- extra_enabled_comments_with_names(extras: Hash.new { |h, k| h[k] = [] }, names: Hash.new(0))
49
+ disable_count = Hash.new(0)
50
+ registry.disabled(config).each do |cop|
51
+ disable_count[cop.cop_name] += 1
52
+ end
53
+ extra_enabled_comments_with_names(extras: Hash.new { |h, k| h[k] = [] }, names: disable_count)
29
54
  end
30
55
 
31
56
  def comment_only_line?(line_number)
@@ -50,6 +75,7 @@ module RuboCop
50
75
 
51
76
  def analyze # rubocop:todo Metrics/AbcSize
52
77
  analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
78
+ inject_disabled_cops_directives(analyses)
53
79
 
54
80
  each_directive do |directive|
55
81
  directive.cop_names.each do |cop_name|
@@ -64,6 +90,15 @@ module RuboCop
64
90
  end
65
91
  end
66
92
 
93
+ def inject_disabled_cops_directives(analyses)
94
+ registry.disabled(config).each do |cop|
95
+ analyses[cop.cop_name] = analyze_cop(
96
+ analyses[cop.cop_name],
97
+ DirectiveComment.new(ConfigDisabledCopDirectiveComment.new(cop.cop_name))
98
+ )
99
+ end
100
+ end
101
+
67
102
  def analyze_cop(analysis, directive)
68
103
  # Disabling cops after comments like `#=SomeDslDirective` does not related to single line
69
104
  if !comment_only_line?(directive.line_number) || directive.single_line?
@@ -159,9 +159,11 @@ module RuboCop
159
159
  def with_cop_error_handling(cop, node = nil)
160
160
  yield
161
161
  rescue StandardError => e
162
- raise e if @options[:raise_error]
162
+ raise e if @options[:raise_error] # For internal testing
163
163
 
164
164
  err = ErrorWithAnalyzedFileLocation.new(cause: e, node: node, cop: cop)
165
+ raise err if @options[:raise_cop_error] # From user-input option
166
+
165
167
  @errors << err
166
168
  end
167
169
  end
@@ -90,7 +90,7 @@ module RuboCop
90
90
  # which lines start inside a string literal?
91
91
  return [] if ast.nil?
92
92
 
93
- ast.each_node(:str, :dstr).each_with_object(Set.new) do |str, ranges|
93
+ ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
94
94
  loc = str.location
95
95
 
96
96
  if str.heredoc?
@@ -42,6 +42,14 @@ module RuboCop
42
42
  # ' long'
43
43
  class LineContinuationLeadingSpace < Base
44
44
  include RangeHelp
45
+ extend AutoCorrector
46
+
47
+ LINE_1_ENDING = /['"]\s*\\\n/.freeze
48
+ LINE_2_BEGINNING = /\A\s*['"]/.freeze
49
+ LEADING_STYLE_OFFENSE = /(?<trailing_spaces>\s+)(?<ending>#{LINE_1_ENDING})/.freeze
50
+ TRAILING_STYLE_OFFENSE = /(?<beginning>#{LINE_2_BEGINNING})(?<leading_spaces>\s+)/.freeze
51
+ private_constant :LINE_1_ENDING, :LINE_2_BEGINNING,
52
+ :LEADING_STYLE_OFFENSE, :TRAILING_STYLE_OFFENSE
45
53
 
46
54
  def on_dstr(node)
47
55
  end_of_first_line = node.loc.expression.begin_pos - node.loc.expression.column
@@ -52,9 +60,9 @@ module RuboCop
52
60
  next unless continuation?(raw_line_one)
53
61
 
54
62
  if enforced_style_leading?
55
- investigate_leading_style(raw_line_one, end_of_first_line)
63
+ investigate_leading_style(raw_line_one, raw_line_two, end_of_first_line)
56
64
  else
57
- investigate_trailing_style(raw_line_two, end_of_first_line)
65
+ investigate_trailing_style(raw_line_one, raw_line_two, end_of_first_line)
58
66
  end
59
67
  end
60
68
  end
@@ -65,24 +73,37 @@ module RuboCop
65
73
  processed_source.raw_source.lines[node.first_line - 1, line_range(node).size]
66
74
  end
67
75
 
68
- def investigate_leading_style(first_line, end_of_first_line)
69
- matches = first_line.match(/(?<trailing_spaces>\s+)(?<ending>['"]\s*\\\n)/)
76
+ def investigate_leading_style(first_line, second_line, end_of_first_line)
77
+ matches = first_line.match(LEADING_STYLE_OFFENSE)
70
78
  return if matches.nil?
71
79
 
72
- add_offense(leading_offense_range(end_of_first_line, matches))
80
+ offense_range = leading_offense_range(end_of_first_line, matches)
81
+ add_offense(offense_range) do |corrector|
82
+ insert_pos = end_of_first_line + second_line[LINE_2_BEGINNING].length
83
+ autocorrect(corrector, offense_range, insert_pos, matches[:trailing_spaces])
84
+ end
73
85
  end
74
86
 
75
- def investigate_trailing_style(second_line, end_of_first_line)
76
- matches = second_line.match(/\A(?<beginning>\s*['"])(?<leading_spaces>\s+)/)
87
+ def investigate_trailing_style(first_line, second_line, end_of_first_line)
88
+ matches = second_line.match(TRAILING_STYLE_OFFENSE)
77
89
  return if matches.nil?
78
90
 
79
- add_offense(trailing_offense_range(end_of_first_line, matches))
91
+ offense_range = trailing_offense_range(end_of_first_line, matches)
92
+ add_offense(offense_range) do |corrector|
93
+ insert_pos = end_of_first_line - first_line[LINE_1_ENDING].length
94
+ autocorrect(corrector, offense_range, insert_pos, matches[:leading_spaces])
95
+ end
80
96
  end
81
97
 
82
98
  def continuation?(line)
83
99
  line.end_with?("\\\n")
84
100
  end
85
101
 
102
+ def autocorrect(corrector, offense_range, insert_pos, spaces)
103
+ corrector.remove(offense_range)
104
+ corrector.replace(range_between(insert_pos, insert_pos), spaces)
105
+ end
106
+
86
107
  def leading_offense_range(end_of_first_line, matches)
87
108
  end_pos = end_of_first_line - matches[:ending].length
88
109
  begin_pos = end_pos - matches[:trailing_spaces].length
@@ -92,7 +92,7 @@ module RuboCop
92
92
  # which lines start inside a string literal?
93
93
  return [] if ast.nil?
94
94
 
95
- ast.each_node(:str, :dstr).each_with_object(Set.new) do |str, ranges|
95
+ ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
96
96
  loc = str.location
97
97
 
98
98
  if str.heredoc?
@@ -6,6 +6,9 @@ module RuboCop
6
6
  # Checks for unnecessary additional spaces inside array percent literals
7
7
  # (i.e. %i/%w).
8
8
  #
9
+ # Note that blank percent literals (e.g. `%i( )`) are checked by
10
+ # `Layout/SpaceInsidePercentLiteralDelimiters`.
11
+ #
9
12
  # @example
10
13
  #
11
14
  # # bad
@@ -194,6 +194,8 @@ module RuboCop
194
194
  end
195
195
 
196
196
  def range_inside_hash(node)
197
+ return node.source_range if node.location.begin.nil?
198
+
197
199
  range_between(node.location.begin.end_pos, node.location.end.begin_pos)
198
200
  end
199
201
 
@@ -8,14 +8,31 @@ module RuboCop
8
8
  #
9
9
  # @example
10
10
  #
11
+ # # bad
12
+ # %i( foo bar baz )
13
+ #
11
14
  # # good
12
15
  # %i(foo bar baz)
13
16
  #
14
17
  # # bad
15
18
  # %w( foo bar baz )
16
19
  #
20
+ # # good
21
+ # %w(foo bar baz)
22
+ #
17
23
  # # bad
18
24
  # %x( ls -l )
25
+ #
26
+ # # good
27
+ # %x(ls -l)
28
+ #
29
+ # # bad
30
+ # %w( )
31
+ # %w(
32
+ # )
33
+ #
34
+ # # good
35
+ # %w()
19
36
  class SpaceInsidePercentLiteralDelimiters < Base
20
37
  include MatchRange
21
38
  include PercentLiteral
@@ -34,11 +51,21 @@ module RuboCop
34
51
  end
35
52
 
36
53
  def on_percent_literal(node)
54
+ add_offenses_for_blank_spaces(node)
37
55
  add_offenses_for_unnecessary_spaces(node)
38
56
  end
39
57
 
40
58
  private
41
59
 
60
+ def add_offenses_for_blank_spaces(node)
61
+ range = body_range(node)
62
+ return if range.source.empty? || !range.source.strip.empty?
63
+
64
+ add_offense(range) do |corrector|
65
+ corrector.remove(range)
66
+ end
67
+ end
68
+
42
69
  def add_offenses_for_unnecessary_spaces(node)
43
70
  return unless node.single_line?
44
71
 
@@ -54,6 +81,13 @@ module RuboCop
54
81
  each_match_range(contents_range(node), regex, &blk)
55
82
  end
56
83
  end
84
+
85
+ def body_range(node)
86
+ node.location.expression.with(
87
+ begin_pos: node.location.begin.end_pos,
88
+ end_pos: node.location.end.begin_pos
89
+ )
90
+ end
57
91
  end
58
92
  end
59
93
  end
@@ -38,6 +38,8 @@ module RuboCop
38
38
  # # bad
39
39
  # foo[ ]
40
40
  # foo[ ]
41
+ # foo[
42
+ # ]
41
43
  #
42
44
  # # good
43
45
  # foo[]
@@ -49,6 +51,8 @@ module RuboCop
49
51
  # # bad
50
52
  # foo[]
51
53
  # foo[ ]
54
+ # foo[
55
+ # ]
52
56
  #
53
57
  # # good
54
58
  # foo[ ]
@@ -64,8 +68,6 @@ module RuboCop
64
68
  RESTRICT_ON_SEND = %i[[] []=].freeze
65
69
 
66
70
  def on_send(node)
67
- return if node.multiline?
68
-
69
71
  tokens = processed_source.tokens_within(node)
70
72
  left_token = left_ref_bracket(node, tokens)
71
73
  return unless left_token
@@ -76,6 +78,8 @@ module RuboCop
76
78
  return empty_offenses(node, left_token, right_token, EMPTY_MSG)
77
79
  end
78
80
 
81
+ return if node.multiline?
82
+
79
83
  if style == :no_space
80
84
  no_space_offenses(node, left_token, right_token, MSG)
81
85
  else
@@ -51,8 +51,8 @@ module RuboCop
51
51
  # alias bar foo
52
52
  class DuplicateMethods < Base
53
53
  MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
54
-
55
54
  RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr].freeze
55
+ DEF_TYPES = %i[def defs].freeze
56
56
 
57
57
  def initialize(config = nil, options = nil)
58
58
  super
@@ -127,8 +127,8 @@ module RuboCop
127
127
  found_method(node, "#{enclosing}.#{name}")
128
128
  end
129
129
 
130
- def message_for_dup(node, method_name)
131
- format(MSG, method: method_name, defined: source_location(@definitions[method_name]),
130
+ def message_for_dup(node, method_name, key)
131
+ format(MSG, method: method_name, defined: source_location(@definitions[key]),
132
132
  current: source_location(node))
133
133
  end
134
134
 
@@ -156,18 +156,27 @@ module RuboCop
156
156
  end
157
157
 
158
158
  def found_method(node, method_name)
159
- if @definitions.key?(method_name)
160
- loc = case node.type
161
- when :def, :defs
159
+ key = method_key(node, method_name)
160
+
161
+ if @definitions.key?(key)
162
+ loc = if DEF_TYPES.include?(node.type)
162
163
  node.loc.keyword.join(node.loc.name)
163
164
  else
164
165
  node.loc.expression
165
166
  end
166
- message = message_for_dup(node, method_name)
167
+ message = message_for_dup(node, method_name, key)
167
168
 
168
169
  add_offense(loc, message: message)
169
170
  else
170
- @definitions[method_name] = node
171
+ @definitions[key] = node
172
+ end
173
+ end
174
+
175
+ def method_key(node, method_name)
176
+ if (ancestor_def = node.each_ancestor(*DEF_TYPES).first)
177
+ "#{ancestor_def.method_name}.#{method_name}"
178
+ else
179
+ method_name
171
180
  end
172
181
  end
173
182
 
@@ -141,7 +141,7 @@ module RuboCop
141
141
  if empty_if_branch?(node) && else_branch?(node)
142
142
  node.source_range.with(end_pos: node.loc.else.begin_pos)
143
143
  elsif node.loc.else
144
- node.source_range.with(end_pos: node.loc.else.begin_pos - 1)
144
+ node.source_range.with(end_pos: node.condition.loc.expression.end_pos)
145
145
  elsif all_branches_body_missing?(node)
146
146
  if_node = node.ancestors.detect(&:if?)
147
147
  node.source_range.with(end_pos: if_node.loc.end.end_pos)
@@ -50,9 +50,7 @@ module RuboCop
50
50
 
51
51
  def on_new_investigation
52
52
  each_missing_enable do |cop, line_range|
53
- # This has to remain a strict inequality to handle
54
- # the case when max_range is Float::INFINITY
55
- next if line_range.max - line_range.min < max_range + 2
53
+ next if acceptable_range?(cop, line_range)
56
54
 
57
55
  range = source_range(processed_source.buffer, line_range.min, (0..0))
58
56
  comment = processed_source.comment_at_line(line_range.begin)
@@ -69,6 +67,23 @@ module RuboCop
69
67
  end
70
68
  end
71
69
 
70
+ def acceptable_range?(cop, line_range)
71
+ # This has to remain a strict inequality to handle
72
+ # the case when max_range is Float::INFINITY
73
+ return true if line_range.max - line_range.min < max_range + 2
74
+ # This cop is disabled in the config, it is not expected to be re-enabled
75
+ return true if line_range.min == CommentConfig::CONFIG_DISABLED_LINE_RANGE_MIN
76
+
77
+ cop_class = RuboCop::Cop::Registry.global.find_by_cop_name cop
78
+ if cop_class &&
79
+ !processed_source.registry.enabled?(cop_class, config) &&
80
+ line_range.max == Float::INFINITY
81
+ return true
82
+ end
83
+
84
+ false
85
+ end
86
+
72
87
  def max_range
73
88
  @max_range ||= cop_config['MaximumRangeSize']
74
89
  end
@@ -113,6 +113,7 @@ module RuboCop
113
113
  def each_line_range(cop, line_ranges)
114
114
  line_ranges.each_with_index do |line_range, line_range_index|
115
115
  next if ignore_offense?(line_range)
116
+ next if expected_final_disable?(cop, line_range)
116
117
 
117
118
  comment = processed_source.comment_at_line(line_range.begin)
118
119
  redundant = if all_disabled?(comment)
@@ -179,11 +180,21 @@ module RuboCop
179
180
  end
180
181
 
181
182
  def ignore_offense?(line_range)
183
+ return true if line_range.min == CommentConfig::CONFIG_DISABLED_LINE_RANGE_MIN
184
+
182
185
  disabled_ranges.any? do |range|
183
186
  range.cover?(line_range.min) && range.cover?(line_range.max)
184
187
  end
185
188
  end
186
189
 
190
+ def expected_final_disable?(cop, line_range)
191
+ # A cop which is disabled in the config is being re-disabled until end of file
192
+ cop_class = RuboCop::Cop::Registry.global.find_by_cop_name cop
193
+ cop_class &&
194
+ !processed_source.registry.enabled?(cop_class, config) &&
195
+ line_range.max == Float::INFINITY
196
+ end
197
+
187
198
  def department_disabled?(cop, comment)
188
199
  directive = DirectiveComment.new(comment)
189
200
  directive.in_directive_department?(cop) && !directive.overridden_by_department?(cop)
@@ -20,6 +20,7 @@ module RuboCop
20
20
  # * 2.5+ ... Add `pp` above
21
21
  # * 2.7+ ... Add `ruby2_keywords` above
22
22
  # * 3.1+ ... Add `fiber` above
23
+ # * 3.2+ ... `set`
23
24
  #
24
25
  # This cop target those features.
25
26
  #
@@ -48,7 +49,13 @@ module RuboCop
48
49
  return unless redundant_require_statement?(node)
49
50
 
50
51
  add_offense(node) do |corrector|
51
- range = range_with_surrounding_space(node.loc.expression, side: :right)
52
+ if node.parent.respond_to?(:modifier_form?) && node.parent.modifier_form?
53
+ corrector.insert_after(node.parent, "\nend")
54
+
55
+ range = range_with_surrounding_space(node.loc.expression, side: :right)
56
+ else
57
+ range = range_by_whole_lines(node.source_range, include_final_newline: true)
58
+ end
52
59
 
53
60
  corrector.remove(range)
54
61
  end
@@ -63,7 +70,8 @@ module RuboCop
63
70
  (target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
64
71
  (target_ruby_version >= 2.5 && feature_name == 'pp') ||
65
72
  (target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
66
- (target_ruby_version >= 3.1 && feature_name == 'fiber')
73
+ (target_ruby_version >= 3.1 && feature_name == 'fiber') ||
74
+ (target_ruby_version >= 3.2 && feature_name == 'set')
67
75
  end
68
76
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
69
77
  end
@@ -116,7 +116,7 @@ module RuboCop
116
116
  private
117
117
 
118
118
  def comment_between_rescue_and_end?(node)
119
- ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block).first
119
+ ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block, :numblock).first
120
120
  return unless ancestor
121
121
 
122
122
  end_line = ancestor.loc.end.line
@@ -20,7 +20,7 @@ module RuboCop
20
20
  #
21
21
  # @example CountRepeatedAttributes: false (default is true)
22
22
  #
23
- # # `model` and `current_user`, refenced 3 times each,
23
+ # # `model` and `current_user`, referenced 3 times each,
24
24
  # # are each counted as only 1 branch each if
25
25
  # # `CountRepeatedAttributes` is set to 'false'
26
26
  #
@@ -126,6 +126,29 @@ module RuboCop
126
126
  pos += size * step while condition && src[pos + offset, size] == needle
127
127
  pos.negative? ? 0 : pos
128
128
  end
129
+
130
+ def range_with_comments_and_lines(node)
131
+ range_by_whole_lines(range_with_comments(node), include_final_newline: true)
132
+ end
133
+
134
+ def range_with_comments(node)
135
+ ranges = [
136
+ node,
137
+ *@processed_source.ast_with_comments[node]
138
+ ].map do |element|
139
+ element.location.expression
140
+ end
141
+ ranges.reduce do |result, range|
142
+ add_range(result, range)
143
+ end
144
+ end
145
+
146
+ def add_range(range1, range2)
147
+ range1.with(
148
+ begin_pos: [range1.begin_pos, range2.begin_pos].min,
149
+ end_pos: [range1.end_pos, range2.end_pos].max
150
+ )
151
+ end
129
152
  end
130
153
  end
131
154
  end
@@ -118,14 +118,15 @@ module RuboCop
118
118
  end
119
119
 
120
120
  def offending_empty_no_space?(config, left_token, right_token)
121
- config == 'no_space' && !no_space_between?(left_token, right_token)
121
+ config == 'no_space' && !no_character_between?(left_token, right_token)
122
122
  end
123
123
 
124
124
  def space_between?(left_bracket_token, right_bracket_token)
125
- left_bracket_token.end_pos + 1 == right_bracket_token.begin_pos
125
+ left_bracket_token.end_pos + 1 == right_bracket_token.begin_pos &&
126
+ processed_source.buffer.source[left_bracket_token.end_pos] == ' '
126
127
  end
127
128
 
128
- def no_space_between?(left_bracket_token, right_bracket_token)
129
+ def no_character_between?(left_bracket_token, right_bracket_token)
129
130
  left_bracket_token.end_pos == right_bracket_token.begin_pos
130
131
  end
131
132
  end
@@ -1,18 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'set'
4
+
3
5
  module RuboCop
4
6
  module Cop
5
7
  # Help methods for determining node visibility.
6
8
  module VisibilityHelp
7
9
  extend NodePattern::Macros
8
10
 
9
- VISIBILITY_SCOPES = %i[private protected public].freeze
11
+ VISIBILITY_SCOPES = ::Set[:private, :protected, :public].freeze
10
12
 
11
13
  private
12
14
 
13
15
  def node_visibility(node)
14
- scope = find_visibility_start(node)
15
- scope&.method_name || :public
16
+ node_visibility_from_visibility_inline(node) ||
17
+ node_visibility_from_visibility_block(node) ||
18
+ :public
19
+ end
20
+
21
+ def node_visibility_from_visibility_inline(node)
22
+ return unless node.def_type?
23
+
24
+ node_visibility_from_visibility_inline_on_def(node) ||
25
+ node_visibility_from_visibility_inline_on_method_name(node)
26
+ end
27
+
28
+ def node_visibility_from_visibility_inline_on_def(node)
29
+ parent = node.parent
30
+ parent.method_name if visibility_inline_on_def?(parent)
31
+ end
32
+
33
+ def node_visibility_from_visibility_inline_on_method_name(node)
34
+ node.right_siblings.reverse.find do |sibling|
35
+ visibility_inline_on_method_name?(sibling, method_name: node.method_name)
36
+ end&.method_name
37
+ end
38
+
39
+ def node_visibility_from_visibility_block(node)
40
+ find_visibility_start(node)&.method_name
16
41
  end
17
42
 
18
43
  def find_visibility_start(node)
@@ -21,7 +46,7 @@ module RuboCop
21
46
 
22
47
  # Navigate to find the last protected method
23
48
  def find_visibility_end(node)
24
- possible_visibilities = VISIBILITY_SCOPES - [node_visibility(node)]
49
+ possible_visibilities = VISIBILITY_SCOPES - ::Set[node_visibility(node)]
25
50
  right = node.right_siblings
26
51
  right.find do |child_node|
27
52
  possible_visibilities.include?(node_visibility(child_node))
@@ -30,7 +55,17 @@ module RuboCop
30
55
 
31
56
  # @!method visibility_block?(node)
32
57
  def_node_matcher :visibility_block?, <<~PATTERN
33
- (send nil? { :private :protected :public })
58
+ (send nil? VISIBILITY_SCOPES)
59
+ PATTERN
60
+
61
+ # @!method visibility_inline_on_def?(node)
62
+ def_node_matcher :visibility_inline_on_def?, <<~PATTERN
63
+ (send nil? VISIBILITY_SCOPES def)
64
+ PATTERN
65
+
66
+ # @!method visibility_inline_on_method_name?(node, method_name:)
67
+ def_node_matcher :visibility_inline_on_method_name?, <<~PATTERN
68
+ (send nil? VISIBILITY_SCOPES (sym %method_name))
34
69
  PATTERN
35
70
  end
36
71
  end