rubocop 1.45.1 → 1.48.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +28 -9
  4. data/lib/rubocop/cli/command/auto_generate_config.rb +7 -0
  5. data/lib/rubocop/comment_config.rb +19 -0
  6. data/lib/rubocop/config.rb +2 -2
  7. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  8. data/lib/rubocop/cop/base.rb +1 -1
  9. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  10. data/lib/rubocop/cop/corrector.rb +1 -1
  11. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -2
  12. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +3 -3
  13. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +3 -3
  14. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  15. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  16. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -1
  17. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  18. data/lib/rubocop/cop/gemspec/dependency_version.rb +1 -1
  19. data/lib/rubocop/cop/internal_affairs/cop_description.rb +4 -4
  20. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +1 -1
  21. data/lib/rubocop/cop/internal_affairs/location_expression.rb +37 -0
  22. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  23. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +1 -1
  24. data/lib/rubocop/cop/internal_affairs/processed_source_buffer_name.rb +42 -0
  25. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -1
  26. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +1 -1
  27. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +39 -0
  28. data/lib/rubocop/cop/internal_affairs.rb +3 -0
  29. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -21
  30. data/lib/rubocop/cop/layout/class_structure.rb +5 -3
  31. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -1
  32. data/lib/rubocop/cop/layout/empty_comment.rb +3 -3
  33. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  34. data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
  35. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +8 -2
  37. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  38. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  39. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -3
  40. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -7
  41. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -2
  42. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +2 -2
  43. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -1
  44. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +1 -1
  45. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  46. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  47. data/lib/rubocop/cop/lint/debugger.rb +3 -0
  48. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  49. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  50. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  51. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -3
  52. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  53. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  54. data/lib/rubocop/cop/lint/empty_conditional_body.rb +4 -2
  55. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  56. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
  57. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +46 -4
  58. data/lib/rubocop/cop/lint/missing_super.rb +31 -2
  59. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -9
  60. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -0
  61. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +6 -10
  62. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  63. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  64. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +10 -4
  65. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -5
  66. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -1
  67. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  68. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
  69. data/lib/rubocop/cop/lint/redundant_with_object.rb +1 -1
  70. data/lib/rubocop/cop/lint/refinement_import_methods.rb +2 -1
  71. data/lib/rubocop/cop/lint/rescue_type.rb +3 -3
  72. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +1 -1
  73. data/lib/rubocop/cop/lint/script_permission.rb +1 -1
  74. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  75. data/lib/rubocop/cop/lint/syntax.rb +4 -0
  76. data/lib/rubocop/cop/lint/to_enum_arguments.rb +6 -2
  77. data/lib/rubocop/cop/lint/useless_access_modifier.rb +10 -10
  78. data/lib/rubocop/cop/lint/useless_rescue.rb +6 -2
  79. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  80. data/lib/rubocop/cop/metrics/collection_literal_length.rb +76 -0
  81. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  82. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  83. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  84. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  85. data/lib/rubocop/cop/mixin/comments_help.rb +2 -2
  86. data/lib/rubocop/cop/mixin/documentation_comment.rb +1 -1
  87. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +1 -1
  88. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +10 -5
  89. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  90. data/lib/rubocop/cop/mixin/min_branches_count.rb +40 -0
  91. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +0 -3
  92. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  93. data/lib/rubocop/cop/mixin/range_help.rb +1 -6
  94. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
  95. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  96. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +1 -1
  97. data/lib/rubocop/cop/naming/method_name.rb +3 -3
  98. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  99. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  100. data/lib/rubocop/cop/registry.rb +3 -1
  101. data/lib/rubocop/cop/style/accessor_grouping.rb +39 -17
  102. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
  103. data/lib/rubocop/cop/style/array_intersect.rb +1 -1
  104. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  105. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +1 -1
  106. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  107. data/lib/rubocop/cop/style/block_delimiters.rb +11 -2
  108. data/lib/rubocop/cop/style/case_like_if.rb +20 -3
  109. data/lib/rubocop/cop/style/collection_compact.rb +1 -1
  110. data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
  111. data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
  112. data/lib/rubocop/cop/style/concat_array_literals.rb +10 -2
  113. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -6
  114. data/lib/rubocop/cop/style/dir_empty.rb +60 -0
  115. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  116. data/lib/rubocop/cop/style/documentation.rb +10 -4
  117. data/lib/rubocop/cop/style/documentation_method.rb +4 -4
  118. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  119. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  120. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  121. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  122. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  123. data/lib/rubocop/cop/style/file_empty.rb +71 -0
  124. data/lib/rubocop/cop/style/file_read.rb +1 -1
  125. data/lib/rubocop/cop/style/file_write.rb +1 -1
  126. data/lib/rubocop/cop/style/guard_clause.rb +1 -1
  127. data/lib/rubocop/cop/style/hash_like_case.rb +3 -9
  128. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  129. data/lib/rubocop/cop/style/if_unless_modifier.rb +76 -9
  130. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -0
  131. data/lib/rubocop/cop/style/inverse_methods.rb +5 -5
  132. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +2 -2
  133. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  134. data/lib/rubocop/cop/style/min_max.rb +3 -3
  135. data/lib/rubocop/cop/style/mixin_grouping.rb +4 -4
  136. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
  137. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
  138. data/lib/rubocop/cop/style/negated_if_else_condition.rb +12 -7
  139. data/lib/rubocop/cop/style/nil_lambda.rb +2 -2
  140. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  141. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +2 -2
  142. data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
  143. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  144. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +5 -6
  145. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +10 -3
  146. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  147. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  148. data/lib/rubocop/cop/style/require_order.rb +1 -3
  149. data/lib/rubocop/cop/style/rescue_standard_error.rb +2 -2
  150. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  151. data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
  152. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -2
  153. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  154. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  155. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +1 -1
  156. data/lib/rubocop/cop/style/unpack_first.rb +3 -3
  157. data/lib/rubocop/cop/style/word_array.rb +17 -5
  158. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  159. data/lib/rubocop/cop/style/zero_length_predicate.rb +9 -5
  160. data/lib/rubocop/cop/team.rb +11 -8
  161. data/lib/rubocop/cop/util.rb +13 -4
  162. data/lib/rubocop/cop/variable_force/variable.rb +5 -3
  163. data/lib/rubocop/directive_comment.rb +3 -3
  164. data/lib/rubocop/ext/comment.rb +18 -0
  165. data/lib/rubocop/formatter/junit_formatter.rb +4 -1
  166. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  167. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  168. data/lib/rubocop/rspec/support.rb +1 -0
  169. data/lib/rubocop/server/core.rb +1 -1
  170. data/lib/rubocop/target_ruby.rb +1 -1
  171. data/lib/rubocop/version.rb +1 -1
  172. data/lib/rubocop.rb +5 -0
  173. metadata +17 -9
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Prefer to use `File.empty?('path/to/file')` when checking if a file is empty.
7
+ #
8
+ # @safety
9
+ # This cop's autocorrection is unsafe it because `File.size`, `File.read`,
10
+ # and `File.binread` raise `ENOENT` exception when there is no file
11
+ # corresponding to the path, while `File.empty?` does not raise an exception.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # File.zero?('path/to/file')
16
+ # File.size('path/to/file') == 0
17
+ # File.size('path/to/file') >= 0
18
+ # File.size('path/to/file').zero?
19
+ # File.read('path/to/file').empty?
20
+ # File.binread('path/to/file') == ''
21
+ # FileTest.zero?('path/to/file')
22
+ #
23
+ # # good
24
+ # File.empty?('path/to/file')
25
+ # FileTest.empty?('path/to/file')
26
+ #
27
+ class FileEmpty < Base
28
+ extend AutoCorrector
29
+ extend TargetRubyVersion
30
+
31
+ MSG = 'Use `%<file_class>s.empty?(%<arg>s)` instead.'
32
+ RESTRICT_ON_SEND = %i[>= != == zero? empty?].freeze
33
+
34
+ minimum_target_ruby_version 2.4
35
+
36
+ # @!method offensive?(node)
37
+ def_node_matcher :offensive?, <<~PATTERN
38
+ {
39
+ (send $(const {nil? cbase} {:File :FileTest}) :zero? $_)
40
+ (send (send $(const {nil? cbase} {:File :FileTest}) :size $_) {:== :>=} (int 0))
41
+ (send (send (send $(const {nil? cbase} {:File :FileTest}) :size $_) :!) {:== :>=} (int 0))
42
+ (send (send $(const {nil? cbase} {:File :FileTest}) :size $_) :zero?)
43
+ (send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) {:!= :==} (str empty?))
44
+ (send (send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) :!) {:!= :==} (str empty?))
45
+ (send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) :empty?)
46
+ }
47
+ PATTERN
48
+
49
+ def on_send(node)
50
+ offensive?(node) do |const_node, arg_node|
51
+ add_offense(node,
52
+ message: format(MSG, file_class: const_node.source,
53
+ arg: arg_node.source)) do |corrector|
54
+ corrector.replace(node,
55
+ "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})")
56
+ end
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def bang(node)
63
+ if (node.method?(:==) && node.child_nodes.first.method?(:!)) ||
64
+ (%i[>= !=].include?(node.method_name) && !node.child_nodes.first.method?(:!))
65
+ '!'
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -71,7 +71,7 @@ module RuboCop
71
71
  message = format(MSG, read_method: read_method(mode))
