rubocop 1.79.2 → 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 (153) 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/exe/rubocop +1 -8
  6. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  7. data/lib/rubocop/cli.rb +8 -3
  8. data/lib/rubocop/comment_config.rb +62 -17
  9. data/lib/rubocop/config_loader.rb +5 -2
  10. data/lib/rubocop/config_loader_resolver.rb +7 -6
  11. data/lib/rubocop/config_store.rb +5 -0
  12. data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
  13. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
  14. data/lib/rubocop/cop/correctors/alignment_corrector.rb +8 -7
  15. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  16. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
  17. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  18. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  19. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  20. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
  21. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  22. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  23. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  24. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
  25. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
  26. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  27. data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
  28. data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
  29. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  30. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -4
  31. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  32. data/lib/rubocop/cop/layout/indentation_width.rb +12 -1
  33. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  34. data/lib/rubocop/cop/layout/line_length.rb +17 -5
  35. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  36. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -1
  37. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
  38. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
  39. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  40. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  41. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  42. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  43. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  44. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  45. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
  46. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  47. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  48. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  49. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  50. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  51. data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
  52. data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
  53. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  54. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
  55. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  56. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  57. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  58. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
  59. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  60. data/lib/rubocop/cop/lint/self_assignment.rb +15 -6
  61. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  62. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  63. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  64. data/lib/rubocop/cop/lint/useless_assignment.rb +44 -16
  65. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  66. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +1 -1
  67. data/lib/rubocop/cop/lint/void.rb +7 -0
  68. data/lib/rubocop/cop/message_annotator.rb +1 -1
  69. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  70. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  71. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -4
  72. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  73. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  74. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
  75. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  76. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  77. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  78. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  79. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  80. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  81. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
  82. data/lib/rubocop/cop/naming/method_name.rb +5 -3
  83. data/lib/rubocop/cop/naming/predicate_method.rb +19 -6
  84. data/lib/rubocop/cop/security/json_load.rb +33 -11
  85. data/lib/rubocop/cop/style/array_intersect.rb +46 -12
  86. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  87. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
  88. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  89. data/lib/rubocop/cop/style/case_equality.rb +11 -13
  90. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
  91. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -14
  92. data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
  93. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  94. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  95. data/lib/rubocop/cop/style/endless_method.rb +15 -2
  96. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  97. data/lib/rubocop/cop/style/float_division.rb +15 -1
  98. data/lib/rubocop/cop/style/guard_clause.rb +0 -11
  99. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  100. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  101. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  102. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
  103. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  104. data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
  105. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  106. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  107. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
  108. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  109. data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
  110. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  111. data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
  112. data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
  113. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  114. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  115. data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
  116. data/lib/rubocop/cop/style/redundant_parentheses.rb +14 -11
  117. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
  118. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
  119. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  120. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  121. data/lib/rubocop/cop/style/safe_navigation.rb +18 -1
  122. data/lib/rubocop/cop/style/semicolon.rb +23 -7
  123. data/lib/rubocop/cop/style/sole_nested_conditional.rb +8 -1
  124. data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
  125. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  126. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  127. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  128. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  129. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  130. data/lib/rubocop/cop/util.rb +2 -3
  131. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  132. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  133. data/lib/rubocop/cop/variable_force.rb +9 -7
  134. data/lib/rubocop/cops_documentation_generator.rb +4 -4
  135. data/lib/rubocop/directive_comment.rb +46 -3
  136. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -5
  137. data/lib/rubocop/lsp/diagnostic.rb +10 -14
  138. data/lib/rubocop/lsp/routes.rb +31 -2
  139. data/lib/rubocop/lsp/stdin_runner.rb +0 -16
  140. data/lib/rubocop/magic_comment.rb +20 -0
  141. data/lib/rubocop/rake_task.rb +1 -1
  142. data/lib/rubocop/remote_config.rb +7 -8
  143. data/lib/rubocop/result_cache.rb +39 -28
  144. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  145. data/lib/rubocop/rspec/support.rb +1 -1
  146. data/lib/rubocop/runner.rb +10 -4
  147. data/lib/rubocop/target_finder.rb +9 -9
  148. data/lib/rubocop/target_ruby.rb +11 -2
  149. data/lib/rubocop/version.rb +1 -1
  150. data/lib/rubocop.rb +2 -0
  151. data/lib/ruby_lsp/rubocop/addon.rb +23 -8
  152. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  153. metadata +9 -7
