rubocop 1.59.0 → 1.65.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 (255) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +3 -4
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +93 -17
  7. data/lib/rubocop/cached_data.rb +11 -3
  8. data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
  9. data/lib/rubocop/cli/command/lsp.rb +2 -2
  10. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  11. data/lib/rubocop/cli.rb +10 -1
  12. data/lib/rubocop/config.rb +36 -12
  13. data/lib/rubocop/config_finder.rb +12 -2
  14. data/lib/rubocop/config_loader.rb +1 -2
  15. data/lib/rubocop/config_loader_resolver.rb +9 -3
  16. data/lib/rubocop/config_obsoletion.rb +1 -1
  17. data/lib/rubocop/config_validator.rb +14 -7
  18. data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
  19. data/lib/rubocop/cop/base.rb +63 -16
  20. data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
  21. data/lib/rubocop/cop/cop.rb +22 -4
  22. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  23. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  24. data/lib/rubocop/cop/documentation.rb +16 -6
  25. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  26. data/lib/rubocop/cop/force.rb +12 -0
  27. data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
  28. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  29. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  30. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  31. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  32. data/lib/rubocop/cop/internal_affairs/example_description.rb +6 -5
  33. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  34. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +122 -28
  35. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  36. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  37. data/lib/rubocop/cop/layout/assignment_indentation.rb +3 -2
  38. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  39. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  40. data/lib/rubocop/cop/layout/condition_position.rb +0 -4
  41. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  42. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  43. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
  44. data/lib/rubocop/cop/layout/end_alignment.rb +8 -2
  45. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
  46. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -1
  47. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
  48. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  49. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
  50. data/lib/rubocop/cop/layout/line_length.rb +20 -20
  51. data/lib/rubocop/cop/layout/redundant_line_break.rb +14 -2
  52. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -0
  53. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  54. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  55. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  56. data/lib/rubocop/cop/legacy/corrector.rb +12 -2
  57. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +0 -2
  58. data/lib/rubocop/cop/lint/ambiguous_operator.rb +0 -2
  59. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +0 -2
  60. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
  61. data/lib/rubocop/cop/lint/boolean_symbol.rb +0 -2
  62. data/lib/rubocop/cop/lint/circular_argument_reference.rb +0 -13
  63. data/lib/rubocop/cop/lint/debugger.rb +27 -6
  64. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  65. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +0 -10
  66. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -5
  67. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +0 -4
  68. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -10
  69. data/lib/rubocop/cop/lint/each_with_object_argument.rb +0 -4
  70. data/lib/rubocop/cop/lint/else_layout.rb +0 -2
  71. data/lib/rubocop/cop/lint/empty_conditional_body.rb +2 -2
  72. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -11
  73. data/lib/rubocop/cop/lint/empty_interpolation.rb +0 -4
  74. data/lib/rubocop/cop/lint/empty_when.rb +1 -3
  75. data/lib/rubocop/cop/lint/ensure_return.rb +1 -6
  76. data/lib/rubocop/cop/lint/erb_new_arguments.rb +21 -14
  77. data/lib/rubocop/cop/lint/float_comparison.rb +3 -1
  78. data/lib/rubocop/cop/lint/float_out_of_range.rb +0 -4
  79. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +0 -10
  80. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +15 -12
  81. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +0 -7
  82. data/lib/rubocop/cop/lint/interpolation_check.rb +0 -4
  83. data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
  84. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +13 -6
  85. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +0 -4
  86. data/lib/rubocop/cop/lint/loop.rb +6 -12
  87. data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
  88. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -7
  89. data/lib/rubocop/cop/lint/next_without_accumulator.rb +0 -4
  90. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +0 -5
  91. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  92. data/lib/rubocop/cop/lint/percent_string_array.rb +0 -4
  93. data/lib/rubocop/cop/lint/percent_symbol_array.rb +0 -4
  94. data/lib/rubocop/cop/lint/rand_one.rb +0 -4
  95. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +3 -1
  96. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +14 -9
  97. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  98. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +0 -4
  99. data/lib/rubocop/cop/lint/redundant_with_index.rb +4 -0
  100. data/lib/rubocop/cop/lint/require_parentheses.rb +0 -4
  101. data/lib/rubocop/cop/lint/rescue_exception.rb +0 -4
  102. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  103. data/lib/rubocop/cop/lint/return_in_void_context.rb +0 -2
  104. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +0 -4
  105. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  106. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  107. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +6 -10
  108. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  109. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -3
  110. data/lib/rubocop/cop/lint/unified_integer.rb +0 -4
  111. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  112. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -7
  113. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  114. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -5
  115. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +0 -4
  116. data/lib/rubocop/cop/lint/useless_setter_call.rb +0 -4
  117. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  118. data/lib/rubocop/cop/lint/void.rb +11 -1
  119. data/lib/rubocop/cop/metrics/block_nesting.rb +19 -7
  120. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
  121. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  122. data/lib/rubocop/cop/mixin/allowed_methods.rb +7 -1
  123. data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
  124. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  125. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  126. data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
  127. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +9 -2
  128. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  129. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  130. data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
  131. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  132. data/lib/rubocop/cop/naming/block_forwarding.rb +32 -5
  133. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  134. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
  135. data/lib/rubocop/cop/naming/predicate_name.rb +54 -28
  136. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +10 -1
  137. data/lib/rubocop/cop/registry.rb +1 -1
  138. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  139. data/lib/rubocop/cop/security/open.rb +2 -2
  140. data/lib/rubocop/cop/style/access_modifier_declarations.rb +50 -0
  141. data/lib/rubocop/cop/style/alias.rb +1 -0
  142. data/lib/rubocop/cop/style/arguments_forwarding.rb +89 -17
  143. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  144. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  145. data/lib/rubocop/cop/style/collection_compact.rb +14 -5
  146. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  147. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -7
  148. data/lib/rubocop/cop/style/copyright.rb +31 -21
  149. data/lib/rubocop/cop/style/def_with_parentheses.rb +0 -2
  150. data/lib/rubocop/cop/style/documentation.rb +24 -24
  151. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  152. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -8
  153. data/lib/rubocop/cop/style/eval_with_location.rb +15 -23
  154. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  155. data/lib/rubocop/cop/style/file_read.rb +2 -5
  156. data/lib/rubocop/cop/style/file_write.rb +2 -5
  157. data/lib/rubocop/cop/style/for.rb +2 -0
  158. data/lib/rubocop/cop/style/format_string.rb +9 -9
  159. data/lib/rubocop/cop/style/global_std_stream.rb +7 -1
  160. data/lib/rubocop/cop/style/hash_each_methods.rb +29 -8
  161. data/lib/rubocop/cop/style/hash_except.rb +8 -5
  162. data/lib/rubocop/cop/style/hash_syntax.rb +24 -2
  163. data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
  164. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -4
  165. data/lib/rubocop/cop/style/inverse_methods.rb +8 -8
  166. data/lib/rubocop/cop/style/invertible_unless_condition.rb +46 -4
  167. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +81 -50
  168. data/lib/rubocop/cop/style/map_into_array.rb +175 -0
  169. data/lib/rubocop/cop/style/map_to_hash.rb +10 -6
  170. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  171. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +18 -5
  172. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  173. data/lib/rubocop/cop/style/missing_else.rb +0 -4
  174. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  175. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +5 -3
  176. data/lib/rubocop/cop/style/multiline_when_then.rb +0 -4
  177. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  178. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  179. data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
  180. data/lib/rubocop/cop/style/object_then.rb +5 -3
  181. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  182. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  183. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  184. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  185. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  186. data/lib/rubocop/cop/style/redundant_argument.rb +25 -2
  187. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  188. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  189. data/lib/rubocop/cop/style/redundant_condition.rb +0 -1
  190. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +5 -4
  191. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  192. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
  193. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  194. data/lib/rubocop/cop/style/redundant_line_continuation.rb +17 -2
  195. data/lib/rubocop/cop/style/redundant_parentheses.rb +18 -2
  196. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  197. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -24
  198. data/lib/rubocop/cop/style/redundant_return.rb +6 -0
  199. data/lib/rubocop/cop/style/require_order.rb +1 -1
  200. data/lib/rubocop/cop/style/sample.rb +1 -3
  201. data/lib/rubocop/cop/style/send.rb +4 -4
  202. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +104 -0
  203. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  204. data/lib/rubocop/cop/style/sole_nested_conditional.rb +21 -2
  205. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  206. data/lib/rubocop/cop/style/super_arguments.rb +174 -0
  207. data/lib/rubocop/cop/style/symbol_proc.rb +75 -5
  208. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  209. data/lib/rubocop/cop/style/while_until_do.rb +0 -2
  210. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  211. data/lib/rubocop/cop/style/zero_length_predicate.rb +32 -24
  212. data/lib/rubocop/cop/team.rb +13 -0
  213. data/lib/rubocop/cop/util.rb +7 -1
  214. data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
  215. data/lib/rubocop/cop/variable_force.rb +13 -1
  216. data/lib/rubocop/cops_documentation_generator.rb +16 -4
  217. data/lib/rubocop/core_ext/string.rb +2 -6
  218. data/lib/rubocop/directive_comment.rb +10 -8
  219. data/lib/rubocop/ext/regexp_node.rb +18 -35
  220. data/lib/rubocop/ext/regexp_parser.rb +4 -21
  221. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  222. data/lib/rubocop/formatter/disabled_config_formatter.rb +23 -8
  223. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  224. data/lib/rubocop/formatter/html_formatter.rb +32 -10
  225. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  226. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  227. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  228. data/lib/rubocop/formatter.rb +1 -1
  229. data/lib/rubocop/lockfile.rb +56 -7
  230. data/lib/rubocop/lsp/logger.rb +1 -1
  231. data/lib/rubocop/lsp/routes.rb +12 -15
  232. data/lib/rubocop/lsp/runtime.rb +1 -1
  233. data/lib/rubocop/lsp/server.rb +7 -2
  234. data/lib/rubocop/lsp/severity.rb +1 -1
  235. data/lib/rubocop/lsp.rb +36 -0
  236. data/lib/rubocop/magic_comment.rb +1 -1
  237. data/lib/rubocop/options.rb +17 -12
  238. data/lib/rubocop/path_util.rb +6 -2
  239. data/lib/rubocop/rake_task.rb +1 -1
  240. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  241. data/lib/rubocop/rspec/expect_offense.rb +16 -8
  242. data/lib/rubocop/rspec/shared_contexts.rb +73 -16
  243. data/lib/rubocop/rspec/support.rb +3 -0
  244. data/lib/rubocop/runner.rb +14 -3
  245. data/lib/rubocop/server/cache.rb +11 -2
  246. data/lib/rubocop/server/client_command/exec.rb +2 -3
  247. data/lib/rubocop/server/client_command/start.rb +1 -1
  248. data/lib/rubocop/server/core.rb +4 -0
  249. data/lib/rubocop/server/server_command/exec.rb +0 -1
  250. data/lib/rubocop/target_finder.rb +84 -78
  251. data/lib/rubocop/target_ruby.rb +82 -80
  252. data/lib/rubocop/version.rb +19 -4
  253. data/lib/rubocop.rb +9 -0
  254. metadata +18 -11
  255. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -300,7 +300,7 @@ module RuboCop
