rubocop 1.46.0 → 1.48.0

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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +24 -0
  4. data/lib/rubocop/cli/command/auto_generate_config.rb +7 -0
  5. data/lib/rubocop/comment_config.rb +2 -0
  6. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  7. data/lib/rubocop/cop/base.rb +1 -1
  8. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  9. data/lib/rubocop/cop/corrector.rb +1 -1
  10. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -2
  11. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +3 -3
  12. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +3 -3
  13. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  15. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -1
  16. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  17. data/lib/rubocop/cop/internal_affairs/cop_description.rb +4 -4
  18. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +1 -1
  19. data/lib/rubocop/cop/internal_affairs/location_expression.rb +37 -0
  20. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  21. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +1 -1
  22. data/lib/rubocop/cop/internal_affairs/processed_source_buffer_name.rb +1 -1
  23. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -1
  24. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +1 -1
  25. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +39 -0
  26. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  27. data/lib/rubocop/cop/layout/block_end_newline.rb +4 -4
  28. data/lib/rubocop/cop/layout/class_structure.rb +5 -3
  29. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -1
  30. data/lib/rubocop/cop/layout/empty_comment.rb +3 -3
  31. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  32. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  33. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  34. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  35. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -3
  36. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -2
  37. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +2 -2
  38. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -1
  39. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +1 -1
  40. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  41. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  42. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  43. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  44. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  45. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -3
  46. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  47. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  48. data/lib/rubocop/cop/lint/empty_conditional_body.rb +4 -2
  49. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  50. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
  51. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +46 -4
  52. data/lib/rubocop/cop/lint/missing_super.rb +31 -2
  53. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -0
  54. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  55. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  56. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -3
  57. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -5
  58. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -1
  59. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  60. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
  61. data/lib/rubocop/cop/lint/redundant_with_object.rb +1 -1
  62. data/lib/rubocop/cop/lint/rescue_type.rb +3 -3
  63. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +1 -1
  64. data/lib/rubocop/cop/lint/script_permission.rb +1 -1
  65. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  66. data/lib/rubocop/cop/lint/useless_access_modifier.rb +9 -1
  67. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  68. data/lib/rubocop/cop/metrics/collection_literal_length.rb +76 -0
  69. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  70. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  71. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  72. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  73. data/lib/rubocop/cop/mixin/comments_help.rb +2 -2
  74. data/lib/rubocop/cop/mixin/documentation_comment.rb +1 -1
  75. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +1 -1
  76. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +3 -2
  77. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  78. data/lib/rubocop/cop/mixin/min_branches_count.rb +40 -0
  79. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  80. data/lib/rubocop/cop/mixin/range_help.rb +1 -6
  81. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
  82. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  83. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +1 -1
  84. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  85. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  86. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  87. data/lib/rubocop/cop/registry.rb +3 -1
  88. data/lib/rubocop/cop/style/accessor_grouping.rb +23 -2
  89. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
  90. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  91. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +1 -1
  92. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  93. data/lib/rubocop/cop/style/block_delimiters.rb +11 -2
  94. data/lib/rubocop/cop/style/case_like_if.rb +20 -3
  95. data/lib/rubocop/cop/style/collection_compact.rb +1 -1
  96. data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
  97. data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
  98. data/lib/rubocop/cop/style/concat_array_literals.rb +10 -2
  99. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -6
  100. data/lib/rubocop/cop/style/dir_empty.rb +60 -0
  101. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  102. data/lib/rubocop/cop/style/documentation.rb +10 -4
  103. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  104. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  105. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  106. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  107. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  108. data/lib/rubocop/cop/style/file_empty.rb +71 -0
  109. data/lib/rubocop/cop/style/file_read.rb +1 -1
  110. data/lib/rubocop/cop/style/file_write.rb +1 -1
  111. data/lib/rubocop/cop/style/guard_clause.rb +1 -1
  112. data/lib/rubocop/cop/style/hash_like_case.rb +3 -9
  113. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  114. data/lib/rubocop/cop/style/if_unless_modifier.rb +76 -9
  115. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -0
  116. data/lib/rubocop/cop/style/inverse_methods.rb +5 -5
  117. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +2 -2
  118. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  119. data/lib/rubocop/cop/style/min_max.rb +3 -3
  120. data/lib/rubocop/cop/style/mixin_grouping.rb +4 -4
  121. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
  122. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
  123. data/lib/rubocop/cop/style/negated_if_else_condition.rb +12 -7
  124. data/lib/rubocop/cop/style/nil_lambda.rb +2 -2
  125. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  126. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +2 -2
  127. data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
  128. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +10 -3
  129. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  130. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  131. data/lib/rubocop/cop/style/require_order.rb +1 -3
  132. data/lib/rubocop/cop/style/rescue_standard_error.rb +2 -2
  133. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  134. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -2
  135. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  136. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  137. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +1 -1
  138. data/lib/rubocop/cop/style/unpack_first.rb +3 -3
  139. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  140. data/lib/rubocop/cop/style/zero_length_predicate.rb +9 -5
  141. data/lib/rubocop/cop/team.rb +1 -1
  142. data/lib/rubocop/cop/util.rb +1 -1
  143. data/lib/rubocop/cop/variable_force/variable.rb +5 -3
  144. data/lib/rubocop/directive_comment.rb +3 -3
  145. data/lib/rubocop/ext/comment.rb +18 -0
  146. data/lib/rubocop/formatter/junit_formatter.rb +4 -1
  147. data/lib/rubocop/server/core.rb +1 -1
  148. data/lib/rubocop/version.rb +1 -1
  149. data/lib/rubocop.rb +5 -0
  150. metadata +10 -3
@@ -146,7 +146,7 @@ module RuboCop
146
146
  actual: line_node.source,
147
147
  expected: expected)
148
148
 
149
- add_offense(line_node.loc.expression, message: message) do |corrector|
149
+ add_offense(line_node.source_range, message: message) do |corrector|
150
150
  corrector.replace(line_node, expected)
151
151
  end
152
152
  end
@@ -175,14 +175,14 @@ module RuboCop
175
175
  end
176
176
 
177
177
  def line_difference(line_node, code)
178
- string_first_line(code) - line_node.loc.expression.first_line
178
+ string_first_line(code) - line_node.source_range.first_line
179
179
  end
180
180
 
181
181
  def string_first_line(str_node)
182
182
  if str_node.heredoc?
183
183
  str_node.loc.heredoc_body.first_line
184
184
  else
185
- str_node.loc.expression.first_line
185
+ str_node.source_range.first_line
186
186
  end
187
187
  end
188
188
 
@@ -210,7 +210,7 @@ module RuboCop
210
210
  def add_offense_for_missing_line(node, code)
211
211
  register_offense(node) do |corrector|
212
212
  line_str = missing_line(node, code)
213
- corrector.insert_after(node.loc.expression.end, ", #{line_str}")
213
+ corrector.insert_after(node.source_range.end, ", #{line_str}")
214
214
  end
215
215
  end
216
216
 
@@ -145,7 +145,7 @@ module RuboCop
145
145
  end
146
146
 
147
147
  def block_body_range(block_node, send_node)
148
- range_between(send_node.loc.expression.end_pos, block_node.loc.end.end_pos)
148
+ range_between(send_node.source_range.end_pos, block_node.loc.end.end_pos)
149
149
  end
150
150
  end
151
151
  end
@@ -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
 
@@ -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