72
72
 
73
73
  add_offense(read_node, message: message) do |corrector|
74
- range = range_between(node.loc.selector.begin_pos, read_node.loc.expression.end_pos)
74
+ range = range_between(node.loc.selector.begin_pos, read_node.source_range.end_pos)
75
75
  replacement = "#{read_method(mode)}(#{filename.source})"
76
76
 
77
77
  corrector.replace(range, replacement)
@@ -74,7 +74,7 @@ module RuboCop
74
74
  message = format(MSG, write_method: write_method(mode))
75
75
 
76
76
  add_offense(write_node, message: message) do |corrector|
77
- range = range_between(node.loc.selector.begin_pos, write_node.loc.expression.end_pos)
77
+ range = range_between(node.loc.selector.begin_pos, write_node.source_range.end_pos)
78
78
  replacement = replacement(mode, filename, content, write_node)
79
79
 
80
80
  corrector.replace(range, replacement)
@@ -182,7 +182,7 @@ module RuboCop
182
182
 
183
183
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
184
184
  def autocorrect(corrector, node, condition, replacement, guard)
185
- corrector.replace(node.loc.keyword.join(condition.loc.expression), replacement)
185
+ corrector.replace(node.loc.keyword.join(condition.source_range), replacement)
186
186
 
187
187
  if_branch = node.if_branch