@@ -13,34 +13,40 @@ module RuboCop
13
13
  # @example
14
14
  # # bad
15
15
  # # rubocop:disable Layout/LineLength Style/Encoding
16
- # # ^ missing comma
16
+ #
17
+ # # good
18
+ # # rubocop:disable Layout/LineLength, Style/Encoding
17
19
  #
18
20
  # # bad
19
21
  # # rubocop:disable
20
22
  #
23
+ # # good
24
+ # # rubocop:disable all
25
+ #
21
26
  # # bad
22
27
  # # rubocop:disable Layout/LineLength # rubocop:disable Style/Encoding
23
28
  #
29
+ # # good
30
+ # # rubocop:disable Layout/LineLength
31
+ # # rubocop:disable Style/Encoding
32
+ #
24
33
  # # bad
25
34
  # # rubocop:wrongmode Layout/LineLength
26
35
  #
27
36
  # # good
28
37
  # # rubocop:disable Layout/LineLength
29
38
  #
30
- # # good
31
- # # rubocop:disable Layout/LineLength, Style/Encoding
32
- #
33
- # # good
34
- # # rubocop:disable all
39
+ # # bad
40
+ # # rubocop:disable Layout/LineLength comment
35
41
  #
36
42
  # # good
37
- # # rubocop:disable Layout/LineLength -- This is a good comment.
43
+ # # rubocop:disable Layout/LineLength -- comment
38
44
  #
39
45
  class CopDirectiveSyntax < Base
40
46
  COMMON_MSG = 'Malformed directive comment detected.'
41
47
 
42
48
  MISSING_MODE_NAME_MSG = 'The mode name is missing.'
43
- INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, or `todo`.'
49
+ INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, `todo`, `push`, or `pop`.' # rubocop:disable Layout/LineLength
44
50
  MISSING_COP_NAME_MSG = 'The cop name is missing.'
45
51
  MALFORMED_COP_NAMES_MSG = 'Cop names must be separated by commas. ' \
46
52
  'Comment in the directive must start with `--`.'
@@ -102,8 +102,6 @@ module RuboCop
102
102
  end
103
103
 
104
104
  def debugger_method?(send_node)
105
- return false if send_node.parent&.send_type? && send_node.parent.receiver == send_node
106
-
107
105
  debugger_methods.include?(chained_method_name(send_node))
108
106
  end
109
107
 
@@ -118,8 +118,11 @@ module RuboCop
118
118
 
119
119
  def replacement_args(node)
120
120
  algorithm_constant, = algorithm_const(node)
121
- algorithm_name = algorithm_name(algorithm_constant)
121
+ if algorithm_constant.source == 'OpenSSL::Cipher::Cipher'
122
+ return node.first_argument.source
123
+ end
122
124
 
125
+ algorithm_name = algorithm_name(algorithm_constant)
123
126
  if openssl_class(algorithm_constant) == 'OpenSSL::Cipher'
124
127
  build_cipher_arguments(node, algorithm_name, node.arguments.empty?)
125
128
  else
@@ -25,17 +25,17 @@ module RuboCop
25
25
  #
26
26
  # # bad - repeated alternate patterns with the same conditions don't depend on the order
27
27
  # case x
28
- # in foo | bar
28
+ # in 0 | 1
29
29
  # first_method
30
- # in bar | foo
30
+ # in 1 | 0
31
31
  # second_method
32
32
  # end
33
33
  #
34
34
  # # good
35
35
  # case x
36
- # in foo | bar
36
+ # in 0 | 1
37
37
  # first_method
38
- # in bar | baz
38
+ # in 2 | 3
39
39
  # second_method
40
40
  # end
41
41
  #
@@ -24,8 +24,6 @@ module RuboCop
24
24
 
25
25
  MSG_REPEATED_ELEMENT = 'Duplicate element inside regexp character class'
26
26
 
27
- OCTAL_DIGITS_AFTER_ESCAPE = 2
28
-
29
27
  def on_regexp(node)