300
300
  unless given_badge.match?(real_badge)
301
301
  path = PathUtil.smart_path(source_path)
302
302
  warn "#{path}: #{given_badge} has the wrong namespace - " \
303
- "should be #{real_badge.department}"
303
+ "replace it with #{given_badge.with_department(real_badge.department)}"
304
304
  end
305
305
 
306
306
  real_badge.to_s
@@ -30,8 +30,8 @@ module RuboCop
30
30
  class CompoundHash < Base
31
31
  COMBINATOR_IN_HASH_MSG = 'Use `[...].hash` instead of combining hash values manually.'
32
32
  MONUPLE_HASH_MSG =
33
- 'Delegate hash directly without wrapping in an array when only using a single value'
34
- REDUNDANT_HASH_MSG = 'Calling .hash on elements of a hashed array is redundant'
33
+ 'Delegate hash directly without wrapping in an array when only using a single value.'
34
+ REDUNDANT_HASH_MSG = 'Calling .hash on elements of a hashed array is redundant.'
35
35
 
36
36
  # @!method hash_method_definition?(node)
37
37
  def_node_matcher :hash_method_definition?, <<~PATTERN
@@ -23,6 +23,7 @@ module RuboCop
23
23
  # # bad
24
24
  # open(something)
25
25
  # open("| #{something}")