188
188
  else_branch = node.else_branch
@@ -37,6 +37,8 @@ module RuboCop
37
37
  # end
38
38
  #
39
39
  class HashLikeCase < Base
40
+ include MinBranchesCount
41
+
40
42
  MSG = 'Consider replacing `case-when` with a hash lookup.'
41
43
 
42
44
  # @!method hash_like_case?(node)
@@ -49,7 +51,7 @@ module RuboCop
49
51
  PATTERN
50
52
 
51
53
  def on_case(node)
52
- return if node.when_branches.size < min_branches_count
54
+ return unless min_branches_count?(node)
53
55
 
54
56
  hash_like_case?(node) do |condition_nodes, body_nodes|
55
57
  if nodes_of_same_type?(condition_nodes) && nodes_of_same_type?(body_nodes)
@@ -63,14 +65,6 @@ module RuboCop
63
65
  def nodes_of_same_type?(nodes)
64
66
  nodes.all? { |node| node.type == nodes.first.type }
65
67
  end
66
-
67
- def min_branches_count
68
- length = cop_config['MinBranchesCount'] || 3
69
- return length if length.is_a?(Integer) && length.positive?
70
-
71
- warn Rainbow('`MinBranchesCount` needs to be a positive integer!').red
72
- exit!
73
- end
74
68
  end
75
69
  end
76
70
  end
@@ -247,7 +247,7 @@ module RuboCop
247
247
  end
248
248
 
249
249
  def argument_without_space?(node)
