rubocop 1.62.1 → 1.67.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 (276) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -68
  3. data/config/default.yml +82 -12
  4. data/config/internal_affairs.yml +11 -0
  5. data/exe/rubocop +4 -3
  6. data/lib/rubocop/cached_data.rb +11 -3
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
  8. data/lib/rubocop/cli/command/lsp.rb +2 -2
  9. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  10. data/lib/rubocop/cli.rb +4 -0
  11. data/lib/rubocop/comment_config.rb +1 -1
  12. data/lib/rubocop/config.rb +37 -11
  13. data/lib/rubocop/config_loader.rb +15 -9
  14. data/lib/rubocop/config_loader_resolver.rb +13 -8
  15. data/lib/rubocop/config_obsoletion.rb +1 -1
  16. data/lib/rubocop/config_validator.rb +3 -2
  17. data/lib/rubocop/cop/base.rb +56 -16
  18. data/lib/rubocop/cop/bundler/gem_version.rb +4 -5
  19. data/lib/rubocop/cop/cop.rb +30 -4
  20. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -0
  21. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  22. data/lib/rubocop/cop/documentation.rb +32 -5
  23. data/lib/rubocop/cop/force.rb +12 -0
  24. data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
  25. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  26. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  27. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  28. data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
  29. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +2 -1
  30. data/lib/rubocop/cop/internal_affairs/example_description.rb +2 -1
  31. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  32. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
  33. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
  34. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +11 -1
  35. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
  36. data/lib/rubocop/cop/internal_affairs.rb +16 -0
  37. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
  38. data/lib/rubocop/cop/layout/assignment_indentation.rb +3 -2
  39. data/lib/rubocop/cop/layout/block_alignment.rb +30 -12
  40. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  41. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  42. data/lib/rubocop/cop/layout/condition_position.rb +0 -4
  43. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  44. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  45. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  46. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
  47. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
  48. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +8 -3
  49. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
  50. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -3
  51. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
  52. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
  53. data/lib/rubocop/cop/layout/indentation_width.rb +5 -6
  54. data/lib/rubocop/cop/layout/leading_comment_space.rb +28 -1
  55. data/lib/rubocop/cop/layout/line_length.rb +20 -20
  56. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -0
  57. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  58. data/lib/rubocop/cop/legacy/corrector.rb +12 -2
  59. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +0 -2
  60. data/lib/rubocop/cop/lint/ambiguous_operator.rb +0 -2
  61. data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
  62. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +0 -2
  63. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
  64. data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
  65. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -3
  66. data/lib/rubocop/cop/lint/circular_argument_reference.rb +0 -13
  67. data/lib/rubocop/cop/lint/debugger.rb +27 -6
  68. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  69. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +0 -10
  70. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -5
  71. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +0 -4
  72. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -10
  73. data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
  74. data/lib/rubocop/cop/lint/each_with_object_argument.rb +0 -4
  75. data/lib/rubocop/cop/lint/else_layout.rb +0 -2
  76. data/lib/rubocop/cop/lint/empty_conditional_body.rb +28 -7
  77. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -11
  78. data/lib/rubocop/cop/lint/empty_interpolation.rb +0 -4
  79. data/lib/rubocop/cop/lint/empty_when.rb +1 -3
  80. data/lib/rubocop/cop/lint/ensure_return.rb +1 -9
  81. data/lib/rubocop/cop/lint/erb_new_arguments.rb +21 -14
  82. data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
  83. data/lib/rubocop/cop/lint/float_out_of_range.rb +0 -4
  84. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +0 -10
  85. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +23 -12
  86. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +0 -7
  87. data/lib/rubocop/cop/lint/interpolation_check.rb +0 -4
  88. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +5 -14
  89. data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
  90. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  91. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +25 -6
  92. data/lib/rubocop/cop/lint/loop.rb +6 -12
  93. data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
  94. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -7
  95. data/lib/rubocop/cop/lint/next_without_accumulator.rb +0 -4
  96. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +0 -5
  97. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  98. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
  99. data/lib/rubocop/cop/lint/percent_string_array.rb +0 -4
  100. data/lib/rubocop/cop/lint/percent_symbol_array.rb +0 -4
  101. data/lib/rubocop/cop/lint/rand_one.rb +0 -4
  102. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +3 -1
  103. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -1
  104. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  105. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +0 -4
  106. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  107. data/lib/rubocop/cop/lint/require_parentheses.rb +0 -4
  108. data/lib/rubocop/cop/lint/rescue_exception.rb +0 -4
  109. data/lib/rubocop/cop/lint/return_in_void_context.rb +0 -2
  110. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +0 -4
  111. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +105 -41
  112. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +6 -10
  113. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  114. data/lib/rubocop/cop/lint/to_enum_arguments.rb +2 -9
  115. data/lib/rubocop/cop/lint/unified_integer.rb +0 -4
  116. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  117. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -7
  118. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  119. data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
  120. data/lib/rubocop/cop/lint/useless_assignment.rb +19 -16
  121. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +0 -4
  122. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +77 -0
  123. data/lib/rubocop/cop/lint/useless_setter_call.rb +0 -4
  124. data/lib/rubocop/cop/lint/void.rb +35 -8
  125. data/lib/rubocop/cop/metrics/block_length.rb +6 -5
  126. data/lib/rubocop/cop/metrics/block_nesting.rb +19 -7
  127. data/lib/rubocop/cop/metrics/class_length.rb +6 -5
  128. data/lib/rubocop/cop/metrics/method_length.rb +6 -5
  129. data/lib/rubocop/cop/metrics/module_length.rb +6 -5
  130. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
  131. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  132. data/lib/rubocop/cop/mixin/allowed_methods.rb +7 -1
  133. data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
  134. data/lib/rubocop/cop/mixin/annotation_comment.rb +0 -2
  135. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  136. data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
  137. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +19 -9
  138. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +9 -2
  139. data/lib/rubocop/cop/mixin/line_length_help.rb +7 -2
  140. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  141. data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
  142. data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
  143. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  144. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
  145. data/lib/rubocop/cop/mixin/string_literals_help.rb +12 -0
  146. data/lib/rubocop/cop/naming/accessor_method_name.rb +5 -0
  147. data/lib/rubocop/cop/naming/block_forwarding.rb +31 -12
  148. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  149. data/lib/rubocop/cop/naming/inclusive_language.rb +13 -5
  150. data/lib/rubocop/cop/naming/predicate_name.rb +53 -27
  151. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +10 -1
  152. data/lib/rubocop/cop/offense.rb +2 -2
  153. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  154. data/lib/rubocop/cop/style/access_modifier_declarations.rb +62 -2
  155. data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
  156. data/lib/rubocop/cop/style/alias.rb +2 -1
  157. data/lib/rubocop/cop/style/arguments_forwarding.rb +59 -11
  158. data/lib/rubocop/cop/style/block_delimiters.rb +14 -1
  159. data/lib/rubocop/cop/style/collection_compact.rb +9 -9
  160. data/lib/rubocop/cop/style/combinable_loops.rb +7 -0
  161. data/lib/rubocop/cop/style/commented_keyword.rb +7 -1
  162. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
  163. data/lib/rubocop/cop/style/copyright.rb +31 -21
  164. data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
  165. data/lib/rubocop/cop/style/def_with_parentheses.rb +0 -2
  166. data/lib/rubocop/cop/style/documentation.rb +24 -24
  167. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  168. data/lib/rubocop/cop/style/each_for_simple_loop.rb +0 -1
  169. data/lib/rubocop/cop/style/empty_else.rb +6 -5
  170. data/lib/rubocop/cop/style/empty_heredoc.rb +1 -14
  171. data/lib/rubocop/cop/style/empty_literal.rb +31 -22
  172. data/lib/rubocop/cop/style/eval_with_location.rb +16 -13
  173. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  174. data/lib/rubocop/cop/style/file_read.rb +2 -5
  175. data/lib/rubocop/cop/style/file_write.rb +2 -5
  176. data/lib/rubocop/cop/style/format_string.rb +9 -9
  177. data/lib/rubocop/cop/style/format_string_token.rb +2 -2
  178. data/lib/rubocop/cop/style/global_std_stream.rb +7 -1
  179. data/lib/rubocop/cop/style/guard_clause.rb +3 -1
  180. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -0
  181. data/lib/rubocop/cop/style/hash_except.rb +8 -5
  182. data/lib/rubocop/cop/style/hash_syntax.rb +20 -2
  183. data/lib/rubocop/cop/style/identical_conditional_branches.rb +1 -1
  184. data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
  185. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -4
  186. data/lib/rubocop/cop/style/if_with_semicolon.rb +49 -6
  187. data/lib/rubocop/cop/style/in_pattern_then.rb +6 -2
  188. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  189. data/lib/rubocop/cop/style/lambda.rb +1 -1
  190. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  191. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +77 -43
  192. data/lib/rubocop/cop/style/map_into_array.rb +228 -0
  193. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  194. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  195. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +17 -7
  196. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  197. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -2
  198. data/lib/rubocop/cop/style/missing_else.rb +0 -4
  199. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  200. data/lib/rubocop/cop/style/multiline_when_then.rb +0 -4
  201. data/lib/rubocop/cop/style/multiple_comparison.rb +3 -11
  202. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  203. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  204. data/lib/rubocop/cop/style/numeric_predicate.rb +12 -4
  205. data/lib/rubocop/cop/style/one_line_conditional.rb +6 -2
  206. data/lib/rubocop/cop/style/operator_method_call.rb +25 -6
  207. data/lib/rubocop/cop/style/parallel_assignment.rb +5 -4
  208. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -3
  209. data/lib/rubocop/cop/style/redundant_argument.rb +24 -1
  210. data/lib/rubocop/cop/style/redundant_begin.rb +5 -1
  211. data/lib/rubocop/cop/style/redundant_condition.rb +4 -4
  212. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +1 -1
  213. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  214. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
  215. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  216. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +46 -0
  217. data/lib/rubocop/cop/style/redundant_line_continuation.rb +15 -18
  218. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  219. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  220. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -1
  221. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -24
  222. data/lib/rubocop/cop/style/require_order.rb +2 -2
  223. data/lib/rubocop/cop/style/rescue_modifier.rb +13 -1
  224. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
  225. data/lib/rubocop/cop/style/safe_navigation.rb +94 -52
  226. data/lib/rubocop/cop/style/select_by_regexp.rb +9 -6
  227. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  228. data/lib/rubocop/cop/style/send.rb +4 -4
  229. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +104 -0
  230. data/lib/rubocop/cop/style/sole_nested_conditional.rb +21 -2
  231. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  232. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  233. data/lib/rubocop/cop/style/super_arguments.rb +174 -0
  234. data/lib/rubocop/cop/style/symbol_proc.rb +39 -5
  235. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  236. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  237. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  238. data/lib/rubocop/cop/style/while_until_do.rb +0 -2
  239. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  240. data/lib/rubocop/cop/style/zero_length_predicate.rb +32 -24
  241. data/lib/rubocop/cop/team.rb +27 -3
  242. data/lib/rubocop/cop/util.rb +8 -2
  243. data/lib/rubocop/cop/variable_force.rb +13 -1
  244. data/lib/rubocop/cops_documentation_generator.rb +73 -34
  245. data/lib/rubocop/core_ext/string.rb +2 -6
  246. data/lib/rubocop/ext/regexp_node.rb +9 -31
  247. data/lib/rubocop/ext/regexp_parser.rb +4 -21
  248. data/lib/rubocop/file_finder.rb +9 -4
  249. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  250. data/lib/rubocop/formatter/disabled_config_formatter.rb +13 -9
  251. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  252. data/lib/rubocop/formatter/html_formatter.rb +3 -1
  253. data/lib/rubocop/formatter/junit_formatter.rb +70 -23
  254. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  255. data/lib/rubocop/lockfile.rb +58 -7
  256. data/lib/rubocop/lsp/routes.rb +10 -13
  257. data/lib/rubocop/lsp/runtime.rb +2 -0
  258. data/lib/rubocop/lsp/server.rb +2 -1
  259. data/lib/rubocop/lsp.rb +9 -2
  260. data/lib/rubocop/options.rb +6 -4
  261. data/lib/rubocop/rake_task.rb +1 -1
  262. data/lib/rubocop/remote_config.rb +5 -1
  263. data/lib/rubocop/result_cache.rb +2 -8
  264. data/lib/rubocop/rspec/expect_offense.rb +9 -0
  265. data/lib/rubocop/rspec/shared_contexts.rb +35 -3
  266. data/lib/rubocop/rspec/support.rb +1 -0
  267. data/lib/rubocop/runner.rb +8 -1
  268. data/lib/rubocop/server/cache.rb +16 -1
  269. data/lib/rubocop/server/client_command/exec.rb +2 -2
  270. data/lib/rubocop/server/client_command/start.rb +1 -1
  271. data/lib/rubocop/server/core.rb +5 -0
  272. data/lib/rubocop/target_ruby.rb +19 -15
  273. data/lib/rubocop/version.rb +7 -5
  274. data/lib/rubocop/yaml_duplication_checker.rb +20 -26
  275. data/lib/rubocop.rb +13 -1
  276. metadata +20 -32
