rubocop 1.65.1 → 1.75.6

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 (507) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +72 -72
  4. data/config/default.yml +299 -55
  5. data/config/internal_affairs.yml +31 -0
  6. data/config/obsoletion.yml +3 -1
  7. data/exe/rubocop +4 -3
  8. data/lib/rubocop/cached_data.rb +12 -4
  9. data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
  10. data/lib/rubocop/cli/command/execute_runner.rb +4 -4
  11. data/lib/rubocop/cli/command/lsp.rb +2 -2
  12. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  13. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  14. data/lib/rubocop/cli/command/version.rb +2 -2
  15. data/lib/rubocop/cli.rb +1 -1
  16. data/lib/rubocop/comment_config.rb +3 -3
  17. data/lib/rubocop/config.rb +57 -11
  18. data/lib/rubocop/config_loader.rb +66 -17
  19. data/lib/rubocop/config_loader_resolver.rb +39 -14
  20. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  21. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  22. data/lib/rubocop/config_obsoletion.rb +46 -2
  23. data/lib/rubocop/config_validator.rb +27 -15
  24. data/lib/rubocop/cop/autocorrect_logic.rb +36 -19
  25. data/lib/rubocop/cop/base.rb +17 -3
  26. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  27. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  28. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  29. data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
  30. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  31. data/lib/rubocop/cop/cop.rb +8 -0
  32. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
  33. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
  34. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -0
  35. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  36. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  37. data/lib/rubocop/cop/documentation.rb +18 -1
  38. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  39. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  40. data/lib/rubocop/cop/generator.rb +6 -0
  41. data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
  42. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  43. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +2 -1
  44. data/lib/rubocop/cop/internal_affairs/example_description.rb +8 -4
  45. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  46. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  47. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
  48. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  49. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  50. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  51. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  52. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +230 -0
  53. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  54. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  55. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  56. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  57. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  58. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  59. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  60. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  61. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
  62. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +11 -2
  63. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  64. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  65. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +23 -2
  66. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
  67. data/lib/rubocop/cop/internal_affairs.rb +7 -0
  68. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +6 -2
  69. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -9
  70. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  71. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  72. data/lib/rubocop/cop/layout/block_alignment.rb +32 -13
  73. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  74. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  75. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  76. data/lib/rubocop/cop/layout/def_end_alignment.rb +2 -2
  77. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  78. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  79. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +4 -4
  80. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +9 -12
  81. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +30 -4
  82. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  83. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  84. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +12 -8
  85. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  86. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  87. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  88. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  89. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -10
  90. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  91. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  92. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
  93. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  94. data/lib/rubocop/cop/layout/hash_alignment.rb +8 -6
  95. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  96. data/lib/rubocop/cop/layout/indentation_width.rb +12 -12
  97. data/lib/rubocop/cop/layout/leading_comment_space.rb +83 -1
  98. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  99. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  100. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  101. data/lib/rubocop/cop/layout/line_length.rb +135 -16
  102. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  103. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  104. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  105. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  106. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  107. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  108. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  109. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +3 -4
  110. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  111. data/lib/rubocop/cop/layout/redundant_line_break.rb +19 -46
  112. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +6 -7
  113. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  114. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  115. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  116. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  117. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  118. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -1
  119. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  120. data/lib/rubocop/cop/layout/space_around_operators.rb +23 -21
  121. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  122. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  123. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  124. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  125. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +11 -1
  126. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +5 -0
  127. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +7 -0
  128. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  129. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  130. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  131. data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
  132. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +118 -0
  133. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  134. data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
  135. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
  136. data/lib/rubocop/cop/lint/boolean_symbol.rb +2 -2
  137. data/lib/rubocop/cop/lint/circular_argument_reference.rb +4 -1
  138. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  139. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  140. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  141. data/lib/rubocop/cop/lint/debugger.rb +3 -3
  142. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  143. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +3 -2
  144. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  145. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  146. data/lib/rubocop/cop/lint/duplicate_methods.rb +46 -19
  147. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  148. data/lib/rubocop/cop/lint/duplicate_set_element.rb +87 -0
  149. data/lib/rubocop/cop/lint/empty_conditional_body.rb +29 -58
  150. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  151. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  152. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  153. data/lib/rubocop/cop/lint/ensure_return.rb +1 -4
  154. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -7
  155. data/lib/rubocop/cop/lint/float_comparison.rb +21 -17
  156. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -4
  157. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  158. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  159. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +13 -5
  160. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  161. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +8 -14
  162. data/lib/rubocop/cop/lint/literal_as_condition.rb +118 -9
  163. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  164. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +49 -8
  165. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
  166. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  167. data/lib/rubocop/cop/lint/mixed_case_range.rb +5 -8
  168. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  169. data/lib/rubocop/cop/lint/nested_method_definition.rb +10 -6
  170. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  171. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  172. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +12 -3
  173. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
  174. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  175. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  176. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  177. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +93 -0
  178. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -3
  179. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +3 -2
  180. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +6 -11
  181. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  182. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  183. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  184. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  185. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +13 -8
  186. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  187. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  188. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  189. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  190. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  191. data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
  192. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  193. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  194. data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
  195. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  196. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -1
  197. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +109 -41
  198. data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
  199. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  200. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
  201. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  202. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  203. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  204. data/lib/rubocop/cop/lint/symbol_conversion.rb +2 -2
  205. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  206. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  207. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  208. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  209. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
  210. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  211. data/lib/rubocop/cop/lint/unreachable_code.rb +52 -2
  212. data/lib/rubocop/cop/lint/unreachable_loop.rb +6 -6
  213. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  214. data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
  215. data/lib/rubocop/cop/lint/useless_access_modifier.rb +5 -4
  216. data/lib/rubocop/cop/lint/useless_assignment.rb +20 -11
  217. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  218. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  219. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
  220. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  221. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +78 -0
  222. data/lib/rubocop/cop/lint/useless_rescue.rb +2 -2
  223. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  224. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  225. data/lib/rubocop/cop/lint/void.rb +40 -14
  226. data/lib/rubocop/cop/message_annotator.rb +7 -3
  227. data/lib/rubocop/cop/metrics/block_length.rb +7 -5
  228. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  229. data/lib/rubocop/cop/metrics/class_length.rb +15 -14
  230. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  231. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  232. data/lib/rubocop/cop/metrics/method_length.rb +15 -6
  233. data/lib/rubocop/cop/metrics/module_length.rb +7 -6
  234. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  235. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  236. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +3 -4
  237. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  238. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  239. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  240. data/lib/rubocop/cop/mixin/annotation_comment.rb +0 -2
  241. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  242. data/lib/rubocop/cop/mixin/check_line_breakable.rb +22 -12
  243. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  244. data/lib/rubocop/cop/mixin/comments_help.rb +8 -3
  245. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  246. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  247. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  248. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  249. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  250. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  251. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +22 -11
  252. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
  253. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  254. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  255. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  256. data/lib/rubocop/cop/mixin/line_length_help.rb +12 -6
  257. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  258. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +7 -9
  259. data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
  260. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  261. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +68 -30
  262. data/lib/rubocop/cop/mixin/range_help.rb +15 -4
  263. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  264. data/lib/rubocop/cop/mixin/statement_modifier.rb +11 -5
  265. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  266. data/lib/rubocop/cop/mixin/string_literals_help.rb +12 -0
  267. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  268. data/lib/rubocop/cop/mixin/trailing_comma.rb +21 -5
  269. data/lib/rubocop/cop/naming/accessor_method_name.rb +11 -6
  270. data/lib/rubocop/cop/naming/block_forwarding.rb +20 -16
  271. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  272. data/lib/rubocop/cop/naming/file_name.rb +0 -2
  273. data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
  274. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +12 -13
  275. data/lib/rubocop/cop/naming/method_name.rb +64 -8
  276. data/lib/rubocop/cop/naming/predicate_name.rb +46 -2
  277. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +6 -14
  278. data/lib/rubocop/cop/naming/variable_name.rb +50 -6
  279. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  280. data/lib/rubocop/cop/offense.rb +4 -5
  281. data/lib/rubocop/cop/registry.rb +9 -6
  282. data/lib/rubocop/cop/security/compound_hash.rb +2 -0
  283. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  284. data/lib/rubocop/cop/style/access_modifier_declarations.rb +96 -28
  285. data/lib/rubocop/cop/style/accessor_grouping.rb +29 -7
  286. data/lib/rubocop/cop/style/alias.rb +1 -1
  287. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  288. data/lib/rubocop/cop/style/and_or.rb +1 -1
  289. data/lib/rubocop/cop/style/arguments_forwarding.rb +94 -30
  290. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  291. data/lib/rubocop/cop/style/array_intersect.rb +42 -30
  292. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  293. data/lib/rubocop/cop/style/block_delimiters.rb +51 -20
  294. data/lib/rubocop/cop/style/case_like_if.rb +8 -11
  295. data/lib/rubocop/cop/style/class_and_module_children.rb +52 -11
  296. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  297. data/lib/rubocop/cop/style/collection_compact.rb +10 -10
  298. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  299. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  300. data/lib/rubocop/cop/style/combinable_loops.rb +10 -2
  301. data/lib/rubocop/cop/style/commented_keyword.rb +25 -2
  302. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  303. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  304. data/lib/rubocop/cop/style/conditional_assignment.rb +40 -28
  305. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  306. data/lib/rubocop/cop/style/data_inheritance.rb +8 -1
  307. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  308. data/lib/rubocop/cop/style/documentation.rb +1 -1
  309. data/lib/rubocop/cop/style/double_negation.rb +4 -4
  310. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  311. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  312. data/lib/rubocop/cop/style/empty_else.rb +10 -7
  313. data/lib/rubocop/cop/style/empty_heredoc.rb +1 -14
  314. data/lib/rubocop/cop/style/empty_literal.rb +35 -22
  315. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  316. data/lib/rubocop/cop/style/endless_method.rb +150 -18
  317. data/lib/rubocop/cop/style/eval_with_location.rb +5 -5
  318. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -3
  319. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  320. data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
  321. data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
  322. data/lib/rubocop/cop/style/fetch_env_var.rb +2 -1
  323. data/lib/rubocop/cop/style/file_null.rb +89 -0
  324. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  325. data/lib/rubocop/cop/style/float_division.rb +8 -4
  326. data/lib/rubocop/cop/style/for.rb +1 -1
  327. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  328. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  329. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  330. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  331. data/lib/rubocop/cop/style/guard_clause.rb +20 -4
  332. data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
  333. data/lib/rubocop/cop/style/hash_each_methods.rb +12 -8
  334. data/lib/rubocop/cop/style/hash_except.rb +35 -147
  335. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  336. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  337. data/lib/rubocop/cop/style/hash_syntax.rb +11 -5
  338. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  339. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  340. data/lib/rubocop/cop/style/identical_conditional_branches.rb +26 -7
  341. data/lib/rubocop/cop/style/if_inside_else.rb +11 -15
  342. data/lib/rubocop/cop/style/if_unless_modifier.rb +25 -5
  343. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +3 -4
  344. data/lib/rubocop/cop/style/if_with_semicolon.rb +60 -6
  345. data/lib/rubocop/cop/style/in_pattern_then.rb +6 -2
  346. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  347. data/lib/rubocop/cop/style/inverse_methods.rb +15 -12
  348. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  349. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  350. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  351. data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
  352. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  353. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  354. data/lib/rubocop/cop/style/lambda.rb +2 -1
  355. data/lib/rubocop/cop/style/lambda_call.rb +10 -4
  356. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  357. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  358. data/lib/rubocop/cop/style/map_into_array.rb +75 -14
  359. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  360. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  361. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +38 -23
  362. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  363. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +10 -13
  364. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  365. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  366. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  367. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  368. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  369. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  370. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  371. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  372. data/lib/rubocop/cop/style/multiple_comparison.rb +53 -60
  373. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  374. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -5
  375. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  376. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -2
  377. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  378. data/lib/rubocop/cop/style/next.rb +44 -0
  379. data/lib/rubocop/cop/style/not.rb +1 -1
  380. data/lib/rubocop/cop/style/numeric_predicate.rb +2 -2
  381. data/lib/rubocop/cop/style/object_then.rb +15 -15
  382. data/lib/rubocop/cop/style/one_line_conditional.rb +30 -5
  383. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  384. data/lib/rubocop/cop/style/operator_method_call.rb +25 -7
  385. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  386. data/lib/rubocop/cop/style/parallel_assignment.rb +14 -22
  387. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  388. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  389. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  390. data/lib/rubocop/cop/style/proc.rb +2 -2
  391. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -3
  392. data/lib/rubocop/cop/style/raise_args.rb +15 -13
  393. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  394. data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
  395. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  396. data/lib/rubocop/cop/style/redundant_begin.rb +6 -1
  397. data/lib/rubocop/cop/style/redundant_condition.rb +97 -24
  398. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
  399. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  400. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  401. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  402. data/lib/rubocop/cop/style/redundant_format.rb +257 -0
  403. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -3
  404. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  405. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +46 -0
  406. data/lib/rubocop/cop/style/redundant_line_continuation.rb +56 -20
  407. data/lib/rubocop/cop/style/redundant_parentheses.rb +57 -27
  408. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +8 -1
  409. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  410. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  411. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  412. data/lib/rubocop/cop/style/redundant_self.rb +9 -15
  413. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  414. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  415. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  416. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  417. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  418. data/lib/rubocop/cop/style/require_order.rb +1 -1
  419. data/lib/rubocop/cop/style/rescue_modifier.rb +18 -4
  420. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  421. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
  422. data/lib/rubocop/cop/style/safe_navigation.rb +123 -54
  423. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  424. data/lib/rubocop/cop/style/select_by_regexp.rb +14 -8
  425. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  426. data/lib/rubocop/cop/style/semicolon.rb +2 -2
  427. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  428. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  429. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  430. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  431. data/lib/rubocop/cop/style/single_line_do_end_block.rb +15 -4
  432. data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
  433. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  434. data/lib/rubocop/cop/style/sole_nested_conditional.rb +42 -106
  435. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  436. data/lib/rubocop/cop/style/string_concatenation.rb +15 -15
  437. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  438. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  439. data/lib/rubocop/cop/style/struct_inheritance.rb +9 -2
  440. data/lib/rubocop/cop/style/super_arguments.rb +66 -19
  441. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  442. data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
  443. data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
  444. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
  445. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +11 -2
  446. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  447. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  448. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  449. data/lib/rubocop/cop/style/trivial_accessors.rb +2 -2
  450. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  451. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  452. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  453. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  454. data/lib/rubocop/cop/team.rb +14 -3
  455. data/lib/rubocop/cop/util.rb +12 -5
  456. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  457. data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
  458. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  459. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  460. data/lib/rubocop/cop/variable_force/variable.rb +14 -3
  461. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  462. data/lib/rubocop/cop/variable_force.rb +5 -11
  463. data/lib/rubocop/cops_documentation_generator.rb +117 -53
  464. data/lib/rubocop/directive_comment.rb +45 -11
  465. data/lib/rubocop/ext/regexp_node.rb +0 -1
  466. data/lib/rubocop/file_finder.rb +9 -4
  467. data/lib/rubocop/formatter/disabled_config_formatter.rb +3 -2
  468. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  469. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  470. data/lib/rubocop/formatter/junit_formatter.rb +70 -23
  471. data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
  472. data/lib/rubocop/lockfile.rb +6 -4
  473. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  474. data/lib/rubocop/lsp/logger.rb +2 -2
  475. data/lib/rubocop/lsp/routes.rb +7 -23
  476. data/lib/rubocop/lsp/runtime.rb +19 -49
  477. data/lib/rubocop/lsp/server.rb +0 -3
  478. data/lib/rubocop/lsp/stdin_runner.rb +85 -0
  479. data/lib/rubocop/magic_comment.rb +11 -3
  480. data/lib/rubocop/options.rb +28 -12
  481. data/lib/rubocop/path_util.rb +15 -8
  482. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  483. data/lib/rubocop/plugin/load_error.rb +26 -0
  484. data/lib/rubocop/plugin/loader.rb +100 -0
  485. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  486. data/lib/rubocop/plugin.rb +46 -0
  487. data/lib/rubocop/rake_task.rb +4 -1
  488. data/lib/rubocop/remote_config.rb +5 -1
  489. data/lib/rubocop/result_cache.rb +15 -21
  490. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  491. data/lib/rubocop/rspec/expect_offense.rb +7 -2
  492. data/lib/rubocop/rspec/shared_contexts.rb +40 -3
  493. data/lib/rubocop/rspec/support.rb +4 -2
  494. data/lib/rubocop/runner.rb +27 -13
  495. data/lib/rubocop/server/cache.rb +52 -11
  496. data/lib/rubocop/server/cli.rb +2 -2
  497. data/lib/rubocop/server/core.rb +1 -0
  498. data/lib/rubocop/target_finder.rb +7 -2
  499. data/lib/rubocop/target_ruby.rb +36 -17
  500. data/lib/rubocop/version.rb +54 -11
  501. data/lib/rubocop/yaml_duplication_checker.rb +20 -26
  502. data/lib/rubocop.rb +36 -2
  503. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  504. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +65 -0
  505. metadata +83 -40
  506. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  507. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -3,7 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks if `return` or `return nil` is used in predicate method definitions.