250
- node.argument? && node.loc.expression.begin_pos == node.parent.loc.selector.end_pos
250
+ node.argument? && node.source_range.begin_pos == node.parent.loc.selector.end_pos
251
251
  end
252
252
 
253
253
  def autocorrect_hash_rockets(corrector, pair_node)
@@ -11,6 +11,20 @@ module RuboCop
11
11
  # cop. The tab size is configured in the `IndentationWidth` of the
12
12
  # `Layout/IndentationStyle` cop.
13
13
  #
14
+ # NOTE: It is allowed when `defined?` argument has an undefined value,
15
+ # because using the modifier form causes the following incompatibility:
16
+ #
17
+ # [source,ruby]
18
+ # ----
19
+ # unless defined?(undefined_foo)
20
+ # undefined_foo = 'default_value'
21
+ # end
22
+ # undefined_foo # => 'default_value'
23
+ #
24
+ # undefined_bar = 'default_value' unless defined?(undefined_bar)
25
+ # undefined_bar # => nil
26
+ # ----
27
+ #
14
28
  # @example
15
29
  # # bad
16
30
  # if condition
@@ -39,6 +53,7 @@ module RuboCop
39
53
  include LineLengthHelp
40
54
  include AllowedPattern
41
55
  include RangeHelp
56
+ include CommentsHelp
42
57
  extend AutoCorrector
43
58
 
44
59
  MSG_USE_MODIFIER = 'Favor modifier `%<keyword>s` usage when having a ' \
@@ -51,6 +66,8 @@ module RuboCop
51
66
  end
52
67
 
53
68
  def on_if(node)
69
+ return if defined_nodes(node).any? { |n| defined_argument_is_undefined?(node, n) }
70
+
54
71
  msg = if single_line_as_modifier?(node) && !named_capture_in_condition?(node)
55
72
  MSG_USE_MODIFIER
56
73
  elsif too_long_due_to_modifier?(node)
@@ -65,28 +82,63 @@ module RuboCop
65
82
 
66
83
  private
67
84
 
85
+ def defined_nodes(node)
86
+ if node.condition.defined_type?
87
+ [node.condition]
88
+ else
89
+ node.condition.each_descendant.select(&:defined_type?)
90
+ end
91
+ end
92
+
93
+ def defined_argument_is_undefined?(if_node, defined_node)
94
+ defined_argument = defined_node.first_argument
95
+ return false unless defined_argument.lvar_type? || defined_argument.send_type?
96
+
97
+ if_node.left_siblings.none? do |sibling|
98
+ sibling.respond_to?(:lvasgn_type?) && sibling.lvasgn_type? &&
99
+ sibling.name == defined_argument.node_parts[0]
100
+ end
101
+ end
102
+
68
103
  def autocorrect(corrector, node)
69
104
  replacement = if node.modifier_form?
70
- last_argument = node.if_branch.last_argument if node.if_branch.send_type?
71
-
72
- if last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
73
- heredoc = extract_heredoc_from(last_argument)
74
- remove_heredoc(corrector, heredoc)
75
- to_normal_form_with_heredoc(node, indent(node), heredoc)
76
- else
77
- to_normal_form(node, indent(node))
78
- end
105
+ replacement_for_modifier_form(corrector, node)
79
106
  else
80
107
  to_modifier_form(node)
81
108
  end
82
109
  corrector.replace(node, replacement)
83
110
  end
84
111
 
112
+ def replacement_for_modifier_form(corrector, node) # rubocop:disable Metrics/AbcSize
113
+ comment = comment_on_node_line(node)
114
+ if comment && too_long_due_to_comment_after_modifier?(node, comment)
115
+ remove_comment(corrector, node, comment)
116
+
117
+ return to_modifier_form_with_move_comment(node, indent(node), comment)
118
+ end
119
+
120
+ last_argument = node.if_branch.last_argument if node.if_branch.send_type?
121
+ if last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
122
+ heredoc = extract_heredoc_from(last_argument)
123
+ remove_heredoc(corrector, heredoc)
124
+
125
+ return to_normal_form_with_heredoc(node, indent(node), heredoc)
126
+ end
127
+
128
+ to_normal_form(node, indent(node))
129
+ end
130
+
85
131
  def too_long_due_to_modifier?(node)
