rubocop 1.75.8 → 1.82.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -16
  3. data/config/default.yml +142 -33
  4. data/config/obsoletion.yml +10 -3
  5. data/exe/rubocop +1 -8
  6. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  7. data/lib/rubocop/cli.rb +20 -4
  8. data/lib/rubocop/comment_config.rb +62 -17
  9. data/lib/rubocop/config_loader.rb +6 -40
  10. data/lib/rubocop/config_loader_resolver.rb +7 -6
  11. data/lib/rubocop/config_store.rb +5 -0
  12. data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
  13. data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -3
  14. data/lib/rubocop/cop/correctors/alignment_corrector.rb +8 -7
  15. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  16. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  17. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  18. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
  19. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +2 -3
  20. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  21. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  22. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  23. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  24. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
  25. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  26. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
  27. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
  28. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  29. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  30. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  31. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  32. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  33. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
  34. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
  35. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  36. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
  37. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  38. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  39. data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
  40. data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
  41. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  42. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -4
  43. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  44. data/lib/rubocop/cop/layout/indentation_width.rb +12 -1
  45. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  46. data/lib/rubocop/cop/layout/line_length.rb +43 -10
  47. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  48. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -1
  49. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
  50. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
  51. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  52. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  53. data/lib/rubocop/cop/layout/space_around_keyword.rb +7 -2
  54. data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
  55. data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
  56. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
  57. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  58. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  59. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  60. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  61. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
  62. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  63. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  64. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  65. data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
  66. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  67. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  68. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  69. data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
  70. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  71. data/lib/rubocop/cop/lint/literal_as_condition.rb +38 -28
  72. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  73. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
  74. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  75. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
  76. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  77. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  78. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  79. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
  80. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
  81. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
  82. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  83. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  84. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  85. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
  86. data/lib/rubocop/cop/lint/self_assignment.rb +39 -5
  87. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  88. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
  89. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  90. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  91. data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
  92. data/lib/rubocop/cop/lint/useless_assignment.rb +44 -16
  93. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  94. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
  95. data/lib/rubocop/cop/lint/useless_or.rb +111 -0
  96. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
  97. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  98. data/lib/rubocop/cop/lint/void.rb +7 -0
  99. data/lib/rubocop/cop/message_annotator.rb +1 -1
  100. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  101. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  102. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  103. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -4
  104. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  105. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  106. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  107. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  108. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
  109. data/lib/rubocop/cop/mixin/line_length_help.rb +45 -10
  110. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  111. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  112. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  113. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  114. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  115. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  116. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
  117. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  118. data/lib/rubocop/cop/naming/method_name.rb +129 -13
  119. data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
  120. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
  121. data/lib/rubocop/cop/security/eval.rb +2 -1
  122. data/lib/rubocop/cop/security/json_load.rb +33 -11
  123. data/lib/rubocop/cop/security/open.rb +1 -0
  124. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
  125. data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
  126. data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
  127. data/lib/rubocop/cop/style/array_intersect.rb +99 -35
  128. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  129. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
  130. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  131. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  132. data/lib/rubocop/cop/style/case_equality.rb +11 -13
  133. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  134. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
  135. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  136. data/lib/rubocop/cop/style/conditional_assignment.rb +12 -16
  137. data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
  138. data/lib/rubocop/cop/style/dig_chain.rb +1 -1
  139. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  140. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  141. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  142. data/lib/rubocop/cop/style/endless_method.rb +15 -2
  143. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  144. data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
  145. data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
  146. data/lib/rubocop/cop/style/float_division.rb +15 -1
  147. data/lib/rubocop/cop/style/guard_clause.rb +0 -11
  148. data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
  149. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  150. data/lib/rubocop/cop/style/if_unless_modifier.rb +16 -9
  151. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  152. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  153. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  154. data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
  155. data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
  156. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  157. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
  158. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
  159. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +33 -4
  160. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  161. data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
  162. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  163. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  164. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
  165. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  166. data/lib/rubocop/cop/style/parallel_assignment.rb +34 -22
  167. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  168. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  169. data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
  170. data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
  171. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  172. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  173. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  174. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  175. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  176. data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
  177. data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
  178. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
  179. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
  180. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  181. data/lib/rubocop/cop/style/redundant_self.rb +8 -5
  182. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  183. data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
  184. data/lib/rubocop/cop/style/semicolon.rb +23 -7
  185. data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
  186. data/lib/rubocop/cop/style/sole_nested_conditional.rb +40 -3
  187. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  188. data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
  189. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  190. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  191. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  192. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  193. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  194. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  195. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  196. data/lib/rubocop/cop/util.rb +2 -3
  197. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  198. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  199. data/lib/rubocop/cop/variable_force.rb +25 -8
  200. data/lib/rubocop/cops_documentation_generator.rb +5 -4
  201. data/lib/rubocop/directive_comment.rb +46 -3
  202. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -5
  203. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  204. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  205. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  206. data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
  207. data/lib/rubocop/lsp/diagnostic.rb +14 -18
  208. data/lib/rubocop/lsp/routes.rb +35 -6
  209. data/lib/rubocop/lsp/stdin_runner.rb +0 -16
  210. data/lib/rubocop/magic_comment.rb +20 -0
  211. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  212. data/lib/rubocop/rake_task.rb +1 -1
  213. data/lib/rubocop/remote_config.rb +7 -8
  214. data/lib/rubocop/result_cache.rb +51 -38
  215. data/lib/rubocop/rspec/expect_offense.rb +9 -3
  216. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  217. data/lib/rubocop/rspec/support.rb +1 -1
  218. data/lib/rubocop/runner.rb +10 -4
  219. data/lib/rubocop/server/cache.rb +4 -2
  220. data/lib/rubocop/server/client_command/base.rb +10 -0
  221. data/lib/rubocop/server/client_command/exec.rb +2 -1
  222. data/lib/rubocop/server/client_command/start.rb +11 -1
  223. data/lib/rubocop/target_finder.rb +9 -9
  224. data/lib/rubocop/target_ruby.rb +11 -2
  225. data/lib/rubocop/version.rb +1 -1
  226. data/lib/rubocop.rb +13 -1
  227. data/lib/ruby_lsp/rubocop/addon.rb +25 -10
  228. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  229. metadata +20 -8
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Gemspec
6
- # Checks that `RUBY_VERSION` constant is not used in gemspec.
7
- # Using `RUBY_VERSION` is dangerous because value of the
6
+ # Checks that `RUBY_VERSION` and `Ruby::VERSION` constants are not used in gemspec.
7
+ # Using `RUBY_VERSION` and `Ruby::VERSION` are dangerous because value of the
8
8
  # constant is determined by `rake release`.