@@ -8,17 +8,13 @@ module RuboCop
8
8
  # @example
9
9
  #
10
10
  # # bad
11
- #
12
11
  # begin
13
12
  # do_something
14
13
  # rescue Exception
15
14
  # handle_exception
16
15
  # end
17
16
  #
18
- # @example
19
- #
20
17
  # # good
21
- #
22
18
  # begin
23
19
  # do_something
24
20
  # rescue ArgumentError
@@ -19,8 +19,6 @@ module RuboCop
19
19
  # return 42
20
20
  # end
21
21
  #
22
- # @example
23
- #
24
22
  # # good
25
23
  # def initialize
26
24
  # foo
@@ -12,15 +12,11 @@ module RuboCop
12
12
  # @example
13
13
  #
14
14
  # # bad
15
- #
16
15
  # x&.foo.bar
17
16
  # x&.foo + bar
18
17
  # x&.foo[bar]
19
18
  #
20
- # @example
21
- #
22
19
  # # good
23
- #
24
20
  # x&.foo&.bar
25
21
  # x&.foo || bar
26
22
  class SafeNavigationChain < Base
@@ -3,88 +3,152 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Check to make sure that if safe navigation is used for a method
7
- # call in an `&&` or `||` condition that safe navigation is used for all
8
- # method calls on that same object.
6
+ # Check to make sure that if safe navigation is used in an `&&` or `||` condition,
7
+ # consistent and appropriate safe navigation, without excess or deficiency,
8
+ # is used for all method calls on the same object.
9
9
  #