86
132
  node.modifier_form? && too_long_single_line?(node) &&
87
133
  !another_statement_on_same_line?(node)
88
134
  end
89
135
 
136
+ def too_long_due_to_comment_after_modifier?(node, comment)
137
+ source_length = processed_source.lines[node.first_line - 1].length
138
+ source_length >= max_line_length &&
139
+ source_length - comment.source_range.length <= max_line_length
140
+ end
141
+
90
142
  def allowed_patterns
91
143
  line_length_config = config.for_cop('Layout/LineLength')
92
144
  line_length_config['AllowedPatterns'] || line_length_config['IgnoredPatterns'] || []
@@ -181,6 +233,13 @@ module RuboCop
181
233
  RUBY
182
234
  end
183
235
 
236
+ def to_modifier_form_with_move_comment(node, indentation, comment)
237
+ <<~RUBY.chomp
238
+ #{comment.source}
239
+ #{indentation}#{node.body.source} #{node.keyword} #{node.condition.source}
240
+ RUBY
241
+ end
242
+
184
243
  def extract_heredoc_from(last_argument)
185
244
  heredoc_body = last_argument.loc.heredoc_body
186
245
  heredoc_end = last_argument.loc.heredoc_end
@@ -193,6 +252,14 @@ module RuboCop
193
252
  corrector.remove(range_by_whole_lines(range, include_final_newline: true))
194
253
  end
195
254
  end
255
+
256
+ def comment_on_node_line(node)
257
+ processed_source.comments.find { |c| same_line?(c, node) }
258
+ end
259
+
260
+ def remove_comment(corrector, _node, comment)
261
+ corrector.remove(range_with_surrounding_space(range: comment.source_range, side: :left))
262
+ end
196
263
  end
197
264
  end
198
265
  end
@@ -118,6 +118,8 @@ module RuboCop
118
118
  end
119
119
 
120
120
  def return_boolean_value?(condition)
121
+ return false unless condition
122
+
121
123
  if condition.begin_type?
122
124
  return_boolean_value?(condition.children.first)
123
125
  elsif condition.or_type?
@@ -155,15 +155,15 @@ module RuboCop
155
155
  end
156
156
 
157
157
  def not_to_receiver(node, method_call)
158
- Parser::Source::Range.new(node.loc.expression.source_buffer,
158
+ Parser::Source::Range.new(node.source_range.source_buffer,
159
159
  node.loc.selector.begin_pos,
160
- method_call.loc.expression.begin_pos)
160
+ method_call.source_range.begin_pos)
161
161
  end
162
162
 
163
163
  def end_parentheses(node, method_call)
164
- Parser::Source::Range.new(node.loc.expression.source_buffer,
165
- method_call.loc.expression.end_pos,
166
- node.loc.expression.end_pos)
164
+ Parser::Source::Range.new(node.source_range.source_buffer,
165
+ method_call.source_range.end_pos,
166
+ node.source_range.end_pos)
167
167
  end
168
168
 
169
169
  # When comparing classes, `!(Integer < Numeric)` is not the same as
@@ -123,10 +123,10 @@ module RuboCop
123
123
  end
124
124
 
125
125
  def range(node)
126
- buffer = node.loc.expression.source_buffer
126
+ buffer = node.source_range.source_buffer
127
127
  map_node = node.receiver.send_node
128
128
  begin_pos = map_node.loc.selector.begin_pos
129
- end_pos = node.loc.expression.end_pos
129
+ end_pos = node.source_range.end_pos
130
130
 
131
131
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
132
132
  end
@@ -226,7 +226,7 @@ module RuboCop
226
226
  end
227
227
 
228
228
  def args_end(node)
229
- node.loc.expression.end
229
+ node.source_range.end
230
230
  end
231
231
 
232
232
  def args_parenthesized?(node)
@@ -48,13 +48,13 @@ module RuboCop
48
48
  when :return
49
49
  argument_range(node)
50
50
  else