26
+ # open("| foo")
26
27
  # URI.open(something)
27
28
  #
28
29
  # # good
@@ -32,7 +33,6 @@ module RuboCop
32
33
  #
33
34
  # # good (literal strings)
34
35
  # open("foo.text")
35
- # open("| foo")
36
36
  # URI.open("http://example.com")
37
37
  class Open < Base
38
38
  MSG = 'The use of `%<receiver>sopen` is a serious security risk.'
@@ -40,7 +40,7 @@ module RuboCop
40
40
 
41
41
  # @!method open?(node)
42
42
  def_node_matcher :open?, <<~PATTERN
43
- (send ${nil? (const {nil? cbase} :URI)} :open $!str ...)
43
+ (send ${nil? (const {nil? cbase} :URI)} :open $_ ...)
44
44
  PATTERN
45
45
 
46
46
  def on_send(node)
@@ -8,6 +8,17 @@ module RuboCop
8
8
  # EnforcedStyle config covers only method definitions.
9
9
  # Applications of visibility methods to symbols can be controlled
10
10
  # using AllowModifiersOnSymbols config.
11
+ # Also, the visibility of `attr*` methods can be controlled using
12
+ # AllowModifiersOnAttrs config.
13
+ #
14
+ # In Ruby 3.0, `attr*` methods now return an array of defined method names
15
+ # as symbols. So we can write the modifier and `attr*` in inline style.
16
+ # AllowModifiersOnAttrs config allows `attr*` methods to be written in
17
+ # inline style without modifying applications that have been maintained
18
+ # for a long time in group style. Furthermore, developers who are not very
19
+ # familiar with Ruby may know that the modifier applies to `def`, but they
20
+ # may not know that it also applies to `attr*` methods. It would be easier
21
+ # to understand if we could write `attr*` methods in inline style.
11
22
  #