6
+ # Checks for predicate method definitions that return `nil`.
7
+ # A predicate method should only return a boolean value.
7
8
  #
8
9
  # @safety
9
10
  # Autocorrection is marked as unsafe because the change of the return value
@@ -31,6 +32,24 @@ module RuboCop
31
32
  # do_something?
32
33
  # end
33
34
  #
35
+ # # bad
36
+ # def foo?
37
+ # if condition
38
+ # nil
39
+ # else
40
+ # true
41
+ # end
42
+ # end
43
+ #
44
+ # # good
45
+ # def foo?
46
+ # if condition
47
+ # false
48
+ # else
49
+ # true
50
+ # end
51
+ # end
52
+ #
34
53
  # @example AllowedMethods: ['foo?']
35
54
  # # good
36
55
  # def foo?
@@ -64,24 +83,25 @@ module RuboCop
64
83
  return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
65
84
  return unless (body = node.body)
66
85
 
67
- body.each_descendant(:return) do |return_node|
68
- register_offense(return_node, 'return false') if return_nil?(return_node)
69
- end
70
-
71
- return unless (nil_node = nil_node_at_the_end_of_method_body(body))
86
+ body.each_descendant(:return) { |return_node| handle_return(return_node) }
72
87
 
73
- register_offense(nil_node, 'false')
88
+ handle_implicit_return_values(body)
74
89
  end