51
- node.loc.expression
51
+ node.source_range
52
52
  end
53
53
  end
54
54
 
55
55
  def argument_range(node)
56
- first_argument_range = node.children.first.loc.expression
57
- last_argument_range = node.children.last.loc.expression
56
+ first_argument_range = node.children.first.source_range
57
+ last_argument_range = node.children.last.source_range
58
58
 
59
59
  first_argument_range.join(last_argument_range)
60
60
  end
@@ -51,9 +51,9 @@ module RuboCop
51
51
  private
52
52
 
53
53
  def range_to_remove_for_subsequent_mixin(mixins, node)
54
- range = node.loc.expression
54
+ range = node.source_range
55
55
  prev_mixin = mixins.each_cons(2) { |m, n| break m if n == node }
56
- between = prev_mixin.loc.expression.end.join(range.begin)
56
+ between = prev_mixin.source_range.end.join(range.begin)
57
57
  # if separated from previous mixin with only whitespace?
58
58
  unless /\S/.match?(between.source)
59
59
  range = range.join(between) # then remove that too
@@ -75,7 +75,7 @@ module RuboCop
75
75
  message = format(MSG, mixin: send_node.method_name, suffix: 'a single statement')
76
76
 
77
77
  add_offense(send_node, message: message) do |corrector|
78
- range = send_node.loc.expression
78
+ range = send_node.source_range
79
79
  mixins = sibling_mixins(send_node)
80
80
  if send_node == mixins.first
81
81
  correction = group_mixins(send_node, mixins)
@@ -94,7 +94,7 @@ module RuboCop
94
94
  message = format(MSG, mixin: send_node.method_name, suffix: 'separate statements')
95
95
 
96
96
  add_offense(send_node, message: message) do |corrector|
97
- range = send_node.loc.expression
97
+ range = send_node.source_range
98
98
  correction = separate_mixins(send_node)
99
99
 
100
100
  corrector.replace(range, correction)
@@ -75,7 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  def indentation_width(node)
78
- processed_source.line_indentation(node.loc.expression.line)
78
+ processed_source.line_indentation(node.source_range.line)
79
79
  end
80
80
 
81
81
  def definition_width(node)
@@ -83,7 +83,7 @@ module RuboCop
83
83
 
84
84
  def comments_in_condition(node)
85
85
  comments_in_range(node).map do |comment|
86
- "#{comment.loc.expression.source}\n"
86
+ "#{comment.source}\n"
87
87
  end.join
88
88
  end
89
89
 
@@ -48,13 +48,11 @@ module RuboCop
48
48
 
49
49
  def on_if(node)
50
50
  return unless if_else?(node)
51
-
52
- condition = unwrap_begin_nodes(node.condition)
53
-
51
+ return unless (condition = unwrap_begin_nodes(node.condition))
54
52
  return if double_negation?(condition) || !negated_condition?(condition)
55
53
 
56
- type = node.ternary? ? 'ternary' : 'if-else'
57
- add_offense(node, message: format(MSG, type: type)) do |corrector|
54
+ message = message(node)
55
+ add_offense(node, message: message) do |corrector|
58
56
  unless corrected_ancestor?(node)
59
57
  correct_negated_condition(corrector, condition)
60
58
  swap_branches(corrector, node)
@@ -73,7 +71,8 @@ module RuboCop
73
71
  end
74
72
 
75
73
  def unwrap_begin_nodes(node)
76
- node = node.children.first while node.begin_type? || node.kwbegin_type?
74
+ node = node.children.first while node && (node.begin_type? || node.kwbegin_type?)
75
+
77
76
  node
78
77
  end
79
78
 
@@ -82,6 +81,12 @@ module RuboCop
82
81
  (node.negation_method? || NEGATED_EQUALITY_METHODS.include?(node.method_name))
83
82
  end
84
83
 
84
+ def message(node)
85
+ type = node.ternary? ? 'ternary' : 'if-else'
86
+
87
+ format(MSG, type: type)
88
+ end
89
+
85
90
  def corrected_ancestor?(node)
86
91
  node.each_ancestor(:if).any? { |ancestor| @corrected_nodes&.include?(ancestor) }