12
23
  # @safety
13
24
  # Autocorrection is not safe, because the visibility of dynamically
@@ -67,6 +78,34 @@ module RuboCop
67
78
  # private :bar, :baz
68
79
  #
69
80
  # end
81
+ #
82
+ # @example AllowModifiersOnAttrs: true (default)
83
+ # # good
84
+ # class Foo
85
+ #
86
+ # public attr_reader :bar
87
+ # protected attr_writer :baz
88
+ # private attr_accessor :qux
89
+ # private attr :quux
90
+ #
91
+ # def public_method; end
92
+ #
93
+ # private
94
+ #
95
+ # def private_method; end
96
+ #
97
+ # end
98
+ #
99
+ # @example AllowModifiersOnAttrs: false
100
+ # # bad
101
+ # class Foo
102
+ #
103
+ # public attr_reader :bar
104
+ # protected attr_writer :baz
105
+ # private attr_accessor :qux
106
+ # private attr :quux
107
+ #
108
+ # end
70
109
  class AccessModifierDeclarations < Base
71
110
  extend AutoCorrector
72
111
 
@@ -92,10 +131,17 @@ module RuboCop
92
131
  (send nil? {:private :protected :public :module_function} (sym _))
93
132
  PATTERN
94
133
 
134
+ # @!method access_modifier_with_attr?(node)
135
+ def_node_matcher :access_modifier_with_attr?, <<~PATTERN
136
+ (send nil? {:private :protected :public :module_function}
137
+ (send nil? {:attr :attr_reader :attr_writer :attr_accessor} _))
138
+ PATTERN
139
+
95
140
  def on_send(node)
96
141
  return unless node.access_modifier?
97
142
  return if ALLOWED_NODE_TYPES.include?(node.parent&.type)
98
143
  return if allow_modifiers_on_symbols?(node)
144
+ return if allow_modifiers_on_attrs?(node)
99
145
 
100
146
  if offense?(node)
101
147
  add_offense(node.loc.selector) do |corrector|
@@ -128,6 +174,10 @@ module RuboCop
128
174
  cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
129
175
  end
130
176
 
177
+ def allow_modifiers_on_attrs?(node)
178
+ cop_config['AllowModifiersOnAttrs'] && access_modifier_with_attr?(node)
179
+ end
180
+
131
181
  def offense?(node)
132
182
  (group_style? && access_modifier_is_inlined?(node) &&
133
183
  !right_siblings_same_inline_method?(node)) ||
@@ -41,6 +41,7 @@ module RuboCop
41
41
  def on_send(node)
42
42
  return unless node.command?(:alias_method)
43
43
  return unless style == :prefer_alias && alias_keyword_possible?(node)
44
+ return unless node.arguments.count == 2
44
45
 
45
46
  msg = format(MSG_ALIAS_METHOD, current: lexical_scope_type(node))
46
47
  add_offense(node.loc.selector, message: msg) do |corrector|
@@ -8,6 +8,12 @@ module RuboCop
8
8
  # This cop identifies places where `do_something(*args, &block)`
9
9
  # can be replaced by `do_something(...)`.
10
10
  #
11
+ # In Ruby 3.1, anonymous block forwarding has been added.
12
+ #
13
+ # This cop identifies places where `do_something(&block)` can be replaced
14
+ # by `do_something(&)`; if desired, this functionality can be disabled
15
+ # by setting `UseAnonymousForwarding: false`.
16
+ #
11
17
  # In Ruby 3.2, anonymous args/kwargs forwarding has been added.
12
18
  #
13
19
  # This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
@@ -23,6 +29,8 @@ module RuboCop
23
29
  #