10
10
  # @example
11
11
  # # bad
12
- # foo&.bar && foo.baz
12
+ # foo&.bar && foo&.baz
13
13
  #
14
- # # bad
15
- # foo.bar || foo&.baz
14
+ # # good
15
+ # foo&.bar && foo.baz
16
16
  #
17
17
  # # bad
18
- # foo&.bar && (foobar.baz || foo.baz)
18
+ # foo.bar && foo&.baz
19
19
  #
20
20
  # # good
21
21
  # foo.bar && foo.baz
22
22
  #
23
+ # # bad
24
+ # foo&.bar || foo.baz
25
+ #
23
26
  # # good
24
27
  # foo&.bar || foo&.baz
25
28
  #
29
+ # # bad
30
+ # foo.bar || foo&.baz
31
+ #
26
32
  # # good
33
+ # foo.bar || foo.baz
34
+ #
35
+ # # bad
27
36
  # foo&.bar && (foobar.baz || foo&.baz)
28
37
  #
38
+ # # good
39
+ # foo&.bar && (foobar.baz || foo.baz)
40
+ #
29
41
  class SafeNavigationConsistency < Base
30
- include IgnoredNode
31
42
  include NilMethods
32
43
  extend AutoCorrector
33
44
 
34
- MSG = 'Ensure that safe navigation is used consistently inside of `&&` and `||`.'
45
+ USE_DOT_MSG = 'Use `.` instead of unnecessary `&.`.'
46
+ USE_SAFE_NAVIGATION_MSG = 'Use `&.` for consistency with safe navigation.'
47
+
48
+ def on_and(node)
49
+ all_operands = collect_operands(node, [])
50
+ operand_groups = all_operands.group_by { |operand| receiver_name_as_key(operand, +'') }
51
+
52
+ operand_groups.each_value do |grouped_operands|
53
+ next unless (dot_op, begin_of_rest_operands = find_consistent_parts(grouped_operands))
35
54
 
