rubocop 1.69.2 → 1.71.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +36 -2
  5. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  6. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  7. data/lib/rubocop/comment_config.rb +1 -1
  8. data/lib/rubocop/config.rb +13 -4
  9. data/lib/rubocop/config_loader.rb +4 -0
  10. data/lib/rubocop/config_loader_resolver.rb +14 -3
  11. data/lib/rubocop/config_validator.rb +18 -8
  12. data/lib/rubocop/cop/base.rb +6 -0
  13. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  14. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  15. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  16. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  17. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  18. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  19. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +2 -1
  20. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  21. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  22. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
  23. data/lib/rubocop/cop/layout/class_structure.rb +7 -7
  24. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  25. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  26. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  27. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -7
  28. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  29. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  30. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  31. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  32. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
  33. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  34. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
  35. data/lib/rubocop/cop/layout/line_length.rb +1 -0
  36. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  37. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  38. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  39. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  40. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  41. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  42. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
  43. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  44. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  45. data/lib/rubocop/cop/lint/constant_reassignment.rb +152 -0
  46. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  47. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  48. data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
  49. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  50. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +23 -5
  51. data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
  52. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  53. data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
  54. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  55. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +17 -30
  56. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  57. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  58. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  59. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  60. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +7 -0
  61. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  62. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  63. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  64. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  65. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  66. data/lib/rubocop/cop/lint/void.rb +3 -2
  67. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  68. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  69. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  70. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  71. data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -7
  72. data/lib/rubocop/cop/mixin/comments_help.rb +2 -0
  73. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  74. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  75. data/lib/rubocop/cop/mixin/hash_subset.rb +170 -0
  76. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +26 -16
  77. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  78. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  79. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  80. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -2
  81. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  82. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  83. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -1
  84. data/lib/rubocop/cop/style/and_or.rb +1 -1
  85. data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -4
  86. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  87. data/lib/rubocop/cop/style/block_delimiters.rb +6 -19
  88. data/lib/rubocop/cop/style/class_and_module_children.rb +5 -2
  89. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  90. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
  91. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  92. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  93. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  94. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  95. data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
  96. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  97. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  98. data/lib/rubocop/cop/style/float_division.rb +8 -4
  99. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  100. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
  101. data/lib/rubocop/cop/style/hash_except.rb +9 -148
  102. data/lib/rubocop/cop/style/hash_slice.rb +65 -0
  103. data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
  104. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  105. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  106. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -1
  107. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  108. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  109. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  110. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  111. data/lib/rubocop/cop/style/mutable_constant.rb +2 -2
  112. data/lib/rubocop/cop/style/object_then.rb +13 -15
  113. data/lib/rubocop/cop/style/open_struct_use.rb +4 -4
  114. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  115. data/lib/rubocop/cop/style/raise_args.rb +6 -4
  116. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  117. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  118. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  119. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  120. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  121. data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
  122. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -4
  123. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  124. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  125. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  126. data/lib/rubocop/cop/style/redundant_self_assignment.rb +6 -5
  127. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  128. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  129. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  130. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  131. data/lib/rubocop/cop/style/single_line_methods.rb +2 -3
  132. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  133. data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -1
  134. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  135. data/lib/rubocop/cop/style/super_arguments.rb +63 -15
  136. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  137. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  138. data/lib/rubocop/cop/style/yoda_expression.rb +1 -0
  139. data/lib/rubocop/cop/util.rb +9 -2
  140. data/lib/rubocop/cops_documentation_generator.rb +13 -13
  141. data/lib/rubocop/directive_comment.rb +9 -8
  142. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  143. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  144. data/lib/rubocop/lsp/logger.rb +2 -2
  145. data/lib/rubocop/lsp/routes.rb +7 -23
  146. data/lib/rubocop/lsp/runtime.rb +15 -49
  147. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  148. data/lib/rubocop/options.rb +2 -1
  149. data/lib/rubocop/path_util.rb +11 -8
  150. data/lib/rubocop/result_cache.rb +13 -13
  151. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  152. data/lib/rubocop/rspec/shared_contexts.rb +4 -1
  153. data/lib/rubocop/runner.rb +5 -6
  154. data/lib/rubocop/target_finder.rb +1 -0
  155. data/lib/rubocop/target_ruby.rb +15 -0
  156. data/lib/rubocop/version.rb +1 -1
  157. data/lib/rubocop.rb +6 -0
  158. data/lib/ruby_lsp/rubocop/addon.rb +78 -0
  159. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
  160. metadata +17 -8