24
30
  # Names not on this list are likely to be meaningful and are allowed by default.
25
31
  #
32
+ # This cop handles not only method forwarding but also forwarding to `super`.
33
+ #
26
34
  # @example
27
35
  # # bad
28
36
  # def foo(*args, &block)
@@ -41,22 +49,25 @@ module RuboCop
41
49
  #
42
50
  # @example UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2)
43
51
  # # bad
44
- # def foo(*args, **kwargs)
52
+ # def foo(*args, **kwargs, &block)
45
53
  # args_only(*args)
46
54
  # kwargs_only(**kwargs)
55
+ # block_only(&block)
47
56
  # end
48
57
  #
49
58
  # # good
50
- # def foo(*, **)
59
+ # def foo(*, **, &)
51
60
  # args_only(*)
52
61
  # kwargs_only(**)
62
+ # block_only(&)
53
63
  # end
54
64
  #
55
65
  # @example UseAnonymousForwarding: false (only relevant for Ruby >= 3.2)
56
66
  # # good
57
- # def foo(*args, **kwargs)
67
+ # def foo(*args, **kwargs, &block)
58
68
  # args_only(*args)
59
69
  # kwargs_only(**kwargs)
70
+ # block_only(&block)
60
71
  # end
61
72
  #
62
73
  # @example AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2)
@@ -104,7 +115,7 @@ module RuboCop
104
115
  # end
105
116
  #
106
117
  # @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
107
- # # bad
118
+ # # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`.
108
119
  # def foo(&block)
109
120
  # bar(&block)
110
121
  # end
@@ -126,6 +137,7 @@ module RuboCop
126
137
  FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
127
138
  ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
128
139
  KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
140
+ BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
129
141
 
130
142
  def self.autocorrect_incompatible_with
131
143
  [Naming::BlockForwarding]
@@ -136,7 +148,7 @@ module RuboCop
136
148
 
137
149
  restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
138
150
  forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
139
- send_nodes = node.each_descendant(:send).to_a
151
+ send_nodes = node.each_descendant(:send, :csend, :super, :yield).to_a
140
152
 