75
90
  alias on_defs on_def
76
91
 
77
92
  private
78
93
 
79
- def nil_node_at_the_end_of_method_body(body)
80
- return body if body.nil_type?
81
- return unless body.begin_type?
82
- return unless (last_child = body.children.last)
94
+ def last_node_of_type(node, type)
95
+ return unless node
96
+ return node if node_type?(node, type)
97
+ return unless node.begin_type?
98
+ return unless (last_child = node.children.last)
99
+
100
+ last_child if last_child.is_a?(AST::Node) && node_type?(last_child, type)
101
+ end
83
102
 
84
- last_child if last_child.is_a?(AST::Node) && last_child.nil_type?
103
+ def node_type?(node, type)
104
+ node.type == type.to_sym
85
105
  end
86
106
 
87
107
  def register_offense(offense_node, replacement)
@@ -89,6 +109,28 @@ module RuboCop
89
109
  corrector.replace(offense_node, replacement)
90
110
  end
91
111
  end
112
+
113
+ def handle_implicit_return_values(node)
114
+ handle_if(last_node_of_type(node, :if))
115
+ handle_nil(last_node_of_type(node, :nil))
116
+ end
117
+
118
+ def handle_return(return_node)
119
+ register_offense(return_node, 'return false') if return_nil?(return_node)
120
+ end
121
+
122
+ def handle_nil(nil_node)
123
+ return unless nil_node
124
+
125
+ register_offense(nil_node, 'false')
126
+ end
127
+
128
+ def handle_if(if_node)
129
+ return unless if_node
130
+
131
+ handle_implicit_return_values(if_node.if_branch)
132
+ handle_implicit_return_values(if_node.else_branch)
133
+ end
92
134
  end