@@ -19,7 +19,7 @@ module RuboCop
19
19
  # acceptable value other than none, it will suppress the offenses
20
20
  # raised by this cop. It enforces frozen state.
21
21
  #
22
- # NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
22
+ # NOTE: `Regexp` and `Range` literals are frozen objects since Ruby 3.0.
23
23
  #
24
24
  # NOTE: From Ruby 3.0, interpolated strings are not frozen when
25
25
  # `# frozen-string-literal: true` is used, so this cop enforces explicit
@@ -238,7 +238,7 @@ module RuboCop
238
238
 
239
239
  # @!method range_enclosed_in_parentheses?(node)
240
240
  def_node_matcher :range_enclosed_in_parentheses?, <<~PATTERN
241
- (begin ({irange erange} _ _))
241
+ (begin (range _ _))
242
242
  PATTERN
243
243
  end
244
244
  end
@@ -33,9 +33,10 @@ module RuboCop
33
33
  RESTRICT_ON_SEND = %i[then yield_self].freeze
34
34
 
35
35
  def on_block(node)
36
+ return unless RESTRICT_ON_SEND.include?(node.method_name)
37
+
36
38
  check_method_node(node.send_node)
37
39
  end
38
-
39
40
  alias on_numblock on_block
40
41
 
41
42
  def on_send(node)
@@ -43,29 +44,26 @@ module RuboCop
43
44
 
44
45
  check_method_node(node)
45
46
  end
47
+ alias on_csend on_send
46
48
 
47
49
  private
48
50
 
49
51
  def check_method_node(node)
50
- return unless preferred_method?(node)
51
-
52
- message = message(node)
53
- add_offense(node.loc.selector, message: message) do |corrector|
54
- prefer = style == :then && node.receiver.nil? ? 'self.then' : style
52
+ if preferred_method?(node)
53
+ correct_style_detected
54
+ else
55
+ opposite_style_detected
56
+ message = message(node)
57
+ add_offense(node.loc.selector, message: message) do |corrector|
58
+ prefer = style == :then && node.receiver.nil? ? 'self.then' : style
55
59
 
56
- corrector.replace(node.loc.selector, prefer)
60
+ corrector.replace(node.loc.selector, prefer)
61
+ end
57
62
  end
58
63
  end
59
64
 
60
65
  def preferred_method?(node)
61
- case style
62
- when :then
63
- node.method?(:yield_self)
64
- when :yield_self
65
- node.method?(:then)
66
- else
67
- false
68
- end
66
+ node.method?(style)
69
67
  end
70
68
 
71
69
  def message(node)
@@ -3,15 +3,15 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Flags uses of OpenStruct, as it is now officially discouraged
6
+ # Flags uses of `OpenStruct`, as it is now officially discouraged
7
7
  # to be used for performance, version compatibility, and potential security issues.
8
8
  #
9
9
  # @safety
10
- #
11
10
  # Note that this cop may flag false positives; for instance, the following legal
12
11
  # use of a hand-rolled `OpenStruct` type would be considered an offense:
13
12
  #
14
- # ```
13
+ # [source,ruby]
14
+ # -----
15
15
  # module MyNamespace
16
16
  # class OpenStruct # not the OpenStruct we're looking for
17
17
  # end
@@ -20,7 +20,7 @@ module RuboCop
20
20
  # OpenStruct.new # resolves to MyNamespace::OpenStruct
21
21
  # end
22
22
  # end
23
- # ```
23
+ # -----
24
24
  #
25
25
  # @example
26
26
  #
@@ -98,7 +98,7 @@ module RuboCop
98
98
 
99
99
  def style
100
100
  return super unless super == :same_as_string_literals
101
- return :single_quotes unless string_literals_config['Enabled']
101
+ return :single_quotes unless config.cop_enabled?('Style/StringLiterals')
102
102
 