141
153
  send_classifications = classify_send_nodes(
142
154
  node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
@@ -171,32 +183,59 @@ module RuboCop
171
183
  send_classifications.all? { |_, c, _, _| c == :all }
172
184
  end
173
185
 
186
+ # rubocop:disable Metrics/MethodLength
174
187
  def add_forward_all_offenses(node, send_classifications, forwardable_args)
175
- send_classifications.each do |send_node, _c, forward_rest, _forward_kwrest|
176
- register_forward_all_offense(send_node, send_node, forward_rest)
188
+ _rest_arg, _kwrest_arg, block_arg = *forwardable_args
189
+ registered_block_arg_offense = false
190
+
191
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
192
+ if !forward_rest && !forward_kwrest
193
+ # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
194
+ # in Ruby 3.3.0.
195
+ if outside_block?(forward_block_arg)
196
+ register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
197
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
198
+ end
199
+ registered_block_arg_offense = true
200
+ break
201
+ else
202
+ register_forward_all_offense(send_node, send_node, forward_rest)
203
+ end
177
204
  end
178
205
 
206
+ return if registered_block_arg_offense
207
+
179
208
  rest_arg, _kwrest_arg, _block_arg = *forwardable_args
180
209
  register_forward_all_offense(node, node.arguments, rest_arg)
181
210
  end
211
+ # rubocop:enable Metrics/MethodLength
182
212
 
213
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
183
214
  def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
184
215
  return unless use_anonymous_forwarding?
185
216
 
186
- rest_arg, kwrest_arg, _block_arg = *forwardable_args
217
+ rest_arg, kwrest_arg, block_arg = *forwardable_args
187
218
 
188
- send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
189
- if forward_rest
219
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
220
+ if outside_block?(forward_rest)
190
221
  register_forward_args_offense(def_node.arguments, rest_arg)
191
222
  register_forward_args_offense(send_node, forward_rest)
192
223
  end
193
224
 
194
- if forward_kwrest
225
+ if outside_block?(forward_kwrest)
195
226
  register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
196
227
  register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
197
228
  end
229
+
230
+ # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
231
+ # in Ruby 3.3.0.
232
+ if outside_block?(forward_block_arg)
233
+ register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
234
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
235
+ end
198
236
  end
199
237
  end
238
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
200
239
 
201
240
  def non_splat_or_block_pass_lvar_references(body)
202
241
  body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
@@ -225,10 +264,7 @@ module RuboCop
225
264
 
226
265
  def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
227
266
  classifier = SendNodeClassifier.new(
228
- def_node,
229
- send_node,
230
- referenced_lvars,
231
- forwardable_args,
267
+ def_node, send_node, referenced_lvars, forwardable_args,
232
268
  target_ruby_version: target_ruby_version,
233
269
  allow_only_rest_arguments: allow_only_rest_arguments?
234
270
  )
@@ -237,7 +273,12 @@ module RuboCop
237
273
 
238
274
  return unless classification
239
275
 
240
- [classification, classifier.forwarded_rest_arg, classifier.forwarded_kwrest_arg]
276
+ [
277
+ classification,
278
+ classifier.forwarded_rest_arg,
279
+ classifier.forwarded_kwrest_arg,
280
+ classifier.forwarded_block_arg
281
+ ]
241
282
  end
242
283
 
243
284
  def redundant_named_arg(arg, config_name, keyword)
@@ -250,6 +291,12 @@ module RuboCop
250
291
  redundant_arg_names.include?(arg.source) ? arg : nil
251
292
  end
252
293
 
294
+ def outside_block?(node)
295
+ return false unless node
296
+
297
+ node.each_ancestor(:block, :numblock).none?
298
+ end
299
+
253
300
  def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
254
301
  add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
255
302
  add_parens_if_missing(def_arguments_or_send, corrector)
@@ -266,6 +313,17 @@ module RuboCop
266
313
  end
267
314
  end
268
315
 
316
+ def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
317
+ return if target_ruby_version <= 3.0 ||
318
+ block_arg.nil? || block_arg.source == '&' || explicit_block_name?
319
+
320
+ add_offense(block_arg, message: BLOCK_MSG) do |corrector|
321
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
322
+
323
+ corrector.replace(block_arg, '&')
324
+ end
325
+ end
326
+
269
327
  def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
270
328
  arg_range = arguments_range(def_or_send, rest_or_splat)
271
329
 
@@ -340,7 +398,7 @@ module RuboCop
340
398
  end
341
399
 
342
400
  def classification
343
- return nil unless forwarded_rest_arg || forwarded_kwrest_arg
401
+ return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
344
402
 
345
403
  if can_forward_all?
346
404
  :all
@@ -424,9 +482,23 @@ module RuboCop
424
482
  def no_additional_args?
425
483
  forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
426
484
 
485
+ return false if missing_rest_arg_or_kwrest_arg?
486
+
427
487
  @def_node.arguments.size == forwardable_count &&
428
488
  @send_node.arguments.size == forwardable_count
429
489
  end
490
+
491
+ def missing_rest_arg_or_kwrest_arg?
492
+ (@rest_arg_name && !forwarded_rest_arg) ||
493
+ (@kwrest_arg_name && !forwarded_kwrest_arg)
494
+ end
495
+ end
496
+
497
+ def explicit_block_name?
498
+ block_forwarding_config = config.for_cop('Naming/BlockForwarding')
499
+ return false unless block_forwarding_config['Enabled']
500
+
501
+ block_forwarding_config['EnforcedStyle'] == 'explicit'
430
502
  end
431
503
  end
432
504
  end
@@ -230,7 +230,7 @@ module RuboCop
230
230
 
231
231
  def branch_conditions(node)
232
232
  conditions = []
233
- while node&.if_type?
233
+ while node&.if_type? && !node.ternary?
234
234
  conditions << node.condition
235
235
  node = node.else_branch
236
236
  end
@@ -54,9 +54,9 @@ module RuboCop
54
54
  end
55
55
 
56
56
  def on_send(node)
57
- add_offense(
58
- node.first_argument, message: format(MSG, class_var: node.first_argument.source)
59
- )
57
+ return unless (first_argument = node.first_argument)
58
+
59
+ add_offense(first_argument, message: format(MSG, class_var: first_argument.source))
60
60
  end
61
61
  end
62
62
  end
@@ -19,17 +19,19 @@ module RuboCop
19
19
  # @example
20
20
  # # bad
21
21
  # array.reject(&:nil?)
22
- # array.delete_if(&:nil?)
23
22
  # array.reject { |e| e.nil? }
24
- # array.delete_if { |e| e.nil? }
25
23
  # array.select { |e| !e.nil? }
24
+ # array.grep_v(nil)
25
+ # array.grep_v(NilClass)
26
26
  #
27
27
  # # good
28
28
  # array.compact
29
29
  #
30
30
  # # bad
31
31
  # hash.reject!(&:nil?)
32
+ # array.delete_if(&:nil?)
32
33
  # hash.reject! { |k, v| v.nil? }
34
+ # array.delete_if { |e| e.nil? }
33
35
  # hash.select! { |k, v| !v.nil? }
34
36
  #
35
37
  # # good
@@ -46,7 +48,7 @@ module RuboCop
46
48
  extend TargetRubyVersion
47
49
 
48
50
  MSG = 'Use `%<good>s` instead of `%<bad>s`.'
49
- RESTRICT_ON_SEND = %i[reject delete_if reject! select select!].freeze
51
+ RESTRICT_ON_SEND = %i[reject delete_if reject! select select! grep_v].freeze
50
52
  TO_ENUM_METHODS = %i[to_enum lazy].freeze
51
53
 
52
54
  minimum_target_ruby_version 2.4
@@ -79,6 +81,11 @@ module RuboCop
79
81
  $(lvar _) :nil?) :!))