30
28
  each_repeated_character_class_element_loc(node) do |loc|
31
29
  add_offense(loc, message: MSG_REPEATED_ELEMENT) do |corrector|
@@ -40,9 +38,9 @@ module RuboCop
40
38
 
41
39
  seen = Set.new
42
40
  group_expressions(node, expr.expressions) do |group|
43
- group_source = group.map(&:to_s).join
41
+ group_source = group.to_s
44
42
 
45
- yield source_range(group) if seen.include?(group_source)
43
+ yield group.expression if seen.include?(group_source)
46
44
 
47
45
  seen << group_source
48
46
  end
@@ -52,40 +50,13 @@ module RuboCop
52
50
  private
53
51
 
54
52
  def group_expressions(node, expressions)
55
- # Create a mutable list to simplify state tracking while we iterate.
56
- expressions = expressions.to_a
57
-
58
- until expressions.empty?
59
- # With we may need to compose a group of multiple expressions.
60
- group = [expressions.shift]
61
- next if within_interpolation?(node, group.first)
62
-
63
- # With regexp_parser < 2.7 escaped octal sequences may be up to 3
64
- # separate expressions ("\\0", "0", "1").
65
- pop_octal_digits(group, expressions) if escaped_octal?(group.first.to_s)
66
-
67
- yield(group)
68
- end
69
- end
70
-
71
- def pop_octal_digits(current_child, expressions)
72
- OCTAL_DIGITS_AFTER_ESCAPE.times do
73
- next_child = expressions.first
74
- break unless octal?(next_child.to_s)
53
+ expressions.each do |expression|
54
+ next if within_interpolation?(node, expression)
75
55
 
76
- current_child << expressions.shift
56
+ yield(expression)
77
57
  end
78
58
  end
79
59
 
80
- def source_range(children)
81
- return children.first.expression if children.size == 1
82
-
83
- range_between(
84
- children.first.expression.begin_pos,
85
- children.last.expression.begin_pos + children.last.to_s.length
86
- )
87
- end
88
-
89
60
  def skip_expression?(expr)
90
61
  expr.type != :set || expr.token == :intersection
91
62
  end
@@ -99,14 +70,6 @@ module RuboCop
99
70
  interpolation_locs(node).any? { |il| il.overlaps?(parse_tree_child_loc) }
100
71
  end
101
72
 
102
- def escaped_octal?(string)
103
- string.length == 2 && string[0] == '\\' && octal?(string[1])
104
- end
105
-
106
- def octal?(char)
107
- ('0'..'7').cover?(char)
108
- end
109
-
110
73
  def interpolation_locs(node)
111
74
  @interpolation_locs ||= {}
112
75
 
@@ -38,6 +38,24 @@ module RuboCop
38
38
  # elsif do_this
39
39
  # do_that
40
40
  # end
41
+ #
42
+ # # bad
43
+ #
44
+ # # For single-line conditionals using `then` the layout is disallowed
45
+ # # when the `else` body is multiline because it is treated as a lint offense.
46
+ # if something then on_the_same_line_as_then
47
+ # else first_line
48
+ # second_line
49
+ # end
50
+ #
51
+ # # good
52
+ #
53
+ # # For single-line conditional using `then` the layout is allowed
54
+ # # when `else` body is a single-line because it is treated as intentional.
55
+ #
56
+ # if something then on_the_same_line_as_then
57
+ # else single_line
58
+ # end
41
59
  class ElseLayout < Base
42
60
  include Alignment
43
61
  include RangeHelp
@@ -47,6 +65,7 @@ module RuboCop
47
65
 
48
66
  def on_if(node)
49
67
  return if node.ternary?
68
+ return if node.then? && !node.else_branch&.begin_type?
50
69
 
51
70
  # If the if is on a single line, it'll be handled by `Style/OneLineConditional`
52
71
  return if node.single_line?
@@ -19,12 +19,23 @@ module RuboCop
19
19
  MSG = 'Empty interpolation detected.'
20
20
 
21
21
  def on_interpolation(begin_node)
22
+ return if in_percent_literal_array?(begin_node)
23
+
22
24
  node_children = begin_node.children.dup