36
- def on_csend(node)
37
- return unless node.parent&.operator_keyword?
55
+ rest_operands = grouped_operands[begin_of_rest_operands..]
56
+ rest_operands.each do |operand|
57
+ next if already_appropriate_call?(operand, dot_op)
38
58
 
39
- check(node)
59
+ register_offense(operand, dot_op)
60
+ end
61
+ end
40
62
  end
63
+ alias on_or on_and
41
64
 
42
- def check(node)
43
- ancestor = top_conditional_ancestor(node)
44
- conditions = ancestor.conditions
45
- safe_nav_receiver = node.receiver
65
+ private
46
66
 
47
- method_calls = conditions.select(&:send_type?)
48
- unsafe_method_calls = unsafe_method_calls(method_calls, safe_nav_receiver)
67
+ def collect_operands(node, operand_nodes)
68
+ operand_nodes(node.lhs, operand_nodes)
69
+ operand_nodes(node.rhs, operand_nodes)
49
70
 
50
- unsafe_method_calls.each do |unsafe_method_call|
51
- location = location(node, unsafe_method_call)
71
+ operand_nodes
72
+ end
52
73
 
53
- add_offense(location) { |corrector| autocorrect(corrector, unsafe_method_call) }
74
+ def receiver_name_as_key(method, fully_receivers)
75
+ if method.parent.call_type?
76
+ receiver(method.parent, fully_receivers)
77
+ else
78
+ fully_receivers << method.receiver&.source.to_s
79
+ end
80
+ end
54
81
 