80
82
  PATTERN
81
83
 
84
+ # @!method grep_v_with_nil?(node)
85
+ def_node_matcher :grep_v_with_nil?, <<~PATTERN
86
+ (send _ :grep_v {(nil) (const {nil? cbase} :NilClass)})
87
+ PATTERN
88
+
82
89
  def on_send(node)
83
90
  return unless (range = offense_range(node))
84
91
  return if allowed_receiver?(node.receiver)
@@ -95,8 +102,9 @@ module RuboCop
95
102
 
96
103
  private
97
104
 
105
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
98
106
  def offense_range(node)
99
- if reject_method_with_block_pass?(node)
107
+ if reject_method_with_block_pass?(node) || grep_v_with_nil?(node)
100
108
  range(node, node)
101
109
  else
102
110
  block_node = node.parent
@@ -110,6 +118,7 @@ module RuboCop
110
118
  range(node, block_node)
111
119
  end
112
120
  end
121
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
113
122
 
114
123
  def to_enum_method?(node)
115
124
  return false unless node.receiver.send_type?
@@ -118,7 +127,7 @@ module RuboCop
118
127
  end
119
128
 
120
129
  def good_method_name(node)
121
- if node.bang_method?
130
+ if node.bang_method? || node.method?(:delete_if)
122
131
  'compact!'
123
132
  else
124
133
  'compact'
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../../directive_comment'
4
+
3
5
  module RuboCop
4
6
  module Cop
5
7
  module Style
@@ -49,8 +51,9 @@ module RuboCop
49
51
  KEYWORDS = %w[begin class def end module].freeze
50
52
  KEYWORD_REGEXES = KEYWORDS.map { |w| /^\s*#{w}\s/ }.freeze
51
53
 
52
- ALLOWED_COMMENTS = %w[:nodoc: :yields: rubocop:disable rubocop:todo].freeze
53
- ALLOWED_COMMENT_REGEXES = ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ }.freeze
54
+ ALLOWED_COMMENTS = %w[:nodoc: :yields:].freeze
55
+ ALLOWED_COMMENT_REGEXES = (ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ } +
56
+ [DirectiveComment::DIRECTIVE_COMMENT_REGEXP]).freeze
54
57
 
55
58
  REGEXP = /(?<keyword>\S+).*#/.freeze
56
59
 
@@ -115,8 +115,8 @@ module RuboCop
115
115
  end
116
116
 
117
117
  # Check for `if` and `case` statements where each branch is used for
118
- # assignment to the same variable when using the return of the
119
- # condition can be used instead.
118
+ # both the assignment and comparison of the same variable
119
+ # when using the return of the condition can be used instead.
120
120
  #
121
121
  # @example EnforcedStyle: assign_to_condition (default)
122
122
  # # bad
@@ -214,7 +214,7 @@ module RuboCop
214
214
  extend AutoCorrector
215
215
 
216
216
  MSG = 'Use the return of the conditional for variable assignment and comparison.'
217
- ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals'
217
+ ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals.'
218
218
  VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
219
219
  ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
220
220
  LINE_LENGTH = 'Layout/LineLength'
@@ -233,7 +233,7 @@ module RuboCop
233
233
  PATTERN
234
234
 
235
235
  ASSIGNMENT_TYPES.each do |type|
236
- define_method "on_#{type}" do |node|
236
+ define_method :"on_#{type}" do |node|
237
237
  return if part_of_ignored_node?(node)
238
238
  return if node.parent&.shorthand_asgn?
239
239
 
@@ -460,9 +460,8 @@ module RuboCop
460
460
 
461
461
  def assignment(node)
462
462
  *_, condition = *node