103
103
  string_literals_config['EnforcedStyle'].to_sym
104
104
  end
@@ -14,7 +14,7 @@ module RuboCop
14
14
  # passed multiple arguments.
15
15
  #
16
16
  # The exploded style has an `AllowedCompactTypes` configuration
17
- # option that takes an Array of exception name Strings.
17
+ # option that takes an `Array` of exception name Strings.
18
18
  #
19
19
  # @safety
20
20
  # This cop is unsafe because `raise Foo` calls `Foo.exception`, not `Foo.new`.
@@ -50,6 +50,9 @@ module RuboCop
50
50
 
51
51
  EXPLODED_MSG = 'Provide an exception class and message as arguments to `%<method>s`.'
52
52
  COMPACT_MSG = 'Provide an exception object as an argument to `%<method>s`.'
53
+ ACCEPTABLE_ARG_TYPES = %i[
54
+ hash forwarded_restarg splat forwarded_restarg forwarded_args
55
+ ].freeze
53
56
 
54
57
  RESTRICT_ON_SEND = %i[raise fail].freeze
55
58
 
@@ -138,9 +141,8 @@ module RuboCop
138
141
 
139
142
  arg = args.first
140
143
 
141
- # Allow code like `raise Ex.new(kw: arg)`.
142
- # Allow code like `raise Ex.new(*args)`.
143
- arg.hash_type? || arg.splat_type?
144
+ # Allow nodes that may forward more than one argument
145
+ ACCEPTABLE_ARG_TYPES.include?(arg.type)
144
146
  end
145
147
 
146
148
  def allowed_non_exploded_type?(arg)
@@ -36,7 +36,7 @@ module RuboCop
36
36
  (send
37
37
  {nil? (const {nil? cbase} :Random) (const {nil? cbase} :Kernel)}
38
38
  :rand
39
- {int (irange int int) (erange int int)}))
39
+ {int (range int int)}))
40
40
  PATTERN
41
41
 
42
42
  # @!method rand_op_integer?(node)
@@ -45,7 +45,7 @@ module RuboCop
45
45
  (send
46
46
  {nil? (const {nil? cbase} :Random) (const {nil? cbase} :Kernel)}
47
47
  :rand
48
- {int (irange int int) (erange int int)})
48
+ {int (range int int)})
49
49
  {:+ :-}
50
50
  int)
51
51
  PATTERN
@@ -56,7 +56,7 @@ module RuboCop
56
56
  (send
57
57
  {nil? (const {nil? cbase} :Random) (const {nil? cbase} :Kernel)}
58
58
  :rand
59
- {int (irange int int) (erange int int)})
59
+ {int (range int int)})
60
60
  {:succ :pred :next})
61
61
  PATTERN
62
62
 
@@ -3,7 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses a redundant current directory in path.
6
+ # Checks for paths given to `require_relative` that start with
7
+ # the current directory (`./`), which can be omitted.
7
8
  #
8
9
  # @example
9
10
  #
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for RuntimeError as the argument of raise/fail.
6
+ # Checks for `RuntimeError` as the argument of `raise`/`fail`.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Style
6
6
  # Check for uses of `Object#freeze` on immutable objects.
7
7
  #
8
- # NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
8
+ # NOTE: `Regexp` and `Range` literals are frozen objects since Ruby 3.0.
9
9
  #
10
10
  # NOTE: From Ruby 3.0, this cop allows explicit freezing of interpolated
11
11
  # string literals when `# frozen-string-literal: true` is used.
@@ -11,6 +11,9 @@ module RuboCop
11
11
  # will not register an offense, because it allows the initializer to take a different
12
12
  # number of arguments as its superclass potentially does.
13
13
  #
14
+ # NOTE: If an initializer takes any arguments and has an empty body, RuboCop
15
+ # assumes it to *not* be redundant. This is to prevent potential `ArgumentError`.
16
+ #
14
17
  # NOTE: If an initializer argument has a default value, RuboCop assumes it
15
18
  # to *not* be redundant.
16
19
  #
@@ -19,8 +22,10 @@ module RuboCop
19
22
  # initializer.
20
23
  #