55
- ignore_node(unsafe_method_call)
82
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
83
+ def find_consistent_parts(grouped_operands)
84
+ csend_in_and, csend_in_or, send_in_and, send_in_or = most_left_indices(grouped_operands)
85
+
86
+ if csend_in_and
87
+ ['.', (send_in_and ? [send_in_and, csend_in_and].min : csend_in_and) + 1]
88
+ elsif send_in_or && csend_in_or
89
+ send_in_or < csend_in_or ? ['.', send_in_or + 1] : ['&.', csend_in_or + 1]
90
+ elsif send_in_and && csend_in_or && send_in_and < csend_in_or
91
+ ['.', csend_in_or]
56
92
  end
57
93
  end
94
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
58
95
 
59
- private
96
+ def already_appropriate_call?(operand, dot_op)
97
+ (operand.safe_navigation? && dot_op == '&.') || (operand.dot? && dot_op == '.')
98
+ end
99
+
100
+ def register_offense(operand, dot_operator)
101
+ offense_range = operand.operator_method? ? operand : operand.loc.dot
102
+ message = dot_operator == '.' ? USE_DOT_MSG : USE_SAFE_NAVIGATION_MSG
60
103
 
61
- def autocorrect(corrector, node)
62
- return unless node.dot?
104
+ add_offense(offense_range, message: message) do |corrector|
105
+ next if operand.operator_method?
63
106
 
64
- corrector.insert_before(node.loc.dot, '&')
107
+ corrector.replace(operand.loc.dot, dot_operator)
108
+ end
65
109
  end
66
110
 
67
- def location(node, unsafe_method_call)
68
- node.source_range.join(unsafe_method_call.source_range)
111
+ def operand_nodes(operand, operand_nodes)
112
+ if operand.operator_keyword?
113
+ collect_operands(operand, operand_nodes)
114
+ elsif operand.call_type?
115
+ operand_nodes << operand
116
+ end
69
117
  end
70
118
 
71
- def top_conditional_ancestor(node)
72
- parent = node.parent
73
- unless parent &&
74
- (parent.operator_keyword? ||
75
- (parent.begin_type? && parent.parent && parent.parent.operator_keyword?))
76
- return node
119
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
120
+ def most_left_indices(grouped_operands)
121
+ indices = { csend_in_and: nil, csend_in_or: nil, send_in_and: nil, send_in_or: nil }
122
+
123
+ grouped_operands.each_with_index do |operand, index|
124
+ indices[:csend_in_and] ||= index if operand_in_and?(operand) && operand.csend_type?
125
+ indices[:csend_in_or] ||= index if operand_in_or?(operand) && operand.csend_type?
126
+ indices[:send_in_and] ||= index if operand_in_and?(operand) && !nilable?(operand)
127
+ indices[:send_in_or] ||= index if operand_in_or?(operand) && !nilable?(operand)
77
128
  end
78
129
 
79
- top_conditional_ancestor(parent)
130
+ indices.values
80
131
  end
132
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
81
133
 
82
- def unsafe_method_calls(method_calls, safe_nav_receiver)
83
- method_calls.select do |method_call|
84
- safe_nav_receiver == method_call.receiver &&
85
- !nil_methods.include?(method_call.method_name) &&
86
- !ignored_node?(method_call)
87
- end
134
+ def operand_in_and?(node)
135
+ return true if node.parent.and_type?
136
+
137
+ parent = node.parent.parent while node.parent.begin_type?
138
+
139
+ parent&.and_type?
140
+ end
141
+
142
+ def operand_in_or?(node)
143
+ return true if node.parent.or_type?
144
+
145
+ parent = node.parent.parent while node.parent.begin_type?
146
+
147
+ parent&.or_type?
148
+ end
149
+
150
+ def nilable?(node)
151
+ node.csend_type? || nil_methods.include?(node.method_name)
88
152
  end
89
153
  end
90
154
  end
@@ -12,17 +12,16 @@ module RuboCop
12
12
  # because `Ractor` should not access outer variables.
13
13
  # eg. following style is encouraged:
14
14
  #
