rubocop 1.80.1 → 1.82.1

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +35 -7
  4. data/config/obsoletion.yml +4 -0
  5. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  6. data/lib/rubocop/cli.rb +3 -3
  7. data/lib/rubocop/comment_config.rb +62 -17
  8. data/lib/rubocop/config_loader.rb +5 -2
  9. data/lib/rubocop/config_loader_resolver.rb +7 -6
  10. data/lib/rubocop/config_store.rb +5 -0
  11. data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
  12. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
  13. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -4
  14. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
  15. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  16. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  17. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  18. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
  19. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  20. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  21. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  22. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
  23. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
  24. data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
  25. data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
  26. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  27. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -4
  28. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  29. data/lib/rubocop/cop/layout/indentation_width.rb +12 -1
  30. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  31. data/lib/rubocop/cop/layout/line_length.rb +17 -5
  32. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  33. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -1
  34. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +6 -4
  35. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
  36. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  37. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  38. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  39. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  40. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  41. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  42. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
  43. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  44. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  45. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  46. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  47. data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
  48. data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
  49. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  50. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +16 -6
  51. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  52. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  53. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  54. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
  55. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  56. data/lib/rubocop/cop/lint/self_assignment.rb +10 -2
  57. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  58. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  59. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  60. data/lib/rubocop/cop/lint/useless_assignment.rb +44 -16
  61. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  62. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +1 -1
  63. data/lib/rubocop/cop/lint/void.rb +7 -0
  64. data/lib/rubocop/cop/message_annotator.rb +1 -1
  65. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  66. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  67. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -4
  68. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  69. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
  70. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  71. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  72. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  73. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  74. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  75. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  76. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
  77. data/lib/rubocop/cop/naming/method_name.rb +4 -2
  78. data/lib/rubocop/cop/naming/predicate_method.rb +19 -6
  79. data/lib/rubocop/cop/security/json_load.rb +33 -11
  80. data/lib/rubocop/cop/style/array_intersect.rb +2 -2
  81. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  82. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
  83. data/lib/rubocop/cop/style/case_equality.rb +11 -13
  84. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
  85. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -14
  86. data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
  87. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  88. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  89. data/lib/rubocop/cop/style/endless_method.rb +15 -2
  90. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  91. data/lib/rubocop/cop/style/float_division.rb +15 -1
  92. data/lib/rubocop/cop/style/guard_clause.rb +0 -11
  93. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  94. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  95. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
  96. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  97. data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
  98. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  99. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  100. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
  101. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  102. data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
  103. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  104. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  105. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  106. data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
  107. data/lib/rubocop/cop/style/redundant_parentheses.rb +13 -10
  108. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
  109. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
  110. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  111. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  112. data/lib/rubocop/cop/style/safe_navigation.rb +6 -0
  113. data/lib/rubocop/cop/style/semicolon.rb +23 -7
  114. data/lib/rubocop/cop/style/sole_nested_conditional.rb +8 -1
  115. data/lib/rubocop/cop/style/string_concatenation.rb +16 -12
  116. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  117. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  118. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  119. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  120. data/lib/rubocop/cop/util.rb +2 -3
  121. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  122. data/lib/rubocop/cops_documentation_generator.rb +4 -4
  123. data/lib/rubocop/directive_comment.rb +46 -3
  124. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -0
  125. data/lib/rubocop/lsp/diagnostic.rb +10 -14
  126. data/lib/rubocop/lsp/stdin_runner.rb +0 -16
  127. data/lib/rubocop/magic_comment.rb +20 -0
  128. data/lib/rubocop/rake_task.rb +1 -1
  129. data/lib/rubocop/remote_config.rb +7 -8
  130. data/lib/rubocop/result_cache.rb +38 -27
  131. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  132. data/lib/rubocop/rspec/support.rb +1 -1
  133. data/lib/rubocop/runner.rb +4 -0
  134. data/lib/rubocop/target_ruby.rb +11 -2
  135. data/lib/rubocop/version.rb +1 -1
  136. data/lib/rubocop.rb +2 -0
  137. data/lib/ruby_lsp/rubocop/addon.rb +23 -8
  138. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  139. metadata +9 -7
@@ -8,8 +8,8 @@ module RuboCop
8
8
  MSG = 'Space missing after %<token>s.'