87
92
  end
@@ -112,7 +117,7 @@ module RuboCop
112
117
  if node.ternary?
113
118
  node.if_branch
114
119
  else
115
- range_between(node.condition.loc.expression.end_pos, node.loc.else.begin_pos)
120
+ range_between(node.condition.source_range.end_pos, node.loc.else.begin_pos)
116
121
  end
117
122
  end
118
123
 
@@ -57,9 +57,9 @@ module RuboCop
57
57
 
58
58
  def autocorrect(corrector, node)
59
59
  range = if node.single_line?
60
- range_with_surrounding_space(node.body.loc.expression)
60
+ range_with_surrounding_space(node.body.source_range)
61
61
  else
62
- range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
62
+ range_by_whole_lines(node.body.source_range, include_final_newline: true)
63
63
  end
64
64
 
65
65
  corrector.remove(range)
@@ -70,8 +70,8 @@ module RuboCop
70
70
  end
71
71
 
72
72
  def range_of_offense(node)
73
- return node.loc.expression unless node.ternary?
74
- return node.loc.expression if node.ternary? && branches_have_method?(node)
73
+ return node.source_range unless node.ternary?
74
+ return node.source_range if node.ternary? && branches_have_method?(node)
75
75
 
76
76
  range_between(node.loc.question.begin_pos, node.loc.colon.end_pos)
77
77
  end
@@ -33,11 +33,11 @@ module RuboCop
33
33
  private
34
34
 
35
35
  def opening_brace(node)
36
- node.loc.begin.join(node.children.first.loc.expression.begin)
36
+ node.loc.begin.join(node.children.first.source_range.begin)
37
37
  end
38
38
 
39
39
  def closing_brace(node)
40
- node.children.last.loc.expression.end.join(node.loc.end)
40
+ node.children.last.source_range.end.join(node.loc.end)
41
41
  end
42
42
  end
43
43
  end
@@ -97,7 +97,7 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def autocorrect_variable_interpolation(corrector, embedded_node, node)
100
- replacement = "#{embedded_node.loc.expression.source}.to_s"
100
+ replacement = "#{embedded_node.source}.to_s"
101
101
 
102
102
  corrector.replace(node, replacement)
103
103
  end
@@ -107,7 +107,7 @@ module RuboCop
107
107
 
108
108
  source = if require_parentheses?(embedded_var)
109
109
  receiver = range_between(
110
- embedded_var.loc.expression.begin_pos, embedded_var.loc.selector.end_pos
110
+ embedded_var.source_range.begin_pos, embedded_var.loc.selector.end_pos
111
111
  )
112
112
  arguments = embedded_var.arguments.map(&:source).join(', ')
113
113
 
@@ -153,7 +153,7 @@ module RuboCop
153
153
 
154
154
  return if node.send_type? && !method_call_with_redundant_parentheses?(node)
155
155
 
156
- offense(begin_node, 'an unary operation')
156
+ offense(begin_node, 'a unary operation')
157
157
  end
158
158
 
159
159
  def offense(node, msg)
@@ -74,7 +74,7 @@ module RuboCop
74
74
 
75
75
  non_redundant =
76
76
  whitespace_in_free_space_mode?(node, class_elem) ||
77
- backslash_b?(class_elem) || backslash_zero?(class_elem) ||
77
+ backslash_b?(class_elem) || octal_requiring_char_class?(class_elem) ||
78
78
  requires_escape_outside_char_class?(class_elem)
79
79
 
80
80
  !non_redundant
@@ -104,11 +104,10 @@ module RuboCop
104
104
  elem == '\b'
105
105
  end
106
106
 
107
- def backslash_zero?(elem)
108
- # See https://github.com/rubocop/rubocop/issues/11067 for details - in short "\0" != "0" -
109
- # the former means an Unicode code point `"\u0000"`, the latter a number character `"0"`.
110
- # Similarly "\032" means "\u001A". Other numbers starting with "\0" can also be mentioned.
111
- elem == '\0'
107
+ def octal_requiring_char_class?(elem)
108
+ # The octal escapes \1 to \7 only work inside a character class
109
+ # because they would be a backreference outside it.
110
+ elem.match?(/\A\\[1-7]\z/)
112
111
  end