21
24
  # @safety
22
- # This cop is unsafe because if subclass overrides `initialize` method with
23
- # a different arity than superclass.
25
+ # This cop is unsafe because removing an empty initializer may alter
26
+ # the behavior of the code, particularly if the superclass initializer
27
+ # raises an exception. In such cases, the empty initializer may act as
28
+ # a safeguard to prevent unintended errors from propagating.
24
29
  #
25
30
  # @example
26
31
  # # bad
@@ -69,6 +74,10 @@ module RuboCop
69
74
  # end
70
75
  #
71
76
  # # good (changes the parameter requirements)
77
+ # def initialize(_)
78
+ # end
79
+ #
80
+ # # good (changes the parameter requirements)
72
81
  # def initialize(*)
73
82
  # end
74
83
  #
@@ -111,7 +120,7 @@ module RuboCop
111
120
  return if acceptable?(node)
112
121
 
113
122
  if node.body.nil?
114
- register_offense(node, MSG_EMPTY)
123
+ register_offense(node, MSG_EMPTY) if node.arguments.empty?
115
124
  else
116
125
  return if node.body.begin_type?
117
126
 
@@ -73,10 +73,15 @@ module RuboCop
73
73
  LINE_CONTINUATION_PATTERN = /(\\\n)/.freeze
74
74
  ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
75
75
  ARGUMENT_TYPES = %i[
76
- kDEF kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
77
- tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
76
+ kDEF kDEFINED kFALSE kNIL kSELF kTRUE tAMPER tBANG tCARET tCHARACTER tCOLON3 tCONSTANT
77
+ tCVAR tDOT2 tDOT3 tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR tLAMBDA tLBRACK tLCURLY
78
+ tLPAREN_ARG tPIPE tQSYMBOLS_BEG tQWORDS_BEG tREGEXP_BEG tSTAR tSTRING tSTRING_BEG tSYMBEG
79
+ tSYMBOL tSYMBOLS_BEG tTILDE tUMINUS tUNARY_NUM tUPLUS tWORDS_BEG tXSTRING_BEG
78
80
  ].freeze
79
- ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
81
+ ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[
82
+ tIDENTIFIER kBREAK kNEXT kRETURN kSUPER kYIELD
83
+ ].freeze
84
+ ARITHMETIC_OPERATOR_TOKENS = %i[tDIVIDE tDSTAR tMINUS tPERCENT tPLUS tSTAR2].freeze
80
85
 
81
86
  def on_new_investigation
82
87
  return unless processed_source.ast
@@ -96,15 +101,20 @@ module RuboCop
96
101
  private
97
102
 
98
103
  def require_line_continuation?(range)
99
- !ends_with_backslash_without_comment?(range.source_line) ||
104
+ !ends_with_uncommented_backslash?(range) ||
100
105
  string_concatenation?(range.source_line) ||
101
- start_with_arithmetic_operator?(processed_source[range.line]) ||
106
+ start_with_arithmetic_operator?(range) ||
102
107
  inside_string_literal_or_method_with_argument?(range) ||
103
108
  leading_dot_method_chain_with_blank_line?(range)
104
109
  end
105
110
 
