rubocop 1.37.1 → 1.39.0

Sign up to get free protection for your applications and to get access to all the features.
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