9
9
 
10
10
  def on_new_investigation
11
- each_missing_space(processed_source.tokens) do |token|
12
- add_offense(token.pos, message: format(MSG, token: kind(token))) do |corrector|
11
+ each_missing_space(processed_source.tokens) do |token, kind|
12
+ add_offense(token.pos, message: format(MSG, token: kind)) do |corrector|
13
13
  PunctuationCorrector.add_space(corrector, token)
14
14
  end
15
15
  end
@@ -19,11 +19,12 @@ module RuboCop
19
19
 
20
20
  def each_missing_space(tokens)
21
21
  tokens.each_cons(2) do |token1, token2|
22
- next unless kind(token1)
22
+ kind = kind(token1, token2)
23
+ next unless kind
23
24
  next unless space_missing?(token1, token2)
24
25
  next unless space_required_before?(token2)
25
26
 
26
- yield token1
27
+ yield token1, kind
27
28
  end
28
29
  end
29
30
 
@@ -100,12 +100,6 @@ module RuboCop
100
100
  node.parent.send_type?
101
101
  end
102
102
 
103
- def max_line_length
104
- return unless config.cop_enabled?('Layout/LineLength')
105
-
106
- config.for_cop('Layout/LineLength')['Max']
107
- end
108
-
109
103
  def comment_disables_cop?(comment)
110
104
  regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
111
105
  Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
@@ -95,13 +95,16 @@ module RuboCop
95
95
  node.multiline? && !allowed_multiline_argument?(node)
96
96
  end
97
97
 
98
+ # rubocop:disable Metrics/AbcSize
98
99
  def method_name_and_arguments_on_same_line?(node)
99
- return false unless node.call_type?
100
+ return false if !node.call_type? || node.last_line != node.last_argument.last_line
101
+ return true if node.last_argument.hash_type? && node.last_argument.braces?
100
102
 
101
- line = node.loc.selector.nil? ? node.loc.line : node.loc.selector.line
103
+ line = node.loc.selector&.line || node.loc.line
102
104
 
103
- line == node.last_argument.last_line && node.last_line == node.last_argument.last_line
105
+ line == node.last_argument.last_line
104
106
  end
107
+ # rubocop:enable Metrics/AbcSize
105
108
 
106
109
  # A single argument with the closing bracket on the same line as the end
107
110
  # of the argument is not considered multiline, even if the argument
@@ -140,7 +143,7 @@ module RuboCop
140
143
  end
141
144
 
142
145
  def last_item_precedes_newline?(node)
143
- after_last_item = node.children.last.source_range.end.join(node.loc.end.begin)
146
+ after_last_item = node.children.last.source_range.end.join(node.source_range.end)
144
147
 