23
25
  node_children.delete_if { |e| e.nil_type? || (e.basic_literal? && e.str_content&.empty?) }
24
26
  return unless node_children.empty?
25
27
 
26
28
  add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
27
29
  end
30
+
31
+ private
32
+
33
+ def in_percent_literal_array?(begin_node)
34
+ array_node = begin_node.each_ancestor(:array).first
35
+ return false unless array_node
36
+
37
+ array_node.percent_literal?
38
+ end
28
39
  end
29
40
  end
30
41
  end
@@ -269,7 +269,11 @@ module RuboCop
269
269
  end
270
270
 
271
271
  add_offense(cond) do |corrector|
272
+ next if part_of_ignored_node?(node)
273
+
272
274
  corrector.replace(node, new_node)
275
+
276
+ ignore_node(node)
273
277
  end
274
278
  end
275
279
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -66,7 +66,7 @@ module RuboCop
66
66
 
67
67
  def special_keyword?(node)
68
68
  # handle strings like __FILE__
69
- (node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
69
+ (node.str_type? && !node.loc?(:begin)) || node.source_range.is?('__LINE__')
70
70
  end
71
71
 
72
72
  def array_in_regexp?(node)
@@ -9,9 +9,21 @@ module RuboCop
9
9
  # cop disables on wide ranges of code, that latter contributors to
10
10
  # a file wouldn't be aware of.
11
11
  #
12
- # @example
13
- # # Lint/MissingCopEnableDirective:
14
- # # MaximumRangeSize: .inf
12
+ # You can set `MaximumRangeSize` to define the maximum number of
13
+ # consecutive lines a cop can be disabled for.
14
+ #
15
+ # - `.inf` any size (default)
16
+ # - `0` allows only single-line disables
17
+ # - `1` means the maximum allowed is as follows:
18
+ #
19
+ # [source,ruby]
20
+ # ----
21
+ # # rubocop:disable SomeCop
22
+ # a = 1
23
+ # # rubocop:enable SomeCop
24
+ # ----
25
+ #
26
+ # @example MaximumRangeSize: .inf (default)
15
27
  #
16
28
  # # good
17
29
  # # rubocop:disable Layout/SpaceAroundOperators
@@ -25,9 +37,7 @@ module RuboCop
25
37
  # x= 0
26
38
  # # EOF
27
39
  #
28
- # @example
29
- # # Lint/MissingCopEnableDirective:
30
- # # MaximumRangeSize: 2
40
+ # @example MaximumRangeSize: 2
31
41
  #
32
42
  # # good
33
43
  # # rubocop:disable Layout/SpaceAroundOperators
@@ -52,10 +62,9 @@ module RuboCop
52
62
  each_missing_enable do |cop, line_range|
53
63
  next if acceptable_range?(cop, line_range)
54
64
 
55
- range = source_range(processed_source.buffer, line_range.min, 0..0)
56
65
  comment = processed_source.comment_at_line(line_range.begin)
57
66
 
58
- add_offense(range, message: message(cop, comment))
67
+ add_offense(comment, message: message(cop, comment))
59
68
  end
60
69
  end
61
70
 
@@ -45,6 +45,10 @@ module RuboCop
45
45
  end
46
46
  end
47
47
  end
48
+ alias on_ivasgn on_lvasgn
49
+ alias on_cvasgn on_lvasgn
50
+ alias on_gvasgn on_lvasgn
51
+ alias on_casgn on_lvasgn
48
52
  alias on_or_asgn on_lvasgn
49
53
  alias on_op_asgn on_lvasgn
50
54
  end
@@ -112,22 +112,36 @@ module RuboCop
112
112
 
113
113
  def each_line_range(cop, line_ranges)
114
114
  line_ranges.each_with_index do |line_range, line_range_index|
115
- next if ignore_offense?(line_range)
116
- next if expected_final_disable?(cop, line_range)
115
+ next if should_skip_line_range?(cop, line_range)
117
116
 
118
117
  comment = processed_source.comment_at_line(line_range.begin)
119
- redundant = if all_disabled?(comment)
120
- find_redundant_all(line_range, line_ranges[line_range_index + 1])
121
- elsif department_disabled?(cop, comment)
122
- find_redundant_department(cop, line_range)
123
- else
124
- find_redundant_cop(cop, line_range)
125
- end
118
+ next if skip_directive?(comment)
126
119
 
120
+ next_range = line_ranges[line_range_index + 1]
121
+ redundant = find_redundant_directive(cop, comment, line_range, next_range)
127
122
  yield comment, redundant if redundant
128
123
  end
129
124
  end
130
125
 
126
+ def should_skip_line_range?(cop, line_range)
127
+ ignore_offense?(line_range) || expected_final_disable?(cop, line_range)
128
+ end
129
+
130
+ def skip_directive?(comment)
131
+ directive = DirectiveComment.new(comment)
132
+ directive.push? || directive.pop?
133
+ end
134
+
135
+ def find_redundant_directive(cop, comment, line_range, next_range)
136
+ if all_disabled?(comment)
137
+ find_redundant_all(line_range, next_range)
138
+ elsif department_disabled?(cop, comment)
139
+ find_redundant_department(cop, line_range)
140
+ else
141
+ find_redundant_cop(cop, line_range)
142
+ end
143
+ end
144
+
131
145
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
132
146
  def each_already_disabled(cop, line_ranges)
133
147
  line_ranges.each_cons(2) do |previous_range, range|
@@ -19,7 +19,8 @@ module RuboCop
19
19
  # * 2.2+ ... Add `rational` and `complex` above
20
20
  # * 2.7+ ... Add `ruby2_keywords` above
21
21
  # * 3.1+ ... Add `fiber` above
22
- # * 3.2+ ... `set`
22
+ # * 3.2+ ... Add `set` above
23
+ # * 4.0+ ... Add `pathname` above
23
24
  #
24
25
  # This cop target those features.
25
26
  #
@@ -69,7 +70,8 @@ module RuboCop
69
70
  (target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
70
71
  (target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
71
72
  (target_ruby_version >= 3.1 && feature_name == 'fiber') ||
72
- (target_ruby_version >= 3.2 && feature_name == 'set')
73
+ (target_ruby_version >= 3.2 && feature_name == 'set') ||
74
+ (target_ruby_version >= 4.0 && feature_name == 'pathname')
73
75
  end
74
76
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
75
77
  end
@@ -144,7 +144,9 @@ module RuboCop
144
144
  expression = node.parent.source_range if node.parent.array_type?
145
145
  [expression, variable.source]
146
146
  elsif !variable.array_type?
147
- [expression, "[#{variable.source}]"]
147
+ replacement = variable.source
148
+ replacement = "[#{replacement}]" if wrap_in_brackets?(node)
149
+ [expression, replacement]
148
150
  elsif redundant_brackets?(node)
149
151
  [expression, remove_brackets(variable)]
150
152
  else
@@ -176,6 +178,10 @@ module RuboCop
176
178
  grandparent&.resbody_type?
177
179
  end
178
180
 
181
+ def wrap_in_brackets?(node)
182
+ node.parent.array_type? && !node.parent.bracketed?
183
+ end
184
+
179
185
  def remove_brackets(array)
180
186
  array_start = array.loc.begin.source
181
187
  elements = *array
@@ -24,10 +24,7 @@ module RuboCop
24
24
  MSG = 'Avoid rescuing the `Exception` class. Perhaps you meant to rescue `StandardError`?'
25
25
 
26
26
  def on_resbody(node)
27
- return unless node.children.first
28
-
29
- rescue_args = node.children.first.children
30
- return unless rescue_args.any? { |a| targets_exception?(a) }
27
+ return unless node.exceptions.any? { |exception| targets_exception?(exception) }
31
28
 
32
29
  add_offense(node)
33
30
  end
@@ -23,7 +23,15 @@ module RuboCop
23
23
  # # good (method calls possibly can return different results)
24
24
  # hash[foo] = hash[foo]
25
25
  #
26
- # @example AllowRBSInlineAnnotation:true
26
+ # @example AllowRBSInlineAnnotation: false (default)
27
+ # # bad
28
+ # foo = foo #: Integer
29
+ # foo, bar = foo, bar #: Integer
30
+ # Foo = Foo #: Integer
31
+ # hash['foo'] = hash['foo'] #: Integer
32
+ # obj.attr = obj.attr #: Integer
33
+ #
34
+ # @example AllowRBSInlineAnnotation: true
27
35
  # # good
28
36
  # foo = foo #: Integer
29
37
  # foo, bar = foo, bar #: Integer
@@ -45,7 +53,7 @@ module RuboCop
45
53
  return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.receiver)
46
54
 
47
55
  if node.method?(:[]=)
48
- handle_key_assignment(node) if node.arguments.size == 2
56
+ handle_key_assignment(node)
49
57
  elsif node.assignment_method?
50
58
  handle_attribute_assignment(node) if node.arguments.size == 1
51
59
  end
@@ -105,12 +113,13 @@ module RuboCop
105
113
  end
106
114
 
107
115
  def handle_key_assignment(node)
108
- value_node = node.arguments[1]
116
+ value_node = node.last_argument
117
+ node_arguments = node.arguments[0...-1]
109
118
 
110
- if value_node.send_type? && value_node.method?(:[]) &&
119
+ if value_node.respond_to?(:method?) && value_node.method?(:[]) &&
111
120
  node.receiver == value_node.receiver &&
112
- !node.first_argument.call_type? &&
113
- node.first_argument == value_node.first_argument
121
+ node_arguments.none?(&:call_type?) &&
122
+ node_arguments == value_node.arguments
114
123
  add_offense(node)
115
124
  end
116
125
  end
@@ -125,13 +125,13 @@ module RuboCop
125
125
  next false if assignment_node.shorthand_asgn?
126
126
  next false unless assignment_node.parent
127
127
 
128
- node_within_block_or_conditional =
129
- node_within_block_or_conditional?(assignment_node.parent, argument.scope.node)
128
+ conditional_assignment =
129
+ conditional_assignment?(assignment_node.parent, argument.scope.node)
130
130
 
131
131
  unless uses_var?(assignment_node, argument.name)
132
132
  # It's impossible to decide whether a branch or block is executed,
133
133
  # so the precise reassignment location is undecidable.
134
- next false if node_within_block_or_conditional
134
+ next false if conditional_assignment
135
135
 
136
136
  yield(assignment.node, location_known)
137
137
  break
@@ -147,13 +147,13 @@ module RuboCop
147
147
  node.source_range.begin_pos
148
148
  end
149
149
 
150
- # Check whether the given node is nested into block or conditional.
150
+ # Check whether the given node is always executed or not
151
151
  #
152
- def node_within_block_or_conditional?(node, stop_search_node)
152
+ def conditional_assignment?(node, stop_search_node)
153
153
  return false if node == stop_search_node
154
154
 
155
- node.conditional? || node.block_type? ||
156
- node_within_block_or_conditional?(node.parent, stop_search_node)
155
+ node.conditional? || node.type?(:block, :rescue) ||
156
+ conditional_assignment?(node.parent, stop_search_node)
157
157
  end
158
158
 
159
159
  # Get argument references without assignments' references
@@ -78,6 +78,7 @@ module RuboCop
78
78
  }
79
79
  PATTERN
80
80
 
81
+ # rubocop:disable Metrics/MethodLength
81
82
  def flow_expression?(node)
82
83
  return report_on_flow_command?(node) if flow_command?(node)
83
84
 
@@ -89,12 +90,14 @@ module RuboCop
89
90
  check_if(node)
90
91
  when :case, :case_match
91
92
  check_case(node)
92
- when :def
93
+ when :def, :defs
93
94
  register_redefinition(node)
95
+ false
94
96
  else
95
97
  false
96
98
  end
97
99
  end
100
+ # rubocop:enable Metrics/MethodLength
98
101
 
99
102
  def check_if(node)
100
103
  if_branch = node.if_branch
@@ -113,8 +116,7 @@ module RuboCop
113
116
  end
114
117
 
115
118
  def register_redefinition(node)
116
- @redefined << node.method_name if redefinable_flow_method? node.method_name
117
- false
119
+ @redefined << node.method_name if redefinable_flow_method?(node.method_name)
118
120
  end
119
121
 
120
122
  def instance_eval_block?(node)
@@ -17,6 +17,7 @@ module RuboCop
17
17
  #
18
18
  # # good
19
19
  # CGI.escape('http://example.com')
20
+ # URI.encode_uri_component(uri) # Since Ruby 3.1
20
21
  # URI.encode_www_form([['example', 'param'], ['lang', 'en']])
21
22
  # URI.encode_www_form(page: 10, locale: 'en')
22
23
  # URI.encode_www_form_component('http://example.com')
@@ -27,6 +28,7 @@ module RuboCop
27
28
  #
28
29
  # # good
29
30
  # CGI.unescape(enc_uri)
31
+ # URI.decode_uri_component(uri) # Since Ruby 3.1
30
32
  # URI.decode_www_form(enc_uri)
31
33
  # URI.decode_www_form_component(enc_uri)
32
34
  class UriEscapeUnescape < Base
@@ -52,32 +52,39 @@ module RuboCop
52
52
  scope.variables.each_value { |variable| check_for_unused_assignments(variable) }
53
53
  end
54
54
 
55
- # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
56
55
  def check_for_unused_assignments(variable)
57
56
  return if variable.should_be_unused?
58
57
 
59
58
  variable.assignments.reverse_each do |assignment|
60
- assignment_node = assignment.node
61
- next if assignment.used? || part_of_ignored_node?(assignment_node)
59
+ check_for_unused_assignment(variable, assignment)
60
+ end
61
+ end
62
62
 
63
- message = message_for_useless_assignment(assignment)
64
- range = offense_range(assignment)
63
+ def check_for_unused_assignment(variable, assignment)
64
+ assignment_node = assignment.node
65
65
 
66
- add_offense(range, message: message) do |corrector|
67
- # In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
68
- # and where changing `x ||= 1` to `x = 1` would cause `NameError`,
69
- # the autocorrect will be skipped, even if the variable is unused.
70
- if sequential_assignment?(assignment_node) || assignment_node.parent&.or_asgn_type?
71
- next
72
- end
66
+ return if ignored_assignment?(variable, assignment_node, assignment)
73
67
 
74
- autocorrect(corrector, assignment)
75
- end
68
+ message = message_for_useless_assignment(assignment)
69
+ range = offense_range(assignment)
76
70
 
77
- ignore_node(assignment_node) if chained_assignment?(assignment_node)
71
+ add_offense(range, message: message) do |corrector|
72
+ # In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
73
+ # and where changing `x ||= 1` to `x = 1` would cause `NameError`,
74
+ # the autocorrect will be skipped, even if the variable is unused.
75
+ next if sequential_assignment?(assignment_node) ||
76
+ assignment_node.parent&.or_asgn_type?
77
+
78
+ autocorrect(corrector, assignment)
78
79
  end
80
+
81
+ ignore_node(assignment_node) if chained_assignment?(assignment_node)
82
+ end
83
+
84
+ def ignored_assignment?(variable, assignment_node, assignment)
85
+ assignment.used? || part_of_ignored_node?(assignment_node) ||
86
+ variable_in_loop_condition?(assignment_node, variable)
79
87
  end
80
- # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
81
88
 
82
89
  def message_for_useless_assignment(assignment)
83
90
  variable = assignment.variable
@@ -208,6 +215,27 @@ module RuboCop
208
215
  def remove_local_variable_assignment_part(corrector, node)
209
216
  corrector.replace(node, node.expression.source)
210
217
  end
218
+
219
+ def variable_in_loop_condition?(assignment_node, variable)
220
+ return false if assignment_node.each_ancestor(:any_def).any?
221
+
222
+ loop_node = assignment_node.each_ancestor.find do |ancestor|
223
+ ancestor.type?(*VariableForce::LOOP_TYPES)
224
+ end
225
+
226
+ return false unless loop_node.respond_to?(:condition)
227
+
228
+ condition_node = loop_node.condition
229
+ variable_name = variable.name
230
+
231
+ return true if condition_node.lvar_type? && condition_node.children.first == variable_name
232
+
233
+ condition_node.each_descendant(:lvar) do |lvar_node|
234
+ return true if lvar_node.children.first == variable_name
235
+ end
236
+
237
+ false
238
+ end
211
239
  end
212
240
  end
213
241
  end