93
135
  end
94
136
  end
@@ -17,9 +17,14 @@ module RuboCop
17
17
  # `foo&.bar` can start returning `nil` as well as what the method
18
18
  # returns.
19
19
  #
20
- # The default for `MaxChainLength` is `2`
20
+ # The default for `MaxChainLength` is `2`.
21
21
  # We have limited the cop to not register an offense for method chains
22
- # that exceed this option is set.
22
+ # that exceed this option's value.
23
+ #
24
+ # NOTE: This cop will recognize offenses but not autocorrect code when the
25
+ # right hand side (RHS) of the `&&` statement is an `||` statement
26
+ # (eg. `foo && (foo.bar? || foo.baz?)`). It can be corrected
27
+ # manually by removing the `foo &&` and adding `&.` to each `foo` on the RHS.
23
28
  #
24
29
  # @safety
25
30
  # Autocorrection is unsafe because if a value is `false`, the resulting
@@ -81,7 +86,7 @@ module RuboCop
81
86
  # foo.baz = bar if foo
82
87
  # foo.baz + bar if foo
83
88
  # foo.bar > 2 if foo
84
- class SafeNavigation < Base
89
+ class SafeNavigation < Base # rubocop:disable Metrics/ClassLength
85
90
  include NilMethods
86
91
  include RangeHelp
87
92
  extend AutoCorrector
@@ -121,50 +126,127 @@ module RuboCop
121
126
  }
122
127
  PATTERN
123
128
 
129
+ # @!method and_with_rhs_or?(node)
130
+ def_node_matcher :and_with_rhs_or?, '(and _ {or (begin or)})'
131
+
124
132
  # @!method not_nil_check?(node)