9
9
  # It's possible to have dependency based on ruby version used
10
10
  # to execute `rake release` and not user's ruby version.
@@ -28,15 +28,20 @@ module RuboCop
28
28
  class RubyVersionGlobalsUsage < Base
29
29
  include GemspecHelp
30
30
 
31
- MSG = 'Do not use `RUBY_VERSION` in gemspec file.'
31
+ MSG = 'Do not use `%<ruby_version>s` in gemspec file.'
32
32
 
33
33
  # @!method ruby_version?(node)
34
- def_node_matcher :ruby_version?, '(const {cbase nil?} :RUBY_VERSION)'
34
+ def_node_matcher :ruby_version?, <<~PATTERN
35
+ {
36
+ (const {cbase nil?} :RUBY_VERSION)
37
+ (const (const {cbase nil?} :Ruby) :VERSION)
38
+ }
39
+ PATTERN
35
40
 
36
41
  def on_const(node)
37
42
  return unless gem_spec_with_ruby_version?(node)
38
43
 
39
- add_offense(node)
44
+ add_offense(node, message: format(MSG, ruby_version: node.source))
40
45
  end
41
46
 
42
47
  private
@@ -46,7 +46,7 @@ module RuboCop
46
46
  /\A(does not|doesn't) (register|find|flag|report)/ => 'registers',
47
47
  /\A(does not|doesn't) add (a|an|any )?offense/ => 'registers an offense',
48
48
  /\Aregisters no offense/ => 'registers an offense',
49
- /\A(accepts|register)\b/ => 'registers'
49
+ /\A(accepts|allows|register)\b/ => 'registers'
50
50
  }.freeze
51
51
 
52
52
  EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
@@ -9,6 +9,12 @@ module RuboCop
9
9
  #
10
10
  # @example
11
11
  # # bad
12
+ # node.loc.respond_to?(:begin)
13
+ #
14
+ # # good
15
+ # node.loc?(:begin)
16
+ #
17
+ # # bad
12
18
  # node.loc.respond_to?(:begin) && node.loc.begin
13
19
  #
14
20
  # # good
@@ -29,7 +35,16 @@ module RuboCop
29
35
  class LocationExists < Base
30
36
  extend AutoCorrector
31
37
 
32
- MSG = 'Use `%<replacement>s` instead of `%<source>s`.'
38
+ MSG = 'Use `node.loc?` instead of `loc.respond_to?`.'
39
+ MSG_CORRECTABLE = 'Use `%<replacement>s` instead of `%<source>s`.'
40
+ RESTRICT_ON_SEND = %i[respond_to?].freeze
41
+
42
+ # @!method loc_respond_to?(node)
43
+ def_node_matcher :loc_respond_to?, <<~PATTERN
44
+ (call
45
+ (call $_receiver :loc) :respond_to?
46
+ $(sym _location))
47
+ PATTERN
33
48
 
34
49
  # @!method replaceable_with_loc_is(node)
35
50
  def_node_matcher :replaceable_with_loc_is, <<~PATTERN
@@ -64,6 +79,15 @@ module RuboCop
64
79
  replace_with_loc(node) || replace_with_loc_is(node)
65
80
  end
66
81
 
82
+ def on_send(node)
83
+ return if ignored_node?(node.parent)
84
+
85
+ loc_respond_to?(node) do |receiver, location|
86
+ register_offense(node, replacement(receiver, "loc?(#{location.source})"))
87
+ end
88
+ end
89
+ alias on_csend on_send
90
+
67
91
  private
68
92
 
69
93
  def replace_with_loc(node)
@@ -84,11 +108,13 @@ module RuboCop
84
108
  end
85
109
 
86
110
  def register_offense(node, replacement)
87
- message = format(MSG, replacement: replacement, source: node.source)
111
+ message = format(MSG_CORRECTABLE, replacement: replacement, source: node.source)
88
112
 
89
113
  add_offense(node, message: message) do |corrector|
90
114
  corrector.replace(node, replacement)
91
115
  end
116
+
117
+ ignore_node(node)
92
118
  end
93
119
 
94
120
  def replacement(receiver, rest)
@@ -110,8 +110,8 @@ module RuboCop
110
110
  def directive_offense_type(directive, actual_name)
111
111
  return :missing_directive unless directive
112
112
 
113
- return :wrong_scope if wrong_scope(directive, actual_name)
114
- return :no_scope if no_scope(directive, actual_name)
113
+ return :wrong_scope if wrong_scope?(directive, actual_name)
114
+ return :no_scope if no_scope?(directive, actual_name)
115
115
 
116
116
  # The method directive being prefixed by 'self.' is always an offense.
117
117
  # The matched method_name does not contain the receiver but the
@@ -121,11 +121,11 @@ module RuboCop
121
121
  end
122
122
  end
123
123
 
124
- def wrong_scope(directive, actual_name)
124
+ def wrong_scope?(directive, actual_name)
125
125
  !actual_name.start_with?('self.') && directive[:has_scope_directive]
126
126
  end
127
127
 
128
- def no_scope(directive, actual_name)
128
+ def no_scope?(directive, actual_name)
129
129
  actual_name.start_with?('self.') && !directive[:has_scope_directive]
130
130
  end
131
131
 
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # AST Processor for NodePattern ASTs, for use with `InternalAffairs/NodePatternGroups`.
8
8
  #
9
9
  # Looks for sequences and subsequences where the first item is a `node_type` node,
10
- # and converts them to `node_sequence` nodes (not a true `Rubocop::AST::NodePattern`
10
+ # and converts them to `node_sequence` nodes (not a true `RuboCop::AST::NodePattern`
11
11
  # node type).
12
12
  #
13
13
  # The resulting AST will be walked by `InternalAffairs::NodePatternGroups::ASTWalker`
@@ -29,6 +29,9 @@ module RuboCop
29
29
  NODE_GROUPS = {
30
30
  any_block: %i[block numblock itblock],
31
31
  any_def: %i[def defs],
32
+ any_match_pattern: %i[match_pattern match_pattern_p],
33
+ any_str: %i[str dstr xstr],
34
+ any_sym: %i[sym dsym],
32
35
  argument: %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg forward_arg shadowarg],
33
36
  boolean: %i[true false],
34
37
  call: %i[send csend],
@@ -209,7 +212,7 @@ module RuboCop
209
212
  # A heredoc can be a `dstr` without interpolation, but if there is interpolation
210
213
  # there'll be a `begin` node, in which case, we cannot evaluate the pattern.
211
214
  def acceptable_heredoc?(node)
212
- node.type?(:str, :dstr) && node.heredoc? && node.each_child_node(:begin).none?
215
+ node.any_str_type? && node.heredoc? && node.each_child_node(:begin).none?
213
216
  end
214
217
 
215
218
  def process_pattern(pattern_node)
@@ -66,8 +66,9 @@ module RuboCop
66
66
  end
67
67
 
68
68
  def autocorrect_to_explicit_predicate(corrector, node, group_name)
69
- corrector.replace(node.selector, "#{group_name}_type?")
70
- corrector.remove(arguments_range(node))
69
+ range = node.loc.selector.begin.join(node.source_range.end)
70
+
71
+ corrector.replace(range, "#{group_name}_type?")
71
72
  end
72
73
 
73
74
  def autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
@@ -76,7 +76,7 @@ module RuboCop
76
76
  end
77
77
 
78
78
  def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
79
- new_identifier = node.first_argument
79
+ return unless (new_identifier = node.first_argument)
80
80
  return unless new_identifier.basic_literal?
81
81
 
82
82
  new_identifier = new_identifier.value
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module InternalAffairs
6
- # Check for useless `RESTRICT_ON_SEND`.
6
+ # Checks for useless `RESTRICT_ON_SEND`.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -357,7 +357,7 @@ module RuboCop
357
357
  end
358
358
 
359
359
  def find_heredoc(node)
360
- node.each_node(:str, :dstr, :xstr).find(&:heredoc?)
360
+ node.each_node(:any_str).find(&:heredoc?)
361
361
  end
362
362
 
363
363
  def buffer
@@ -161,7 +161,7 @@ module RuboCop
161
161
  elements.flat_map do |e|
162
162
  e.loc.column
163
163
  end
164
- end.uniq.count == 1
164
+ end.uniq.one?
165
165
  end
166
166
 
167
167
  def first_argument_line(elements)
@@ -120,7 +120,7 @@ module RuboCop
120
120
  end
121
121
 
122
122
  def heredoc?(node)
123
- node.type?(:str, :dstr) && node.heredoc?
123
+ node.any_str_type? && node.heredoc?
124
124
  end
125
125
 
126
126
  def end_range(node)
@@ -145,8 +145,10 @@ module RuboCop
145
145
  next_sibling.if_type? && contains_guard_clause?(next_sibling)
146
146
  end
147
147
 
148
+ # rubocop:disable Metrics/CyclomaticComplexity
148
149
  def last_heredoc_argument(node)
149
150
  n = last_heredoc_argument_node(node)
151
+ n = n.children.first while n.respond_to?(:begin_type?) && n.begin_type?
150
152
 
151
153
  return n if heredoc?(n)
152
154
  return unless n.respond_to?(:arguments)
@@ -158,6 +160,7 @@ module RuboCop
158
160
 
159
161
  last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
160
162
  end
163
+ # rubocop:enable Metrics/CyclomaticComplexity
161
164
 
162
165
  def last_heredoc_argument_node(node)
163
166
  return node unless node.respond_to?(:if_branch)
@@ -76,28 +76,40 @@ module RuboCop
76
76
  # # good
77
77
  # class ErrorA < BaseError; end
78
78
  # class ErrorB < BaseError; end
79
- # class ErrorC < BaseError; end
80
79
  #
81
80
  # # good
82
81
  # class ErrorA < BaseError; end
83
82
  #
84
83
  # class ErrorB < BaseError; end
85
84
  #
86
- # class ErrorC < BaseError; end
85
+ # # good - DefLikeMacros: [memoize]
86
+ # memoize :attribute_a
87
+ # memoize :attribute_b
88
+ #
89
+ # # good
90
+ # memoize :attribute_a
91
+ #
92
+ # memoize :attribute_b
87
93
  #
88
94
  # @example AllowAdjacentOneLineDefs: false
89
95
  #
90
96
  # # bad
91
97
  # class ErrorA < BaseError; end
92
98
  # class ErrorB < BaseError; end
93
- # class ErrorC < BaseError; end
94
99
  #
95
100
  # # good
96
101
  # class ErrorA < BaseError; end
97
102
  #
98
103
  # class ErrorB < BaseError; end
99
104
  #
100
- # class ErrorC < BaseError; end
105
+ # # bad - DefLikeMacros: [memoize]
106
+ # memoize :attribute_a
107
+ # memoize :attribute_b
108
+ #
109
+ # # good
110
+ # memoize :attribute_a
111
+ #
112
+ # memoize :attribute_b
101
113
  #
102
114
  class EmptyLineBetweenDefs < Base
103
115
  include RangeHelp
@@ -158,6 +170,8 @@ module RuboCop
158
170
  def def_location(correction_node)
159
171
  if correction_node.any_block_type?
160
172
  correction_node.source_range.join(correction_node.children.first.source_range)
173
+ elsif correction_node.send_type?
174
+ correction_node.source_range
161
175
  else
162
176
  correction_node.loc.keyword.join(correction_node.loc.name)
163
177
  end
@@ -175,8 +189,14 @@ module RuboCop
175
189
  end
176
190
 
177
191
  def macro_candidate?(node)
178
- node.any_block_type? && node.children.first.macro? &&
179
- empty_line_between_macros.include?(node.children.first.method_name)
192
+ macro_candidate = if node.any_block_type?
193
+ node.send_node
194
+ elsif node.send_type?
195
+ node
196
+ end
197
+ return false unless macro_candidate
198
+
199
+ macro_candidate.macro? && empty_line_between_macros.include?(macro_candidate.method_name)
180
200
  end
181
201
 
182
202
  def method_candidate?(node)
@@ -240,7 +260,9 @@ module RuboCop
240
260
  end
241
261
 
242
262
  def def_start(node)
243
- if node.any_block_type? && node.children.first.send_type?
263
+ node = node.send_node if node.any_block_type?
264
+
265
+ if node.send_type?
244
266
  node.source_range.line
245
267
  else
246
268
  node.loc.keyword.line
@@ -252,11 +274,7 @@ module RuboCop
252
274
  end
253
275
 
254
276
  def end_loc(node)
255
- if node.any_def_type? && node.endless?
256
- node.source_range.end
257
- else
258
- node.loc.end
259
- end
277
+ node.source_range.end
260
278
  end
261
279
 
262
280
  def autocorrect_remove_lines(corrector, newline_pos, count)
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Layout
6
+ # Checks for an empty line after a module inclusion method (`extend`,
7
+ # `include` and `prepend`), or a group of them.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # class Foo
12
+ # include Bar
13
+ # attr_reader :baz
14
+ # end
15
+ #
16
+ # # good
17
+ # class Foo
18
+ # include Bar
19
+ #
20
+ # attr_reader :baz
21
+ # end
22
+ #
23
+ # # also good - multiple module inclusions grouped together
24
+ # class Foo
25
+ # extend Bar
26
+ # include Baz
27
+ # prepend Qux
28
+ # end
29
+ #
30
+ class EmptyLinesAfterModuleInclusion < Base
31
+ include RangeHelp
32
+ extend AutoCorrector
33
+
34
+ MSG = 'Add an empty line after module inclusion.'
35
+
36
+ MODULE_INCLUSION_METHODS = %i[include extend prepend].freeze
37
+
38
+ RESTRICT_ON_SEND = MODULE_INCLUSION_METHODS
39
+
40
+ def on_send(node)
41
+ return if node.receiver || node.arguments.empty?
42
+ return if node.parent&.type?(:send, :any_block)
43
+
44
+ return if next_line_empty_or_enable_directive_comment?(node.last_line)
45
+
46
+ next_line_node = next_line_node(node)
47
+ return unless require_empty_line?(next_line_node)
48
+
49
+ add_offense(node) { |corrector| autocorrect(corrector, node) }
50
+ end
51
+
52
+ private
53
+
54
+ def autocorrect(corrector, node)
55
+ node_range = range_by_whole_lines(node.source_range)
56
+
57
+ next_line = node_range.last_line + 1
58
+ if enable_directive_comment?(next_line)
59
+ node_range = processed_source.comment_at_line(next_line)
60
+ end
61
+
62
+ corrector.insert_after(node_range, "\n")
63
+ end
64
+
65
+ def next_line_empty_or_enable_directive_comment?(line)
66
+ line_empty?(line) || (enable_directive_comment?(line + 1) && line_empty?(line + 1))
67
+ end
68
+
69
+ def enable_directive_comment?(line)
70
+ return false unless (comment = processed_source.comment_at_line(line))
71
+
72
+ DirectiveComment.new(comment).enabled?
73
+ end
74
+
75
+ def line_empty?(line)
76
+ processed_source[line].nil? || processed_source[line].blank?
77
+ end
78
+
79
+ def require_empty_line?(node)
80
+ return false unless node
81
+
82
+ !allowed_method?(node)
83
+ end
84
+
85
+ def allowed_method?(node)
86
+ node = node.body if node.respond_to?(:modifier_form?) && node.modifier_form?
87
+
88
+ return false unless node.send_type?
89
+
90
+ MODULE_INCLUSION_METHODS.include?(node.method_name)
91
+ end
92
+
93
+ def next_line_node(node)
94
+ return if node.parent.if_type?
95
+
96
+ node.right_sibling
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -138,7 +138,7 @@ module RuboCop
138
138
  end
139
139
 
140
140
  def previous_line_ignoring_comments(processed_source, send_line)
141
- processed_source[0..send_line - 2].reverse.find { |line| !comment_line?(line) }
141
+ processed_source[0..(send_line - 2)].reverse.find { |line| !comment_line?(line) }
142
142
  end
143
143
 
144
144
  def previous_line_empty?(send_line)
@@ -62,40 +62,19 @@ module RuboCop
62
62
  node.receiver && node.receiver.loc.last_line != node.loc.selector&.line
63
63
  end
64
64
 
65
- def empty_lines(node)
66
- lines = processed_lines(node)
67
- lines.select! { |code, _| code.empty? }
68
- lines.map { |_, line| line }
69
- end
70
-
71
- def extra_lines(node)
72
- empty_lines(node).each do |line|
73
- range = source_range(processed_source.buffer, line, 0)
74
- yield(range)
75
- end
76
- end
77
-
78
- def processed_lines(node)
79
- line_numbers(node).each_with_object([]) do |num, array|
80
- array << [processed_source.lines[num - 1], num]
65
+ def extra_lines(node, &block)
66
+ node.arguments.each do |arg|
67
+ empty_range_for_starting_point(arg.source_range.begin, &block)
81
68
  end
82
- end
83
69
 
84
- def line_numbers(node)
85
- inner_lines = []
86
- line_nums = node.arguments.each_with_object([]) do |arg_node, lines|
87
- lines << outer_lines(arg_node)
88
- inner_lines << inner_lines(arg_node) if arg_node.multiline?
89
- end
90
- line_nums.flatten.uniq - inner_lines.flatten - outer_lines(node)
70
+ empty_range_for_starting_point(node.loc.end.begin, &block) if node.loc.end
91
71
  end
92
72
 
93
- def inner_lines(node)
94
- [node.first_line + 1, node.last_line - 1]
95
- end
73
+ def empty_range_for_starting_point(start)
74
+ range = range_with_surrounding_space(start, whitespace: true, side: :left)
75
+ return unless range.last_line - range.first_line > 1
96
76
 
97
- def outer_lines(node)
98
- [node.first_line - 1, node.last_line + 1]
77
+ yield range.source_buffer.line_range(range.last_line - 1).adjust(end_pos: 1)
99
78
  end
100
79
  end
101
80
  end
@@ -71,7 +71,7 @@ module RuboCop
71
71
  KIND = 'class'
72
72
 
73
73
  def on_class(node)
74
- first_line = node.parent_class.first_line if node.parent_class
74
+ first_line = node.parent_class.last_line if node.parent_class
75
75
 
76
76
  check(node, node.body, adjusted_first_line: first_line)
77
77
  end
@@ -128,6 +128,10 @@ module RuboCop
128
128
  # assignment, we let rhs be the receiver of those method calls before
129
129
  # we check if it's an if/unless/while/until.
130
130
  return unless (rhs = first_part_of_call_chain(rhs))
131
+
132
+ # If `rhs` is a `begin` node, find the first non-`begin` child.
133
+ rhs = rhs.child_nodes.first while rhs.begin_type?
134
+
131
135
  return unless rhs.conditional?
132
136
  return if rhs.if_type? && rhs.ternary?
133
137
 
@@ -193,7 +193,6 @@ module RuboCop
193
193
  SEPARATOR_ALIGNMENT_STYLES = %w[EnforcedColonStyle EnforcedHashRocketStyle].freeze
194
194
 
195
195
  def on_send(node)
196
- return if double_splat?(node)
197
196
  return unless node.arguments?
198
197
 
199
198
  last_argument = node.last_argument
@@ -233,6 +232,8 @@ module RuboCop
233
232
  end
234
233
 
235
234
  def argument_before_hash(hash_node)
235
+ return hash_node.children.first.children.first if hash_node.children.first.kwsplat_type?
236
+
236
237
  hash_node.left_sibling.respond_to?(:loc) ? hash_node.left_sibling : nil
237
238
  end
238
239
 
@@ -241,10 +242,6 @@ module RuboCop
241
242
  self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
242
243
  end
243
244
 
244
- def double_splat?(node)
245
- node.children.last.is_a?(Symbol)
246
- end
247
-
248
245
  def check_pairs(node)
249
246
  first_pair = node.pairs.first
250
247
  reset!
@@ -168,7 +168,7 @@ module RuboCop
168
168
 
169
169
  def subsequent_closing_parentheses_in_same_line?(outermost_send)
170
170
  last_arg_of_outer_send = outermost_send.last_argument
171
- return false unless last_arg_of_outer_send&.loc.respond_to?(:end) &&
171
+ return false unless last_arg_of_outer_send&.loc?(:end) &&
172
172
  (end_of_last_arg_of_outer_send = last_arg_of_outer_send.loc.end)
173
173
 
174
174
  end_of_outer_send = outermost_send.loc.end
@@ -230,7 +230,7 @@ module RuboCop
230
230
 
231
231
  def find_most_bottom_of_heredoc_end(arguments)
232
232
  arguments.filter_map do |argument|
233
- argument.loc.heredoc_end.end_pos if argument.loc.respond_to?(:heredoc_end)
233
+ argument.loc.heredoc_end.end_pos if argument.loc?(:heredoc_end)
234
234
  end.max
235
235
  end
236
236
 
@@ -89,6 +89,7 @@ module RuboCop
89
89
  end
90
90
 
91
91
  def line_too_long?(node)
92
+ return false unless max_line_length
92
93
  return false if unlimited_heredoc_length?
93
94
 
94
95
  body = heredoc_body(node)
@@ -108,10 +109,6 @@ module RuboCop
108
109
  config.for_cop('Layout/LineLength')['AllowHeredoc']
109
110
  end
110
111
 
111
- def max_line_length
112
- config.for_cop('Layout/LineLength')['Max']
113
- end
114
-
115
112
  def adjust_squiggly(corrector, node)
116
113
  corrector.replace(node.loc.heredoc_body, indented_body(node))
117
114
  corrector.replace(node.loc.heredoc_end, indented_end(node))
@@ -99,7 +99,7 @@ module RuboCop
99
99
 
100
100
  if str.heredoc?
101
101
  ranges << loc.heredoc_body
102
- elsif loc.respond_to?(:begin) && loc.begin
102
+ elsif str.loc?(:begin)
103
103
  ranges << loc.expression
104
104
  end
105
105
  end
@@ -83,7 +83,10 @@ module RuboCop
83
83
 
84
84
  return unless begins_its_line?(end_loc)
85
85
 
86
- check_indentation(end_loc, node.body)
86
+ # For blocks where the dot is on a new line, use the dot position as the base.
87
+ # Otherwise, use the end keyword position as the base.
88
+ base_loc = dot_on_new_line?(node) ? node.send_node.loc.dot : end_loc
89
+ check_indentation(base_loc, node.body)
87
90
 
88
91
  return unless indented_internal_methods_style?
89
92
 
@@ -383,6 +386,14 @@ module RuboCop
383
386
 
384
387
  leftmost_modifier_of(node.parent)
385
388
  end
389
+
390
+ def dot_on_new_line?(node)
391
+ send_node = node.send_node
392
+ return false unless send_node.loc?(:dot)
393
+
394
+ receiver = send_node.receiver
395
+ receiver && receiver.last_line < send_node.loc.dot.line
396
+ end
386
397
  end
387
398
  end
388
399
  end
@@ -101,7 +101,7 @@ module RuboCop
101
101
  ranges << loc.expression
102
102
  elsif literal.heredoc?
103
103
  ranges << loc.heredoc_body
104
- elsif (loc.respond_to?(:begin) && loc.begin) || ignored_parent?(literal)
104
+ elsif literal.loc?(:begin) || ignored_parent?(literal)
105
105
  ranges << loc.expression
106
106
  end
107
107
  end