15
- # [source,ruby]
16
- # ----
17
- # worker_id, pipe = env
18
- # Ractor.new(worker_id, pipe) do |worker_id, pipe|
19
- # end
20
- # ----
15
+ # [source,ruby]
16
+ # ----
17
+ # worker_id, pipe = env
18
+ # Ractor.new(worker_id, pipe) do |worker_id, pipe|
19
+ # end
20
+ # ----
21
21
  #
22
22
  # @example
23
23
  #
24
24
  # # bad
25
- #
26
25
  # def some_method
27
26
  # foo = 1
28
27
  #
@@ -31,10 +30,7 @@ module RuboCop
31
30
  # end
32
31
  # end
33
32
  #
34
- # @example
35
- #
36
33
  # # good
37
- #
38
34
  # def some_method
39
35
  # foo = 1
40
36
  #
@@ -141,7 +141,7 @@ module RuboCop
141
141
  end
142
142
 
143
143
  def in_percent_literal_array?(node)
144
- node.parent&.array_type? && node.parent&.percent_literal?
144
+ node.parent&.array_type? && node.parent.percent_literal?
145
145
  end
146
146
 
147
147
  def correct_hash_key(node)
@@ -49,15 +49,8 @@ module RuboCop
49
49
  return unless def_node
50
50
 
51
51
  enum_conversion_call?(node) do |method_node, arguments|
52
- next if method_node.call_type? &&
53
- !method_node.method?(:__method__) && !method_node.method?(:__callee__)
54
-
55
- valid = if method_name?(method_node, def_node.method_name)
56
- arguments_match?(arguments, def_node)
57
- else
58
- def_node.arguments.empty?
59
- end
60
- return if valid
52
+ next if !method_name?(method_node, def_node.method_name) ||
53
+ arguments_match?(arguments, def_node)
61
54
 
62
55
  add_offense(node)
63
56
  end
@@ -8,14 +8,10 @@ module RuboCop
8
8
  # @example
9
9
  #
10
10
  # # bad
11
- #
12
11
  # 1.is_a?(Fixnum)
13
12
  # 1.is_a?(Bignum)
14
13
  #
15
- # @example
16
- #
17
14
  # # good
18
- #
19
15
  # 1.is_a?(Integer)
20
16
  class UnifiedInteger < Base
21
17
  extend AutoCorrector
@@ -113,6 +113,7 @@ module RuboCop
113
113
  PATTERN
114
114
 
115
115
  def on_block(node)
116
+ return unless node.body
116
117
  return unless reduce_with_block?(node)
117
118
  return unless node.argument_list.length >= 2
118
119
 
@@ -10,14 +10,12 @@ module RuboCop
10
10
  # @example
11
11
  #
12
12
  # # bad
13
- #
14
13
  # def some_method
15
14
  # return
16
15
  # do_something
17
16
  # end
18
17
  #
19
18
  # # bad
20
- #
21
19
  # def some_method
22
20
  # if cond
23
21
  # return
@@ -27,10 +25,7 @@ module RuboCop
27
25
  # do_something
28
26
  # end
29
27
  #
30
- # @example
31
- #
32
28
  # # good
33
- #
34
29
  # def some_method
35
30
  # do_something
36
31
  # end
@@ -71,7 +66,7 @@ module RuboCop
71
66
  expressions.any? { |expr| flow_expression?(expr) }
72
67
  when :if
73
68
  check_if(node)
74
- when :case
69
+ when :case, :case_match
75
70
  check_case(node)
76
71
  else
77
72
  false
@@ -89,7 +84,9 @@ module RuboCop
89
84
  return false unless else_branch
90
85
  return false unless flow_expression?(else_branch)
91
86
 
92
- node.when_branches.all? { |branch| branch.body && flow_expression?(branch.body) }
87
+ branches = node.case_type? ? node.when_branches : node.in_pattern_branches
88
+
89
+ branches.all? { |branch| branch.body && flow_expression?(branch.body) }
93
90
  end
94
91
  end
95
92
  end
@@ -160,7 +160,7 @@ module RuboCop
160
160
  break_statement && !preceded_by_continue_statement?(break_statement)
161
161
  when :if
162
162
  check_if(node)
163
- when :case
163
+ when :case, :case_match
164
164
  check_case(node)
165
165
  else
166
166
  false
@@ -178,7 +178,13 @@ module RuboCop
178
178
  return false unless else_branch
179
179
  return false unless break_statement?(else_branch)
180
180
 