125
133
  def_node_matcher :not_nil_check?, '(send (send $_ :nil?) :!)'
126
134
 
135
+ # @!method and_inside_begin?(node)
136
+ def_node_matcher :and_inside_begin?, '`(begin and ...)'
137
+
138
+ # @!method strip_begin(node)
139
+ def_node_matcher :strip_begin, '{ (begin $!begin) $!(begin) }'
140
+
127
141
  def on_if(node)
128
142
  return if allowed_if_condition?(node)
129
143
 
130
- check_node(node)
144
+ checked_variable, receiver, method_chain, _method = extract_parts_from_if(node)
145
+ return unless offending_node?(node, checked_variable, method_chain, receiver)
146
+
147
+ body = extract_if_body(node)
148
+ method_call = receiver.parent
149
+
150
+ removal_ranges = [begin_range(node, body), end_range(node, body)]
151
+
152
+ report_offense(node, method_chain, method_call, *removal_ranges) do |corrector|
153
+ corrector.insert_before(method_call.loc.dot, '&') unless method_call.safe_navigation?
154
+ end
131
155
  end
132
156
 
133
- def on_and(node)
134
- check_node(node)
157
+ def on_and(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
158
+ collect_and_clauses(node).each do |(lhs, lhs_operator_range), (rhs, _rhs_operator_range)|
159
+ lhs_not_nil_check = not_nil_check?(lhs)
160
+ lhs_receiver = lhs_not_nil_check || lhs
161
+ rhs_receiver = find_matching_receiver_invocation(strip_begin(rhs), lhs_receiver)
162
+
163
+ next if !cop_config['ConvertCodeThatCanStartToReturnNil'] && lhs_not_nil_check
164
+ next unless offending_node?(node, lhs_receiver, rhs, rhs_receiver)
165
+
166
+ # Since we are evaluating every clause in potentially a complex chain of `and` nodes,
167
+ # we need to ensure that there isn't an object check happening
168
+ lhs_method_chain = find_method_chain(lhs_receiver)
169
+ next unless lhs_method_chain == lhs_receiver || lhs_not_nil_check
170
+
171
+ report_offense(
172
+ node,
173
+ rhs, rhs_receiver,
174
+ range_with_surrounding_space(range: lhs.source_range, side: :right),
175
+ range_with_surrounding_space(range: lhs_operator_range, side: :right),
176
+ offense_range: range_between(lhs.source_range.begin_pos, rhs.source_range.end_pos)
177
+ ) do |corrector|
178
+ corrector.replace(rhs_receiver, lhs_receiver.source)
179
+ end
180
+ ignore_node(node)
181
+ end
182
+ end
183
+
184
+ def report_offense(node, rhs, rhs_receiver, *removal_ranges, offense_range: node)
185
+ add_offense(offense_range) do |corrector|
186
+ next if ignored_node?(node)
187
+
188
+ # If the RHS is an `or` we cannot safely autocorrect because in order to remove
189
+ # the non-nil check we need to add safe-navs to all clauses where the receiver is used
190
+ next if and_with_rhs_or?(node)
191
+
192
+ removal_ranges.each { |range| corrector.remove(range) }
193
+ yield corrector if block_given?
194
+
195
+ handle_comments(corrector, node, rhs)
196
+
197
+ add_safe_nav_to_all_methods_in_chain(corrector, rhs_receiver, rhs)
198
+ end
135
199
  end
136
200
 
137
201
  private
138
202
 
139
- def check_node(node)
140
- checked_variable, receiver, method_chain, method = extract_parts(node)
141
- return if receiver != checked_variable || receiver.nil?
142
- return if use_var_only_in_unless_modifier?(node, checked_variable)
143
- return if chain_length(method_chain, method) > max_chain_length
144
- return if unsafe_method_used?(method_chain, method)
145
- return if method_chain.method?(:empty?)
203
+ def find_method_chain(node)
204
+ return node unless node&.parent&.call_type?
146
205
 
147
- add_offense(node) { |corrector| autocorrect(corrector, node) }
206
+ find_method_chain(node.parent)
148
207
  end
149
208
 
150
- def use_var_only_in_unless_modifier?(node, variable)
151
- node.if_type? && node.unless? && !method_called?(variable)
209
+ def collect_and_clauses(node)
210
+ # Collect the lhs, operator and rhs of all `and` nodes
211
+ # `and` nodes can be nested and can contain `begin` nodes
212
+ # This gives us a source-ordered list of clauses that is then used to look
213
+ # for matching receivers as well as operator locations for offense and corrections
214
+ node.each_descendant(:and)
215
+ .inject(and_parts(node)) { |nodes, and_node| concat_nodes(nodes, and_node) }
216
+ .sort_by { |a| a.is_a?(RuboCop::AST::Node) ? a.source_range.begin_pos : a.begin_pos }
217
+ .each_slice(2)
218
+ .each_cons(2)
152
219
  end
153
220
 
154
- def autocorrect(corrector, node)
155
- body = extract_body(node)
156
- method_call = method_call(node)
221
+ def concat_nodes(nodes, and_node)
222
+ return nodes if and_node.each_ancestor(:block).any?
157
223
 
158
- corrector.remove(begin_range(node, body))
159
- corrector.remove(end_range(node, body))
160
- corrector.insert_before(method_call.loc.dot, '&') unless method_call.safe_navigation?
161
- handle_comments(corrector, node, method_call)
224
+ nodes.concat(and_parts(and_node))
225
+ end
162
226
 
163
- add_safe_nav_to_all_methods_in_chain(corrector, method_call, body)
227
+ def and_parts(node)
228
+ parts = [node.loc.operator]
229
+ parts << node.rhs unless and_inside_begin?(node.rhs)
230
+ parts << node.lhs unless node.lhs.and_type? || and_inside_begin?(node.lhs)
231
+ parts
164
232
  end
165
233
 
166
- def extract_body(node)
167
- if node.if_type? && node.ternary?
234
+ def offending_node?(node, lhs_receiver, rhs, rhs_receiver) # rubocop:disable Metrics/CyclomaticComplexity
235
+ return false if !matching_nodes?(lhs_receiver, rhs_receiver) || rhs_receiver.nil?
236
+ return false if use_var_only_in_unless_modifier?(node, lhs_receiver)
237
+ return false if chain_length(rhs, rhs_receiver) > max_chain_length
238
+ return false if unsafe_method_used?(rhs, rhs_receiver.parent)
239
+ return false if rhs.send_type? && rhs.method?(:empty?)
240
+
241
+ true
242
+ end
243
+
244
+ def use_var_only_in_unless_modifier?(node, variable)
245
+ node.if_type? && node.unless? && !method_called?(variable)
246
+ end
247
+
248
+ def extract_if_body(node)
249
+ if node.ternary?
168
250
  node.branches.find { |branch| !branch.nil_type? }
169
251
  else
170
252
  node.node_parts[1]
@@ -201,20 +283,6 @@ module RuboCop
201
283
  node.else? || node.elsif?
202
284
  end
203
285
 
204
- def method_call(node)
205
- _checked_variable, matching_receiver, = extract_parts(node)
206
- matching_receiver.parent
207
- end
208
-
209
- def extract_parts(node)
210
- case node.type
211
- when :if
212
- extract_parts_from_if(node)
213
- when :and
214
- extract_parts_from_and(node)
215
- end
216
- end
217
-
218
286
  def extract_parts_from_if(node)
219
287
  variable, receiver =
220
288
  if node.ternary?
@@ -230,16 +298,6 @@ module RuboCop
230
298
  [checked_variable, matching_receiver, receiver, method]
231
299
  end
232
300
 
233
- def extract_parts_from_and(node)
234
- checked_variable, rhs = *node
235
- if cop_config['ConvertCodeThatCanStartToReturnNil']
236
- checked_variable = not_nil_check?(checked_variable) || checked_variable
237
- end
238
-
239
- checked_variable, matching_receiver, method = extract_common_parts(rhs, checked_variable)
240
- [checked_variable, matching_receiver, rhs, method]
241
- end
242
-
243
301
  def extract_common_parts(method_chain, checked_variable)
244
302
  matching_receiver = find_matching_receiver_invocation(method_chain, checked_variable)
245
303
 
@@ -249,17 +307,27 @@ module RuboCop
249
307
  end
250
308
 
251
309
  def find_matching_receiver_invocation(method_chain, checked_variable)
252
- return nil unless method_chain
310
+ return nil unless method_chain.respond_to?(:receiver)
253
311
 
254
312
  receiver = method_chain.receiver
255
313
 
256
- return receiver if receiver == checked_variable
314
+ return receiver if matching_nodes?(receiver, checked_variable)
257
315
 
258
316
  find_matching_receiver_invocation(receiver, checked_variable)
259
317
  end
260
318
 
319
+ def matching_nodes?(left, right)
320
+ left == right || matching_call_nodes?(left, right)
321
+ end
322
+
323
+ def matching_call_nodes?(left, right)
324
+ return false unless left && right.respond_to?(:call_type?)
325
+
326
+ left.call_type? && right.call_type? && left.children == right.children
327
+ end
328
+
261
329
  def chain_length(method_chain, method)
262
- method.each_ancestor(:send).inject(1) do |total, ancestor|
330
+ method.each_ancestor(:call).inject(0) do |total, ancestor|
263
331
  break total + 1 if ancestor == method_chain
264
332
 
265
333
  total + 1
@@ -270,7 +338,7 @@ module RuboCop
270
338
  return true if unsafe_method?(method)
271
339
 
272
340
  method.each_ancestor(:send).any? do |ancestor|
273
- break true unless config.for_cop('Lint/SafeNavigationChain')['Enabled']
341
+ break true unless config.cop_enabled?('Lint/SafeNavigationChain')
274
342
 
275
343
  break true if unsafe_method?(ancestor)
276
344
  break true if nil_methods.include?(ancestor.method_name)
@@ -310,6 +378,7 @@ module RuboCop
310
378
  start_method.each_ancestor do |ancestor|
311
379
  break unless %i[send block].include?(ancestor.type)
312
380
  next unless ancestor.send_type?
381
+ next if ancestor.safe_navigation?
313
382
 
314
383
  corrector.insert_before(ancestor.loc.dot, '&')
315
384
 
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Enforces safe navigation chains length to not exceed the configured maximum.
7
+ # The longer the chain is, the harder it becomes to track what on it could be
8
+ # returning `nil`.
9
+ #
10
+ # There is a potential interplay with `Style/SafeNavigation` - if both are enabled
11
+ # and their settings are "incompatible", one of the cops will complain about what
12
+ # the other proposes.
13
+ #
14
+ # E.g. if `Style/SafeNavigation` is configured with `MaxChainLength: 2` (default)
15
+ # and this cop is configured with `Max: 1`, then for `foo.bar.baz if foo` the former
16
+ # will suggest `foo&.bar&.baz`, which is an offense for the latter.
17
+ #
18
+ # @example Max: 2 (default)
19
+ # # bad
20
+ # user&.address&.zip&.upcase
21
+ #
22
+ # # good
23
+ # user&.address&.zip
24
+ # user.address.zip if user
25
+ #
26
+ class SafeNavigationChainLength < Base
27
+ MSG = 'Avoid safe navigation chains longer than %<max>d calls.'
28
+
29
+ def on_csend(node)
30
+ safe_navigation_chains = safe_navigation_chains(node)
31
+ return if safe_navigation_chains.size < max
32
+
33
+ add_offense(safe_navigation_chains.last, message: format(MSG, max: max))
34
+ end
35
+
36
+ private
37
+
38
+ def safe_navigation_chains(node)
39
+ node.each_ancestor.with_object([]) do |parent, chains|
40
+ break chains unless parent.csend_type?
41
+
42
+ chains << parent
43
+ end
44
+ end
45
+
46
+ def max
47
+ cop_config['Max'] || 2
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Looks for places where an subset of an Enumerable (array,
6
+ # Looks for places where a subset of an Enumerable (array,
7
7
  # range, set, etc.; see note below) is calculated based on a `Regexp`
8
8
  # match, and suggests `grep` or `grep_v` instead.
9
9
  #
@@ -27,7 +27,7 @@ module RuboCop
27
27
  # so the correction may not be actually equivalent.
28
28
  #
29
29
  # @example
30
- # # bad (select or find_all)
30
+ # # bad (select, filter, or find_all)
31
31
  # array.select { |x| x.match? /regexp/ }
32
32
  # array.select { |x| /regexp/.match?(x) }
33
33
  # array.select { |x| x =~ /regexp/ }
@@ -47,9 +47,11 @@ module RuboCop
47
47
  include RangeHelp
48
48
 
49
49
  MSG = 'Prefer `%<replacement>s` to `%<original_method>s` with a regexp match.'
50
- RESTRICT_ON_SEND = %i[select find_all reject].freeze
51
- REPLACEMENTS = { select: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
52
- OPPOSITE_REPLACEMENTS = { select: 'grep_v', find_all: 'grep_v', reject: 'grep' }.freeze
50
+ RESTRICT_ON_SEND = %i[select filter find_all reject].freeze
51
+ REPLACEMENTS = { select: 'grep', filter: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
52
+ OPPOSITE_REPLACEMENTS = {
53
+ select: 'grep_v', filter: 'grep_v', find_all: 'grep_v', reject: 'grep'
54
+ }.freeze
53
55
  REGEXP_METHODS = %i[match? =~ !~].to_set.freeze
54
56
 
55
57
  # @!method regexp_match?(node)
@@ -57,6 +59,7 @@ module RuboCop
57
59
  {
58
60
  (block call (args (arg $_)) ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
59
61
  (numblock call $1 ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
62
+ (itblock call $_ ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
60
63
  }
61
64
  PATTERN
62
65
 
@@ -84,8 +87,9 @@ module RuboCop
84
87
  }
85
88
  PATTERN
86
89
 
87
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
90
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
88
91
  def on_send(node)
92
+ return if target_ruby_version < 2.6 && node.method?(:filter)
89
93
  return unless (block_node = node.block_node)
90
94
  return if block_node.body&.begin_type?
91
95
  return if receiver_allowed?(block_node.receiver)
@@ -99,7 +103,7 @@ module RuboCop
99
103
 
100
104
  register_offense(node, block_node, regexp, replacement)
101
105
  end
102
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
106
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
103
107
  alias on_csend on_send
104
108
 
105
109
  private
@@ -134,6 +138,7 @@ module RuboCop
134
138
  return unless (block_arg_name, regexp_method_send_node = regexp_match?(block_node))
135
139
 
136
140
  block_arg_name = :"_#{block_arg_name}" if block_node.numblock_type?
141
+
137
142
  return unless calls_lvar?(regexp_method_send_node, block_arg_name)
138
143
 
139
144
  regexp_method_send_node
@@ -147,7 +152,8 @@ module RuboCop
147
152
  return node.child_nodes.first if node.match_with_lvasgn_type?
148
153
 
149
154
  if node.receiver.lvar_type? &&
150
- (block.numblock_type? || node.receiver.source == block.first_argument.source)
155
+ (block.type?(:numblock, :itblock) ||
156
+ node.receiver.source == block.first_argument.source)
151
157
  node.first_argument
152
158
  elsif node.first_argument.lvar_type?
153
159
  node.receiver
@@ -37,33 +37,29 @@ module RuboCop
37
37
  private
38
38
 
39
39
  def check(node, var_type)
40
- var_name, rhs = *node
41
- return unless rhs
40
+ return unless (rhs = node.expression)
42
41
 
43
- if rhs.send_type?
44
- check_send_node(node, rhs, var_name, var_type)
42
+ if rhs.send_type? && rhs.arguments.one?
43
+ check_send_node(node, rhs, node.name, var_type)
45
44
  elsif rhs.operator_keyword?
46
- check_boolean_node(node, rhs, var_name, var_type)
45
+ check_boolean_node(node, rhs, node.name, var_type)
47
46
  end
48
47
  end
49
48
 
50
49
  def check_send_node(node, rhs, var_name, var_type)
51
- receiver, method_name, *_args = *rhs
52
- return unless OPS.include?(method_name)
50
+ return unless OPS.include?(rhs.method_name)
53
51
 
54
52
  target_node = s(var_type, var_name)
55
- return unless receiver == target_node
53
+ return unless rhs.receiver == target_node
56
54
 
57
- add_offense(node, message: format(MSG, method: method_name)) do |corrector|
55
+ add_offense(node, message: format(MSG, method: rhs.method_name)) do |corrector|
58
56
  autocorrect(corrector, node)
59
57
  end
60
58
  end
61
59
 
62
60
  def check_boolean_node(node, rhs, var_name, var_type)
63
- first_operand, _second_operand = *rhs
64
-
65
61
  target_node = s(var_type, var_name)
66
- return unless first_operand == target_node
62
+ return unless rhs.lhs == target_node
67
63
 
68
64
  operator = rhs.loc.operator.source
69
65
  add_offense(node, message: format(MSG, method: operator)) do |corrector|
@@ -72,7 +68,7 @@ module RuboCop
72
68
  end
73
69
 
74
70
  def autocorrect(corrector, node)
75
- _var_name, rhs = *node
71
+ rhs = node.expression
76
72
 
77
73
  if rhs.send_type?
78
74
  autocorrect_send_node(corrector, node, rhs)
@@ -82,13 +78,11 @@ module RuboCop
82
78
  end
83
79
 
84
80
  def autocorrect_send_node(corrector, node, rhs)
85
- _receiver, method_name, args = *rhs
86
- apply_autocorrect(corrector, node, rhs, method_name.to_s, args)
81
+ apply_autocorrect(corrector, node, rhs, rhs.method_name, rhs.first_argument)
87
82
  end
88
83
 
89
84
  def autocorrect_boolean_node(corrector, node, rhs)
90
- _first_operand, second_operand = *rhs
91
- apply_autocorrect(corrector, node, rhs, rhs.loc.operator.source, second_operand)
85
+ apply_autocorrect(corrector, node, rhs, rhs.loc.operator.source, rhs.rhs)
92
86
  end
93
87
 
94
88
  def apply_autocorrect(corrector, node, rhs, operator, new_rhs)
@@ -141,7 +141,7 @@ module RuboCop
141
141
 
142
142
  def expressions_per_line(exprs)
143
143
  # create a map matching lines to the number of expressions on them
144
- exprs_lines = exprs.map(&:first_line)
144
+ exprs_lines = exprs.map(&:last_line)
145
145
  exprs_lines.group_by(&:itself)
146
146
  end
147
147
 
@@ -164,7 +164,7 @@ module RuboCop
164
164
 
165
165
  ast = processed_source.ast
166
166
  @range_nodes = ast.range_type? ? [ast] : []
167
- @range_nodes.concat(ast.each_descendant(:irange, :erange).to_a)
167
+ @range_nodes.concat(ast.each_descendant(:range).to_a)
168
168
  end
169
169
  end
170
170
  end
@@ -68,7 +68,7 @@ module RuboCop
68
68
  def on_send(node)
69
69
  return if allow_send? && !node.method?(:public_send)
70
70
  return unless (first_argument = node.first_argument)
71
- return unless STATIC_METHOD_NAME_NODE_TYPES.include?(first_argument.type)
71
+ return unless first_argument.type?(*STATIC_METHOD_NAME_NODE_TYPES)
72
72
 
73
73
  offense_range = offense_range(node)
74
74
  method_name = first_argument.value
@@ -83,6 +83,7 @@ module RuboCop
83
83
  end
84
84
  end
85
85
  end
86
+ alias on_csend on_send
86
87
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
87
88
 
88
89
  private
@@ -122,10 +122,9 @@ module RuboCop
122
122
  def on_rescue(node)
123
123
  return unless style == :semantic
124
124
 
125
- begin_node, *rescue_nodes, _else_node = *node
126
- check_scope(:raise, begin_node)
125
+ check_scope(:raise, node.body)
127
126
 
128
- rescue_nodes.each do |rescue_node|
127
+ node.resbody_branches.each do |rescue_node|
129
128
  check_scope(:fail, rescue_node)
130
129
  allow(:raise, rescue_node)
131
130
  end
@@ -33,22 +33,19 @@ module RuboCop
33
33
  #
34
34
  class SingleArgumentDig < Base
35
35
  extend AutoCorrector
36
+ include DigHelp
36
37
 
37
38
  MSG = 'Use `%<receiver>s[%<argument>s]` instead of `%<original>s`.'
38
39
  RESTRICT_ON_SEND = %i[dig].freeze
39
40
  IGNORED_ARGUMENT_TYPES = %i[block_pass forwarded_restarg forwarded_args hash].freeze
40
41
 
41
- # @!method single_argument_dig?(node)
42
- def_node_matcher :single_argument_dig?, <<~PATTERN
43
- (send _ :dig $!splat)
44
- PATTERN
45
-
46
42
  def on_send(node)
47
43
  return unless node.receiver
48
44
 
49
45
  expression = single_argument_dig?(node)
50
46
  return unless expression
51
47
  return if IGNORED_ARGUMENT_TYPES.include?(expression.type)
48
+ return if ignore_dig_chain?(node)
52
49
 
53
50
  receiver = node.receiver.source
54
51
  argument = expression.source
@@ -63,6 +60,13 @@ module RuboCop
63
60
 
64
61
  ignore_node(node)
65
62
  end
63
+
64
+ private
65
+
66
+ def ignore_dig_chain?(node)
67
+ dig_chain_enabled? &&
68
+ (dig?(node.receiver) || dig?(node.parent))
69
+ end
66
70
  end
67
71
  end
68
72
  end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # parameters.
11
11
  #
12
12
  # Configuration option: Methods
13
- # Should be set to use this cop. Array of hashes, where each key is the
13
+ # Should be set to use this cop. `Array` of hashes, where each key is the
14
14
  # method name and value - array of argument names.
15
15
  #
16
16
  # @example Methods: [{reduce: %w[a b]}]