145
148
  after_last_item.source.start_with?(/,?\s*(#.*)?\n/)
146
149
  end
@@ -185,7 +188,7 @@ module RuboCop
185
188
 
186
189
  def heredoc?(node)
187
190
  return false unless node.is_a?(RuboCop::AST::Node)
188
- return true if node.loc.respond_to?(:heredoc_body)
191
+ return true if node.loc?(:heredoc_body)
189
192
 
190
193
  return heredoc_send?(node) if node.send_type?
191
194
 
@@ -147,7 +147,9 @@ module RuboCop
147
147
  alias on_defs on_def
148
148
 
149
149
  def on_alias(node)
150
- handle_method_name(node.new_identifier, node.new_identifier.value)
150
+ return unless (new_identifier = node.new_identifier).sym_type?
151
+
152
+ handle_method_name(new_identifier, new_identifier.value)
151
153
  end
152
154
 
153
155
  private
@@ -232,7 +234,7 @@ module RuboCop
232
234
  end
233
235
 
234
236
  def range_position(node)
235
- if node.loc.respond_to?(:selector)
237
+ if node.loc?(:selector)
236
238
  selector_end_pos = node.loc.selector.end_pos + 1
237
239
  expr_end_pos = node.source_range.end_pos
238
240
 
@@ -14,7 +14,7 @@ module RuboCop
14
14
  # method calls are assumed to return boolean values. The cop does not make an assessment
15
15
  # if the return type is unknown (non-predicate method calls, variables, etc.).
16
16
  #
17
- # NOTE: Operator methods (`def ==`, etc.) are ignored.
17
+ # NOTE: The `initialize` method and operator methods (`def ==`, etc.) are ignored.
18
18
  #
19
19
  # By default, the cop runs in `conservative` mode, which allows a method to be named
20
20
  # with a question mark as long as at least one return value is boolean. In `aggressive`
@@ -113,6 +113,18 @@ module RuboCop
113
113
  # true
114
114
  # end
115
115
  #
116
+ # @example AllowedMethods: [call] (default)
117
+ # # good
118
+ # def call
119
+ # foo == bar
120
+ # end
121
+ #
122
+ # @example AllowedPatterns: [\Afoo]
123
+ # # good
124
+ # def foo?
125
+ # 'foo'
126
+ # end
127
+ #
116
128
  # @example AllowBangMethods: false (default)
117
129
  # # bad
118
130
  # def save!
@@ -149,7 +161,8 @@ module RuboCop
149
161
  private
150
162
 
151
163
  def allowed?(node)
152
- allowed_method?(node.method_name) ||
164
+ node.method?(:initialize) ||
165
+ allowed_method?(node.method_name) ||
153
166
  matches_allowed_pattern?(node.method_name) ||
154
167
  allowed_bang_method?(node) ||
155
168
  node.operator_method? ||
@@ -180,8 +193,7 @@ module RuboCop
180
193
  return_values << extract_return_value(return_node)
181
194
  end
182
195
 
183
- last_value = last_value(node)
184
- return_values << last_value if last_value
196
+ return_values << last_value(node)
185
197
 
186
198
  process_return_values(return_values)
187
199
  end
@@ -234,8 +246,9 @@ module RuboCop
234
246
  end
235
247
 
236
248
  def last_value(node)
237
- value = node.begin_type? ? node.children.last : node
238
- value&.return_type? ? extract_return_value(value) : value
249
+ value = node.begin_type? ? node.children.last || s(:nil) : node
250
+
251
+ value.return_type? ? extract_return_value(value) : value
239
252
  end
240
253
 
241
254
  def process_return_values(return_values)
@@ -6,22 +6,40 @@ module RuboCop
6
6
  # Checks for the use of JSON class methods which have potential
7
7
  # security issues.
8
8
  #
9
+ # `JSON.load` and similar methods allow deserialization of arbitrary ruby objects:
10
+ #
11
+ # [source,ruby]
12
+ # ----
13
+ # require 'json/add/string'
14
+ # result = JSON.load('{ "json_class": "String", "raw": [72, 101, 108, 108, 111] }')
15
+ # pp result # => "Hello"
16
+ # ----
17
+ #
18
+ # Never use `JSON.load` for untrusted user input. Prefer `JSON.parse` unless you have
19
+ # a concrete use-case for `JSON.load`.
20
+ #
21
+ # NOTE: Starting with `json` gem version 2.8.0, triggering this behavior without explicitly
22
+ # passing the `create_additions` keyword argument emits a deprecation warning, with the
23
+ # goal of being secure by default in the next major version 3.0.0.
24
+ #
9
25
  # @safety
10
26
  # This cop's autocorrection is unsafe because it's potentially dangerous.
11
- # If using a stream, like `JSON.load(open('file'))`, it will need to call
27
+ # If using a stream, like `JSON.load(open('file'))`, you will need to call
12
28
  # `#read` manually, like `JSON.parse(open('file').read)`.
13
- # If reading single values (rather than proper JSON objects), like
14
- # `JSON.load('false')`, it will need to pass the `quirks_mode: true`
15
- # option, like `JSON.parse('false', quirks_mode: true)`.
16
29
  # Other similar issues may apply.
17
30
  #
18
31
  # @example
19
32
  # # bad
20
- # JSON.load("{}")
21
- # JSON.restore("{}")
33
+ # JSON.load('{}')
34
+ # JSON.restore('{}')
22
35
  #
23
36
  # # good
24
- # JSON.parse("{}")
37
+ # JSON.parse('{}')
38
+ # JSON.unsafe_load('{}')
39
+ #
40
+ # # good - explicit use of `create_additions` option
41
+ # JSON.load('{}', create_additions: true)
42
+ # JSON.load('{}', create_additions: false)
25
43
  #
26
44
  class JSONLoad < Base
27
45
  extend AutoCorrector
@@ -29,13 +47,17 @@ module RuboCop
29
47
  MSG = 'Prefer `JSON.parse` over `JSON.%<method>s`.'
30
48
  RESTRICT_ON_SEND = %i[load restore].freeze
31
49
 
32
- # @!method json_load(node)
33
- def_node_matcher :json_load, <<~PATTERN
34
- (send (const {nil? cbase} :JSON) ${:load :restore} ...)
50
+ # @!method insecure_json_load(node)
51
+ def_node_matcher :insecure_json_load, <<~PATTERN
52
+ (
53
+ send (const {nil? cbase} :JSON) ${:load :restore}
54
+ ...
55
+ !(hash `(sym $:create_additions))
56
+ )
35
57
  PATTERN
36
58
 
37
59
  def on_send(node)
38
- json_load(node) do |method|
60
+ insecure_json_load(node) do |method|
39
61
  add_offense(node.loc.selector, message: format(MSG, method: method)) do |corrector|
40
62
  corrector.replace(node.loc.selector, 'parse')
41
63
  end
@@ -95,7 +95,7 @@ module RuboCop
95
95
  $(call
96
96
  {
97
97
  (begin (send $_ :& $_))
98
- (call $_ :intersection $_)
98
+ (call $!nil? :intersection $_)
99
99
  }
100
100
  $%1
101
101
  )
@@ -107,7 +107,7 @@ module RuboCop
107
107
  $(call
108
108
  {
109
109
  (begin (send $_ :& $_))
110
- (call $_ :intersection $_)
110
+ (call $!nil? :intersection $_)
111
111
  }
112
112
  %ARRAY_SIZE_METHODS
113
113
  )
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Use `include?(element)` instead of `intersect?([element])`.
7
+ #
8
+ # @safety
9
+ # The receiver might not be an array.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # array.intersect?([element])
14
+ #
15
+ # # good
16
+ # array.include?(element)
17
+ class ArrayIntersectWithSingleElement < Base
18
+ extend AutoCorrector
19
+
20
+ MSG = 'Use `include?(element)` instead of `intersect?([element])`.'
21
+
22
+ RESTRICT_ON_SEND = %i[intersect?].freeze
23
+
24
+ # @!method single_element(node)
25
+ def_node_matcher :single_element, <<~PATTERN
26
+ (send _ _ $(array $_))
27
+ PATTERN
28
+
29
+ def on_send(node)
30
+ array, element = single_element(node)
31
+ return unless array
32
+
33
+ add_offense(
34
+ node.source_range.with(begin_pos: node.loc.selector.begin_pos)
35
+ ) do |corrector|
36
+ corrector.replace(node.loc.selector, 'include?')
37
+ corrector.replace(
38
+ array,
39
+ array.percent_literal? ? element.value.inspect : element.source
40
+ )
41
+ end
42
+ end
43
+ alias on_csend on_send
44
+ end
45
+ end
46
+ end
47
+ end
@@ -41,8 +41,7 @@ module RuboCop
41
41
 
42
42
  def check(node)
43
43
  return if node.heredoc?
44
- return unless node.loc.respond_to?(:begin)
45
- return unless node.loc.begin
44
+ return unless node.loc?(:begin)
46
45
 
47
46
  source = node.loc.begin.source
48
47
  if requires_percent_q?(source)
@@ -3,31 +3,36 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of the case equality operator(===).
6
+ # Checks for uses of the case equality operator (`===`).
7
7
  #
8
8
  # If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
9
9
  # the case equality operator is a constant.
10
-
10
+ #
11
11
  # If `AllowOnSelfClass` option is enabled, the cop will ignore violations when the receiver of
12
12
  # the case equality operator is `self.class`. Note intermediate variables are not accepted.
13
13
  #
14
+ # NOTE: Regexp case equality (`/regexp/ === var`) is allowed because changing it to
15
+ # `/regexp/.match?(var)` needs to take into account `Regexp.last_match?`, `$~`, `$1`, etc.
16
+ # This potentially incompatible transformation is handled by `Performance/RegexpMatch` cop.
17
+ #
14
18
  # @example
15
19
  # # bad
16
20
  # (1..100) === 7
17
- # /something/ === some_string
18
21
  #
19
22
  # # good
20
- # something.is_a?(Array)
21
23
  # (1..100).include?(7)
22
- # /something/.match?(some_string)
23
24
  #
24
25
  # @example AllowOnConstant: false (default)
25
26
  # # bad
26
27
  # Array === something
27
28
  #
29
+ # # good
30
+ # something.is_a?(Array)
31
+ #
28
32
  # @example AllowOnConstant: true
29
33
  # # good
30
34
  # Array === something
35
+ # something.is_a?(Array)
31
36
  #
32
37
  # @example AllowOnSelfClass: false (default)
33
38
  # # bad
@@ -51,7 +56,7 @@ module RuboCop
51
56
 
52
57
  def on_send(node)
53
58
  case_equality?(node) do |lhs, rhs|
54
- return if lhs.const_type? && !lhs.module_name?
59
+ return if lhs.regexp_type? || (lhs.const_type? && !lhs.module_name?)
55
60
 
56
61
  add_offense(node.loc.selector) do |corrector|
57
62
  replacement = replacement(lhs, rhs)
@@ -71,13 +76,6 @@ module RuboCop
71
76
 
72
77
  def replacement(lhs, rhs)
73
78
  case lhs.type
74
- when :regexp
75
- # The automatic correction from `a === b` to `a.match?(b)` needs to
76
- # consider `Regexp.last_match?`, `$~`, `$1`, and etc.
77
- # This correction is expected to be supported by `Performance/Regexp` cop.
78
- # See: https://github.com/rubocop/rubocop-performance/issues/152
79
- #
80
- # So here is noop.
81
79
  when :begin
82
80
  begin_replacement(lhs, rhs)
83
81
  when :const
@@ -183,6 +183,7 @@ module RuboCop
183
183
 
184
184
  def check_nested_style(node)
185
185
  return unless compact_node_name?(node)
186
+ return if node.parent&.type?(:class, :module)
186
187
 
187
188
  add_offense(node.loc.name, message: NESTED_MSG) do |corrector|
188
189
  autocorrect(corrector, node)
@@ -213,9 +213,7 @@ module RuboCop
213
213
  ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals.'
214
214
  VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
215
215
  ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
216
- LINE_LENGTH = 'Layout/LineLength'
217
216
  ENABLED = 'Enabled'
218
- MAX = 'Max'
219
217
  SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'
220
218
 
221
219
  # The shovel operator `<<` does not have its own type. It is a `send`
@@ -399,7 +397,7 @@ module RuboCop
399
397
  # of the longest line + the length of the corrected assignment is
400
398
  # greater than the max configured line length
401
399
  def correction_exceeds_line_limit?(node, branches)
402
- return false unless line_length_cop_enabled?
400
+ return false unless config.cop_enabled?('Layout/LineLength')
403
401
 
404
402
  assignment = lhs(tail(branches[0]))
405
403
 
@@ -417,14 +415,6 @@ module RuboCop
417
415
  assignment + longest_line
418
416
  end
419
417
 
420
- def line_length_cop_enabled?
421
- config.for_cop(LINE_LENGTH)[ENABLED]
422
- end
423
-
424
- def max_line_length
425
- config.for_cop(LINE_LENGTH)[MAX]
426
- end
427
-
428
418
  def single_line_conditions_only?
429
419
  cop_config[SINGLE_LINE_CONDITIONS_ONLY]
430
420
  end
@@ -444,7 +434,7 @@ module RuboCop
444
434
  next if child.parent.dstr_type?
445
435
 
446
436
  white_space = white_space_range(child, column)
447
- corrector.remove(white_space) if white_space.source.strip.empty?
437
+ corrector.remove(white_space) if white_space
448
438
  end
449
439
 
450
440
  if condition.loc.else && !same_line?(condition.else_branch, condition)
@@ -465,9 +455,13 @@ module RuboCop
465
455
 
466
456
  def white_space_range(node, column)
467
457
  expression = node.source_range
468
- begin_pos = expression.begin_pos - (expression.column - column - 2)
458
+ end_pos = expression.begin_pos
459
+ begin_pos = end_pos - (expression.column - column - 2)
460
+
461
+ return nil if begin_pos > end_pos
469
462
 
470
- Parser::Source::Range.new(expression.source_buffer, begin_pos, expression.begin_pos)
463
+ white_space = Parser::Source::Range.new(expression.source_buffer, begin_pos, end_pos)
464
+ white_space if white_space.source.strip.empty?
471
465
  end
472
466
 
473
467
  def assignment(node)
@@ -29,25 +29,30 @@ module RuboCop
29
29
  # @example IgnoreModules: false (default)
30
30
  # # bad
31
31
  # class Foo
32
- # MyClass = Struct.new()
32
+ # MyClass = Struct.new
33
33
  # end
34
34
  #
35
35
  # # good
36
36
  # class Foo
37
- # MyClass = Struct.new()
37
+ # MyClass = Struct.new
38
38
  # public_constant :MyClass
39
39
  # end
40
40
  #
41
41
  # @example IgnoreModules: true
42
42
  # # good
43
43
  # class Foo
44
- # MyClass = Struct.new()
44
+ # MyClass = Struct.new
45
45
  # end
46
46
  #
47
47
  class ConstantVisibility < Base
48
48
  MSG = 'Explicitly make `%<constant_name>s` public or private using ' \
49
49
  'either `#public_constant` or `#private_constant`.'
50
50
 
51
+ # @!method visibility_declaration_for(node)
52
+ def_node_matcher :visibility_declaration_for, <<~PATTERN
53
+ (send nil? {:public_constant :private_constant} $...)
54
+ PATTERN
55
+
51
56
  def on_casgn(node)
52
57
  return unless class_or_module_scope?(node)
53
58
  return if visibility_declaration?(node)
@@ -77,20 +82,20 @@ module RuboCop
77
82
  end
78
83
  end
79
84
 
85
+ # rubocop:disable Metrics/AbcSize
80
86
  def visibility_declaration?(node)
81
87
  node.parent.each_child_node(:send).any? do |child|
82
- visibility_declaration_for?(child, node.name)
83
- end
84
- end
88
+ next false unless (arguments = visibility_declaration_for(child))
85
89
 
86
- # @!method visibility_declaration_for?(node, const_name)
87
- def_node_matcher :visibility_declaration_for?, <<~PATTERN
88
- (send nil? {:public_constant :private_constant} ({sym str} #match_name?(%1)))
89
- PATTERN
90
+ arguments = arguments.first.children.first.to_a if arguments.first&.splat_type?
91
+ constant_values = arguments.map do |argument|
92
+ argument.value.to_sym if argument.respond_to?(:value)
93
+ end
90
94
 
91
- def match_name?(name, constant_name)
92
- name.to_sym == constant_name.to_sym
95
+ constant_values.include?(node.name)
96
+ end
93
97
  end
98
+ # rubocop:enable Metrics/AbcSize
94
99
  end
95
100
  end
96
101
  end
@@ -96,7 +96,7 @@ module RuboCop
96
96
  elsif last_child.type?(:pair, :hash) || last_child.parent.array_type?
97
97
  false
98
98
  else
99
- last_child.last_line <= node.last_line
99
+ last_child.first_line <= node.first_line
100
100
  end
101
101
  end
102
102
 
@@ -107,12 +107,6 @@ module RuboCop
107
107
  def expanded_style?
108
108
  style == :expanded
109
109
  end
110
-
111
- def max_line_length
112
- return unless config.cop_enabled?('Layout/LineLength')
113
-
114
- config.for_cop('Layout/LineLength')['Max']
115
- end
116
110
  end
117
111
  end
118
112
  end
@@ -144,7 +144,7 @@ module RuboCop
144
144
  MSG_REQUIRE_ALWAYS = 'Use endless method definitions.'
145
145
 
146
146
  def on_def(node)
147
- return if node.assignment_method?
147
+ return if node.assignment_method? || use_heredoc?(node)
148
148
 
149
149
  case style
150
150
  when :allow_single_line, :allow_always
@@ -198,6 +198,13 @@ module RuboCop
198
198
  add_offense(node) { |corrector| correct_to_multiline(corrector, node) }
199
199
  end
200
200
 
201
+ def use_heredoc?(node)
202
+ return false unless (body = node.body)
203
+ return true if body.any_str_type? && body.heredoc?
204
+
205
+ body.each_descendant(:str).any?(&:heredoc?)
206
+ end
207
+
201
208
  def correct_to_multiline(corrector, node)
202
209
  replacement = <<~RUBY.strip
203
210
  def #{node.method_name}#{arguments(node)}
@@ -225,7 +232,13 @@ module RuboCop
225
232
  def too_long_when_made_endless?(node)
226
233
  return false unless config.cop_enabled?('Layout/LineLength')
227
234
 
228
- endless_replacement(node).length > config.for_cop('Layout/LineLength')['Max']
235
+ offset = modifier_offset(node)
236
+
237
+ endless_replacement(node).length + offset > max_line_length
238
+ end
239
+
240
+ def modifier_offset(node)
241
+ same_line?(node.parent, node) ? node.loc.column - node.parent.loc.column : 0
229
242
  end
230
243
  end
231
244
  end
@@ -56,7 +56,7 @@ module RuboCop
56
56
 
57
57
  def initialize(config = nil, options = nil)
58
58
  super
59
- @def_nodes = Set.new
59
+ @def_nodes = Set.new.compare_by_identity
60
60
  end
61
61
 
62
62
  def on_yield(node)
@@ -7,9 +7,12 @@ module RuboCop
7
7
  # It is recommended to either always use `fdiv` or coerce one side only.
8
8
  # This cop also provides other options for code consistency.
9
9
  #
10
+ # For `Regexp.last_match` and nth reference (e.g., `$1`), it assumes that the value
11
+ # is a string matched by a regular expression, and allows conversion with `#to_f`.
12
+ #
10
13
  # @safety
11
14
  # This cop is unsafe, because if the operand variable is a string object
12
- # then `.to_f` will be removed and an error will occur.
15
+ # then `#to_f` will be removed and an error will occur.
13
16
  #
14
17
  # [source,ruby]
15
18
  # ----
@@ -84,6 +87,14 @@ module RuboCop
84
87
  (send !nil? :to_f)
85
88
  PATTERN
86
89
 
90
+ # @!method regexp_last_match?(node)
91
+ def_node_matcher :regexp_last_match?, <<~PATTERN
92
+ {
93
+ (send (const {nil? cbase} :Regexp) :last_match int)
94
+ (:nth_ref _)
95
+ }
96
+ PATTERN
97
+
87
98
  def on_send(node)
88
99
  return unless offense_condition?(node)
89
100
 
@@ -104,6 +115,9 @@ module RuboCop
104
115
  private
105
116
 
106
117
  def offense_condition?(node)
118
+ return false if regexp_last_match?(node.receiver.receiver) ||
119
+ regexp_last_match?(node.first_argument.receiver)
120
+
107
121
  case style
108
122
  when :left_coerce
109
123
  right_coerce?(node)
@@ -45,17 +45,6 @@ module RuboCop
45
45
  # ok
46
46
  #
47
47
  # # bad
48
- # if something
49
- # foo || raise('exception')
50
- # else
51
- # ok
52
- # end
53
- #
54
- # # good
55
- # foo || raise('exception') if something
56
- # ok
57
- #
58
- # # bad
59
48
  # define_method(:test) do
60
49
  # if something
61
50
  # work
@@ -212,7 +212,7 @@ module RuboCop
212
212
  end
213
213
 
214
214
  def word_symbol_pair?(pair)
215
- return false unless pair.key.type?(:sym, :dsym)
215
+ return false unless pair.key.any_sym_type?
216
216
 
217
217
  acceptable_19_syntax_symbol?(pair.key.source)
218
218
  end
@@ -207,14 +207,14 @@ module RuboCop
207
207
  def too_long_line_based_on_config?(range, line)
208
208
  return false if matches_allowed_pattern?(line)
209
209
 
210
- too_long = too_long_line_based_on_ignore_cop_directives?(range, line)
210
+ too_long = too_long_line_based_on_allow_cop_directives?(range, line)
211
211
  return too_long unless too_long == :undetermined
212
212
 
213
213
  too_long_line_based_on_allow_uri?(line)
214
214
  end
215
215
 
216
- def too_long_line_based_on_ignore_cop_directives?(range, line)
217
- if ignore_cop_directives? && directive_on_source_line?(range.line - 1)
216
+ def too_long_line_based_on_allow_cop_directives?(range, line)
217
+ if allow_cop_directives? && directive_on_source_line?(range.line - 1)
218
218
  return line_length_without_directive(line) > max_line_length
219
219
  end
220
220