181
- node.when_branches.all? { |branch| branch.body && break_statement?(branch.body) }
181
+ branches = if node.case_type?
182
+ node.when_branches
183
+ else
184
+ node.in_pattern_branches
185
+ end
186
+
187
+ branches.all? { |branch| branch.body && break_statement?(branch.body) }
182
188
  end
183
189
 
184
190
  def preceded_by_continue_statement?(break_statement)
@@ -3,29 +3,47 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Identifies places where `URI.regexp` is obsolete and should
7
- # not be used. Instead, use `URI::DEFAULT_PARSER.make_regexp`.
6
+ # Identifies places where `URI.regexp` is obsolete and should not be used.
7
+ #
8
+ # For Ruby 3.3 or lower, use `URI::DEFAULT_PARSER.make_regexp`.
9
+ # For Ruby 3.4 or higher, use `URI::RFC2396_PARSER.make_regexp`.
10
+ #
11
+ # NOTE: If you need to support both Ruby 3.3 and lower as well as Ruby 3.4 and higher,
12
+ # consider manually changing the code as follows:
13
+ #
14
+ # [source,ruby]
15
+ # ----
16
+ # defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
17
+ # ----
8
18
  #
9
19
  # @example
10
20
  # # bad
11
21
  # URI.regexp('http://example.com')
12
22
  #
13
- # # good
23
+ # # good - Ruby 3.3 or lower
14
24
  # URI::DEFAULT_PARSER.make_regexp('http://example.com')
15
25
  #
26
+ # # good - Ruby 3.4 or higher
27
+ # URI::RFC2396_PARSER.make_regexp('http://example.com')
28
+ #
16
29
  class UriRegexp < Base
17
30
  extend AutoCorrector
18
31
 
19
32
  MSG = '`%<current>s` is obsolete and should not be used. Instead, use `%<preferred>s`.'
20
- URI_CONSTANTS = ['URI', '::URI'].freeze
21
33
  RESTRICT_ON_SEND = %i[regexp].freeze
22
34
 
35
+ # @!method uri_constant?(node)
36
+ def_node_matcher :uri_constant?, <<~PATTERN
37
+ (const {cbase nil?} :URI)
38
+ PATTERN
39
+
23
40
  def on_send(node)
24
- return unless node.receiver
25
- return unless URI_CONSTANTS.include?(node.receiver.source)
41
+ return unless uri_constant?(node.receiver)
26
42
 
43
+ parser = target_ruby_version >= 3.4 ? 'RFC2396_PARSER' : 'DEFAULT_PARSER'
27
44
  argument = node.first_argument ? "(#{node.first_argument.source})" : ''
28
- preferred_method = "#{node.receiver.source}::DEFAULT_PARSER.make_regexp#{argument}"
45
+
46
+ preferred_method = "#{node.receiver.source}::#{parser}.make_regexp#{argument}"
29
47
  message = format(MSG, current: node.source, preferred: preferred_method)
30
48
 
31
49
  add_offense(node.loc.selector, message: message) do |corrector|
@@ -16,28 +16,23 @@ module RuboCop
16
16
  # reassignments and properly handles varied cases such as branch, loop,
17
17
  # rescue, ensure, etc.
18
18
  #
19
+ # This cop's autocorrection avoids cases like `a ||= 1` because removing assignment from
20
+ # operator assignment can cause NameError if this assignment has been used to declare
21
+ # a local variable. For example, replacing `a ||= 1` with `a || 1` may cause
22
+ # "undefined local variable or method `a' for main:Object (NameError)".
23
+ #
19
24
  # NOTE: Given the assignment `foo = 1, bar = 2`, removing unused variables
20
25
  # can lead to a syntax error, so this case is not autocorrected.
21
26
  #
22
- # @safety
23
- # This cop's autocorrection is unsafe because removing assignment from
24
- # operator assignment can cause NameError if this assignment has been used to declare
25
- # local variable. For example, replacing `a ||= 1` to `a || 1` may cause
26
- # "undefined local variable or method `a' for main:Object (NameError)".
27
- #
28
27
  # @example
29
28
  #
30
29
  # # bad
31
- #
32
30
  # def some_method
33
31
  # some_var = 1
34
32
  # do_something
35
33
  # end
36
34
  #
37
- # @example
38
- #
39
35
  # # good
40
- #
41
36
  # def some_method
42
37
  # some_var = 1
43
38
  # do_something(some_var)
@@ -57,24 +52,32 @@ module RuboCop
57
52
  scope.variables.each_value { |variable| check_for_unused_assignments(variable) }
58
53
  end
59
54
 