463
- Parser::Source::Range.new(node.source_range.source_buffer,
464
- node.source_range.begin_pos,
465
- condition.source_range.begin_pos)
463
+
464
+ node.source_range.begin.join(condition.source_range.begin)
466
465
  end
467
466
 
468
467
  def correct_if_branches(corrector, cop, node)
@@ -28,18 +28,27 @@ module RuboCop
28
28
  def on_new_investigation
29
29
  return if notice.empty? || notice_found?(processed_source)
30
30
 
31
- add_offense(offense_range, message: format(MSG, notice: notice)) do |corrector|
32
- verify_autocorrect_notice!
33
-
34
- token = insert_notice_before(processed_source)
35
- range = token.nil? ? range_between(0, 0) : token.pos
36
-
37
- corrector.insert_before(range, "#{autocorrect_notice}\n")
31
+ verify_autocorrect_notice!
32
+ message = format(MSG, notice: notice)
33
+ if processed_source.blank?
34
+ add_global_offense(message)
35
+ else
36
+ offense_range = source_range(processed_source.buffer, 1, 0)
37
+ add_offense(offense_range, message: message) do |corrector|
38
+ autocorrect(corrector)
39
+ end
38
40
  end
39
41
  end
40
42
 
41
43
  private
42
44
 
45
+ def autocorrect(corrector)
46
+ token = insert_notice_before(processed_source)
47
+ range = token.nil? ? range_between(0, 0) : token.pos
48
+
49
+ corrector.insert_before(range, "#{autocorrect_notice}\n")
50
+ end
51
+
43
52
  def notice
44
53
  cop_config['Notice']
45
54
  end
@@ -48,17 +57,16 @@ module RuboCop
48
57
  cop_config['AutocorrectNotice']
49
58
  end
50
59
 
51
- def offense_range
52
- source_range(processed_source.buffer, 1, 0)
53
- end
54
-
55
60
  def verify_autocorrect_notice!
56
- raise Warning, AUTOCORRECT_EMPTY_WARNING if autocorrect_notice.empty?
61
+ if autocorrect_notice.nil? || autocorrect_notice.empty?
62
+ raise Warning, "#{cop_name}: #{AUTOCORRECT_EMPTY_WARNING}"
63
+ end
57
64
 
58
65
  regex = Regexp.new(notice)
59
- return if autocorrect_notice&.match?(regex)
66
+ return if autocorrect_notice.gsub(/^# */, '').match?(regex)
60
67
 
61
- raise Warning, "AutocorrectNotice '#{autocorrect_notice}' must match Notice /#{notice}/"
68
+ message = "AutocorrectNotice '#{autocorrect_notice}' must match Notice /#{notice}/"
69
+ raise Warning, "#{cop_name}: #{message}"
62
70
  end
63
71
 
64
72
  def insert_notice_before(processed_source)
@@ -72,26 +80,28 @@ module RuboCop
72
80
  return false if token_index >= processed_source.tokens.size
73
81
 
74
82
  token = processed_source.tokens[token_index]
75
- token.comment? && /^#!.*$/.match?(token.text)
83
+ token.comment? && /\A#!.*\z/.match?(token.text)
76
84
  end
77
85
 
78
86
  def encoding_token?(processed_source, token_index)
79
87
  return false if token_index >= processed_source.tokens.size
80
88
 
81
89
  token = processed_source.tokens[token_index]
82
- token.comment? && /^#.*coding\s?[:=]\s?(?:UTF|utf)-8/.match?(token.text)
90
+ token.comment? && /\A#.*coding\s?[:=]\s?(?:UTF|utf)-8/.match?(token.text)
83
91
  end
84
92
 
85
93
  def notice_found?(processed_source)
86
- notice_found = false
87
- notice_regexp = Regexp.new(notice)
94
+ notice_regexp = Regexp.new(notice.lines.map(&:strip).join)
95
+ multiline_notice = +''
88
96
  processed_source.tokens.each do |token|
89
97
  break unless token.comment?
90
98
 
91
- notice_found = notice_regexp.match?(token.text)
92
- break if notice_found
99
+ multiline_notice << token.text.sub(/\A# */, '')
100
+
101
+ break if notice_regexp.match?(token.text)
93
102
  end
94
- notice_found
103
+
104
+ multiline_notice.match?(notice_regexp)
95
105
  end
96
106
  end
97
107
  end
@@ -28,8 +28,6 @@ module RuboCop
28
28
  # # good (without parentheses it's a syntax error)
29
29
  # def foo() do_something end
30
30
  #
31
- # @example
32
- #
33
31
  # # bad
34
32
  # def Baz.foo()
35
33
  # do_something