106
- def ends_with_backslash_without_comment?(source_line)
107
- source_line.gsub(/#.+/, '').end_with?('\\')
111
+ def ends_with_uncommented_backslash?(range)
112
+ # A line continuation always needs to be the last character on the line, which
113
+ # means that it is impossible to have a comment following a continuation.
114
+ # Therefore, if the line contains a comment, it cannot end with a continuation.
115
+ return false if processed_source.line_with_comment?(range.line)
116
+
117
+ range.source_line.end_with?(LINE_CONTINUATION)
108
118
  end
109
119
 
110
120
  def string_concatenation?(source_line)
@@ -112,10 +122,13 @@ module RuboCop
112
122
  end
113
123
 
114
124
  def inside_string_literal_or_method_with_argument?(range)
125
+ line_range = range_by_whole_lines(range)
126
+
115
127
  processed_source.tokens.each_cons(2).any? do |token, next_token|
116
128
  next if token.line == next_token.line
117
129
 
118
- inside_string_literal?(range, token) || method_with_argument?(token, next_token)
130
+ inside_string_literal?(range, token) ||
131
+ method_with_argument?(line_range, token, next_token)
119
132
  end
120
133
  end
121
134
 
@@ -137,7 +150,7 @@ module RuboCop
137
150
 
138
151
  def inspect_end_of_ruby_code_line_continuation
139
152
  last_line = processed_source.lines[processed_source.ast.last_line - 1]
140
- return unless last_line.end_with?(LINE_CONTINUATION)
153
+ return unless code_ends_with_continuation?(last_line)
141
154
 
142
155
  last_column = last_line.length
143
156
  line_continuation_range = range_between(last_column - 1, last_column)
@@ -147,6 +160,12 @@ module RuboCop
147
160
  end
148
161
  end
149
162
 
163
+ def code_ends_with_continuation?(last_line)
164
+ return false if processed_source.line_with_comment?(processed_source.ast.last_line)
165
+
166
+ last_line.end_with?(LINE_CONTINUATION)
167
+ end
168
+
150
169
  def inside_string_literal?(range, token)
151
170
  ALLOWED_STRING_TOKENS.include?(token.type) && token.pos.overlaps?(range)
152
171
  end
@@ -155,8 +174,9 @@ module RuboCop
155
174
  #
156
175
  # do_something \
157
176
  # argument
158
- def method_with_argument?(current_token, next_token)
177
+ def method_with_argument?(line_range, current_token, next_token)
159
178
  return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
179
+ return false unless current_token.pos.overlaps?(line_range)
160
180
 
161
181
  ARGUMENT_TYPES.include?(next_token.type)
162
182
  end
@@ -180,7 +200,7 @@ module RuboCop
180
200
 
181
201
  def find_node_for_line(last_line)
182
202
  processed_source.ast.each_node do |node|
183
- return node if node.respond_to?(:expression) && node.expression&.last_line == last_line
203
+ return node if same_line?(node, last_line)
184
204
  end
185
205
  end
186
206
 
@@ -209,8 +229,9 @@ module RuboCop
209
229
  node.call_type? && !node.arguments.empty?
210
230
  end
211
231
 
212
- def start_with_arithmetic_operator?(source_line)
213
- %r{\A\s*[+\-*/%]}.match?(source_line)
232
+ def start_with_arithmetic_operator?(range)
233
+ line_range = processed_source.buffer.line_range(range.line + 1)
234
+ ARITHMETIC_OPERATOR_TOKENS.include?(processed_source.first_token_of(line_range).type)
214
235
  end
215
236
  end
216
237
  end
@@ -140,6 +140,9 @@ module RuboCop
140
140
  return 'a literal' if disallowed_literal?(begin_node, node)
141
141
  return 'a variable' if node.variable?
142
142
  return 'a constant' if node.const_type?
143
+ if node.assignment? && (begin_node.parent.nil? || begin_node.parent.begin_type?)
144
+ return 'an assignment'
145
+ end
143
146
  if node.lambda_or_proc? && (node.braces? || node.send_node.lambda_literal?)
144
147
  return 'an expression'
145
148
  end
@@ -166,10 +169,7 @@ module RuboCop
166
169
  def_node_matcher :interpolation?, '[^begin ^^dstr]'
167
170
 
168
171
  def allow_in_multiline_conditions?
169
- parentheses_around_condition_config = config.for_cop('Style/ParenthesesAroundCondition')
170
- return false unless parentheses_around_condition_config['Enabled']
171
-
172
- !!parentheses_around_condition_config['AllowInMultilineConditions']
172
+ !!config.for_enabled_cop('Style/ParenthesesAroundCondition')['AllowInMultilineConditions']
173
173
  end
174
174
 
175
175
  def check_send(begin_node, node)
@@ -73,6 +73,9 @@ module RuboCop
73
73
  new_argument.gsub!("'", "\\\\'")
74
74
  new_argument.gsub!('\"', '"')
75
75
  quote = "'"
76
+ elsif new_argument.include?('\'')
77
+ new_argument.gsub!("'", "\\\\'")
78
+ quote = "'"
76
79
  elsif new_argument.include?('\\')
77
80
  quote = '"'
78
81
  else
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for unnecessary single-element Regexp character classes.
6
+ # Checks for unnecessary single-element `Regexp` character classes.
7
7
  #
8
8
  # @example
9
9
  #
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for redundant escapes inside Regexp literals.
6
+ # Checks for redundant escapes inside `Regexp` literals.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -52,7 +52,7 @@ module RuboCop
52
52
  # rubocop:disable Metrics/AbcSize
53
53
  def on_lvasgn(node)
54
54
  return unless (rhs = node.rhs)
55
- return unless rhs.send_type? && method_returning_self?(rhs.method_name)
55
+ return unless rhs.call_type? && method_returning_self?(rhs.method_name)
56
56
  return unless (receiver = rhs.receiver)
57
57
 
58
58
  receiver_type = ASSIGNMENT_TYPE_TO_RECEIVER_TYPE[node.type]
@@ -77,6 +77,7 @@ module RuboCop
77
77
  corrector.remove(correction_range(node))
78
78
  end
79
79
  end
80
+ alias on_csend on_send
80
81
 
81
82
  private
82
83
 
@@ -88,7 +89,7 @@ module RuboCop
88
89
  def_node_matcher :redundant_self_assignment?, <<~PATTERN
89
90
  (send
90
91
  (self) _
91
- (send
92
+ (call
92
93
  (send
93
94
  {(self) nil?} %1) #method_returning_self?
94
95
  ...))
@@ -96,10 +97,10 @@ module RuboCop
96
97
 
97
98
  # @!method redundant_nonself_assignment?(node, receiver, method_name)
98
99
  def_node_matcher :redundant_nonself_assignment?, <<~PATTERN
99
- (send
100
+ (call
100
101
  %1 _
101
- (send
102
- (send
102
+ (call
103
+ (call
103
104
  %1 %2) #method_returning_self?
104
105
  ...))
105
106
  PATTERN
@@ -323,7 +323,7 @@ module RuboCop
323
323
  return true if unsafe_method?(method)
324
324
 
325
325
  method.each_ancestor(:send).any? do |ancestor|
326
- break true unless config.for_cop('Lint/SafeNavigationChain')['Enabled']
326
+ break true unless config.cop_enabled?('Lint/SafeNavigationChain')
327
327
 
328
328
  break true if unsafe_method?(ancestor)
329
329
  break true if nil_methods.include?(ancestor.method_name)
@@ -68,7 +68,7 @@ module RuboCop
68
68
  def on_send(node)
69
69
  return if allow_send? && !node.method?(:public_send)
70
70
  return unless (first_argument = node.first_argument)
71
- return unless STATIC_METHOD_NAME_NODE_TYPES.include?(first_argument.type)
71
+ return unless first_argument.type?(*STATIC_METHOD_NAME_NODE_TYPES)
72
72
 
73
73
  offense_range = offense_range(node)
74
74
  method_name = first_argument.value
@@ -83,6 +83,7 @@ module RuboCop
83
83
  end
84
84
  end
85
85
  end
86
+ alias on_csend on_send
86
87
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
87
88
 
88
89
  private
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # parameters.
11
11
  #
12
12
  # Configuration option: Methods
13
- # Should be set to use this cop. Array of hashes, where each key is the
13
+ # Should be set to use this cop. `Array` of hashes, where each key is the
14
14
  # method name and value - array of argument names.
15
15
  #
16
16
  # @example Methods: [{reduce: %w[a b]}]
@@ -68,8 +68,7 @@ module RuboCop
68
68
  end
69
69
 
70
70
  def single_line_blocks_preferred?
71
- redundant_line_break_config = @config.for_cop('Layout/RedundantLineBreak')
72
- redundant_line_break_config['Enabled'] && redundant_line_break_config['InspectBlocks']
71
+ @config.for_enabled_cop('Layout/RedundantLineBreak')['InspectBlocks']
73
72
  end
74
73
  end
75
74
  end
@@ -134,10 +134,9 @@ module RuboCop
134
134
  end
135
135
 
136
136
  def disallow_endless_method_style?
137
- endless_method_config = config.for_cop('Style/EndlessMethod')
138
- return true unless endless_method_config['Enabled']
137
+ return true unless config.cop_enabled?('Style/EndlessMethod')
139
138
 
140
- endless_method_config['EnforcedStyle'] == 'disallow'
139
+ config.for_cop('Style/EndlessMethod')['EnforcedStyle'] == 'disallow'
141
140
  end
142
141
  end
143
142
  end
@@ -78,38 +78,67 @@ module RuboCop
78
78
  return unless node.arguments.one?
79
79
 
80
80
  range_node = node.first_argument
81
- selector = node.loc.selector
82
- unless (message, removal_range = offense_message_with_removal_range(range_node, selector))
83
- return
84
- end
81
+ offense_range = find_offense_range(node)
82
+ return unless (message, removal_range =
83
+ offense_message_with_removal_range(node, range_node, offense_range))
84
+
85
+ # Changing the range to beginningless or endless when unparenthesized
86
+ # changes the semantics of the code, and thus will not be considered
87
+ # an offense.
88
+ return if removal_range != offense_range && unparenthesized_call?(node)
85
89
 
86
- add_offense(selector, message: message) do |corrector|
90
+ add_offense(offense_range, message: message) do |corrector|
87
91
  corrector.remove(removal_range)
88
92
  end
89
93
  end
94
+ alias on_csend on_send
90
95
 
91
96
  private
92
97
 
93
- def offense_message_with_removal_range(range_node, selector)
98
+ def unparenthesized_call?(node)
99
+ node.loc.dot && !node.parenthesized?
100
+ end
101
+
102
+ def find_offense_range(node)
103
+ if node.loc.dot
104
+ node.loc.dot.join(node.source_range.end)
105
+ else
106
+ node.loc.selector
107
+ end
108
+ end
109
+
110
+ def offense_message_with_removal_range(node, range_node, offense_range)
94
111
  if range_from_zero_till_minus_one?(range_node)
95
- [format(MSG_USELESS_RANGE, prefer: selector.source), selector]
112
+ [format(MSG_USELESS_RANGE, prefer: offense_range.source), offense_range]
96
113
  elsif range_till_minus_one?(range_node)
97
114
  [
98
- format(MSG, prefer: endless(range_node), current: selector.source), range_node.end
115
+ offense_message_for_partial_range(node, endless(range_node), offense_range),
116
+ range_node.end
99
117
  ]
100
118
  elsif range_from_zero?(range_node) && target_ruby_version >= 2.7
101
119
  [
102
- format(MSG, prefer: beginless(range_node), current: selector.source), range_node.begin
120
+ offense_message_for_partial_range(node, beginless(range_node), offense_range),
121
+ range_node.begin
103
122
  ]
104
123
  end
105
124
  end
106
125
 
126
+ def offense_message_for_partial_range(node, prefer, offense_range)
127
+ current = node.loc.dot ? arguments_source(node) : offense_range.source
128
+ prefer = "[#{prefer}]" unless node.loc.dot
129
+ format(MSG, prefer: prefer, current: current)
130
+ end
131
+
107
132
  def endless(range_node)
108
- "[#{range_node.begin.source}#{range_node.loc.operator.source}]"
133
+ "#{range_node.begin.source}#{range_node.loc.operator.source}"
109
134
  end
110
135
 
111
136
  def beginless(range_node)
112
- "[#{range_node.loc.operator.source}#{range_node.end.source}]"
137
+ "#{range_node.loc.operator.source}#{range_node.end.source}"
138
+ end
139
+
140
+ def arguments_source(node)
141
+ node.first_argument.source_range.join(node.last_argument.source_range.end).source
113
142
  end
114
143
  end
115
144
  end
@@ -243,7 +243,7 @@ module RuboCop
243
243
  def replace_condition(condition)
244
244
  return condition.source unless wrap_condition?(condition)
245
245
 
246
- if condition.call_type?
246
+ if condition.call_type? && !condition.comparison_method?
247
247
  parenthesized_method_arguments(condition)
248
248
  else
249
249
  "(#{condition.source})"
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Enforces the use of consistent method names
7
- # from the String class.
7
+ # from the `String` class.
8
8
  #
9
9
  # @example
10
10
  # # bad