113
112
 
114
113
  def requires_escape_outside_char_class?(elem)
@@ -74,11 +74,18 @@ module RuboCop
74
74
 
75
75
  def char_class_begins_or_ends_with_escaped_hyphen?(node, index)
76
76
  # The hyphen character is allowed to be escaped within a character class
77
- # but it's not necessry to escape hyphen if it's the first or last character
77
+ # but it's not necessary to escape hyphen if it's the first or last character
78
78
  # within the character class. This method checks if that's the case.
79
79
  # e.g. "[0-9\\-]" or "[\\-0-9]" would return true
80
- contents_range(node).source[index - 1] == '[' ||
81
- contents_range(node).source[index + 2] == ']'
80
+ content = contents_range(node).source
81
+
82
+ if content[index + 2] == ']'
83
+ true
84
+ elsif content[index - 1] == '['
85
+ index < 2 || content[index - 2] != '\\'
86
+ else
87
+ false
88
+ end
82
89
  end
83
90
 
84
91
  def delimiter?(node, char)
@@ -129,13 +129,13 @@ module RuboCop
129
129
  end
130
130
 
131
131
  def offense_range(sort_node, node)
132
- range_between(sort_node.loc.selector.begin_pos, node.loc.expression.end_pos)
132
+ range_between(sort_node.loc.selector.begin_pos, node.source_range.end_pos)
133
133
  end
134
134
 
135
135
  def message(node, sorter, accessor)
136
136
  accessor_source = range_between(
137
137
  node.loc.selector.begin_pos,
138
- node.loc.expression.end_pos
138
+ node.source_range.end_pos
139
139
  ).source
140
140
 
141
141
  format(MSG,
@@ -146,7 +146,7 @@ module RuboCop
146
146
 
147
147
  def autocorrect(corrector, node, sort_node, sorter, accessor)
148
148
  # Remove accessor, e.g. `first` or `[-1]`.
149
- corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
149
+ corrector.remove(range_between(accessor_start(node), node.source_range.end_pos))
150
150
  # Replace "sort" or "sort_by" with the appropriate min/max method.
151
151
  corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
152
152
  # Replace to avoid syntax errors when followed by a logical operator.
@@ -67,7 +67,7 @@ module RuboCop
67
67
  elsif begin_loc_present?(node)
68
68
  contents_range(node)
69
69
  else
70
- node.loc.expression
70
+ node.source_range
71
71
  end
72
72
  end
73
73
 
@@ -139,7 +139,7 @@ module RuboCop
139
139
 
140
140
  def heredoc_with_disabled_interpolation?(node)
141
141
  if heredoc?(node)
142
- node.loc.expression.source.end_with?("'")
142
+ node.source.end_with?("'")
143
143
  elsif node.parent&.dstr_type?
144
144
  heredoc_with_disabled_interpolation?(node.parent)
145
145
  else
@@ -125,9 +125,7 @@ module RuboCop
125
125
  end
126
126
 
127
127
  def in_same_section?(node1, node2)
128
- !node1.location.expression.with(
129
- end_pos: node2.location.expression.end_pos
130
- ).source.include?("\n\n")
128
+ !node1.source_range.with(end_pos: node2.source_range.end_pos).source.include?("\n\n")
131
129
  end
132
130
  end
133
131
  end
@@ -105,11 +105,11 @@ module RuboCop
105
105
  private
106
106
 
107
107
  def offense_for_implicit_enforced_style(node, error)
108
- range = node.loc.keyword.join(error.loc.expression)
108
+ range = node.loc.keyword.join(error.source_range)
109
109
 
110
110
  add_offense(range, message: MSG_IMPLICIT) do |corrector|
111
111
  error = rescue_standard_error?(node)
112
- range = range_between(node.loc.keyword.end_pos, error.loc.expression.end_pos)
112
+ range = range_between(node.loc.keyword.end_pos, error.source_range.end_pos)
113
113
 
114
114
  corrector.remove(range)
115
115
  end