60
- # rubocop:disable Metrics/AbcSize
55
+ # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
61
56
  def check_for_unused_assignments(variable)
62
57
  return if variable.should_be_unused?
63
58
 
64
- variable.assignments.each do |assignment|
65
- next if assignment.used? || part_of_ignored_node?(assignment.node)
59
+ variable.assignments.reverse_each do |assignment|
60
+ assignment_node = assignment.node
61
+ next if assignment.used? || part_of_ignored_node?(assignment_node)
66
62
 
67
63
  message = message_for_useless_assignment(assignment)
68
64
  range = offense_range(assignment)
69
65
 
70
66
  add_offense(range, message: message) do |corrector|
71
- autocorrect(corrector, assignment) unless sequential_assignment?(assignment.node)
67
+ # In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
68
+ # and where changing `x ||= 1` to `x = 1` would cause `NameError`,
69
+ # the autocorrect will be skipped, even if the variable is unused.
70
+ if sequential_assignment?(assignment_node) || assignment_node.parent&.or_asgn_type?
71
+ next
72
+ end
73
+
74
+ autocorrect(corrector, assignment)
72
75
  end
73
76
 
74
- ignore_node(assignment.node) if chained_assignment?(assignment.node)
77
+ ignore_node(assignment_node) if chained_assignment?(assignment_node)
75
78
  end
76
79
  end
77
- # rubocop:enable Metrics/AbcSize
80
+ # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
78
81
 
79
82
  def message_for_useless_assignment(assignment)
80
83
  variable = assignment.variable
@@ -10,17 +10,13 @@ module RuboCop
10
10
  # @example
11
11
  #
12
12
  # # bad
13
- #
14
13
  # begin
15
14
  # do_something
16
15
  # else
17
16
  # do_something_else # This will never be run.
18
17
  # end
19
18
  #
20
- # @example
21
- #
22
19
  # # good
23
- #
24
20
  # begin
25
21
  # do_something
26
22
  # rescue
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Certain numeric operations have no impact, being:
7
+ # Adding or subtracting 0, multiplying or dividing by 1 or raising to the power of 1.
8
+ # These are probably leftover from debugging, or are mistakes.
9
+ #
10
+ # @example
11
+ #
12
+ # # bad
13
+ # x + 0
14
+ # x - 0
15
+ # x * 1
16
+ # x / 1
17
+ # x ** 1
18
+ #
19
+ # # good
20
+ # x
21
+ #
22
+ # # bad
23
+ # x += 0
24
+ # x -= 0
25
+ # x *= 1
26
+ # x /= 1
27
+ # x **= 1
28
+ #
29
+ # # good
30
+ # x = x
31
+ #
32
+ class UselessNumericOperation < Base
33
+ extend AutoCorrector
34
+ MSG = 'Do not apply inconsequential numeric operations to variables.'
35
+ RESTRICT_ON_SEND = %i[+ - * / **].freeze
36
+
37
+ # @!method useless_operation?(node)
38
+ def_node_matcher :useless_operation?, '(send (send nil? $_) $_ (int $_))'
39
+
40
+ # @!method useless_abbreviated_assignment?(node)
41
+ def_node_matcher :useless_abbreviated_assignment?, '(op-asgn (lvasgn $_) $_ (int $_))'
42
+
43
+ def on_send(node)
44
+ return unless useless_operation?(node)
45
+
46
+ variable, operation, number = useless_operation?(node)
47
+ return unless useless?(operation, number)
48
+
49
+ add_offense(node) do |corrector|
50
+ corrector.replace(node, variable)
51
+ end
52
+ end
53
+
54
+ def on_op_asgn(node)
55
+ return unless useless_abbreviated_assignment?(node)
56
+
57
+ variable, operation, number = useless_abbreviated_assignment?(node)
58
+ return unless useless?(operation, number)
59
+
60
+ add_offense(node) do |corrector|
61
+ corrector.replace(node, "#{variable} = #{variable}")
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def useless?(operation, number)
68
+ if number.zero?
69
+ true if %i[+ -].include?(operation)
70
+ elsif number == 1
71
+ true if %i[* / **].include?(operation)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -17,16 +17,12 @@ module RuboCop
17
17
  # @example
18
18
  #
19
19
  # # bad
20
- #
21
20
  # def something
22
21
  # x = Something.new
23
22
  # x.attr = 5
24
23
  # end
25
24
  #
26
- # @example
27
- #
28
25
  # # good
29
- #
30
26
  # def something
31
27
  # x = Something.new
32
28
  # x.attr = 5