rubocop 1.72.1 → 1.81.7

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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -18
  3. data/config/default.yml +240 -65
  4. data/config/internal_affairs.yml +20 -0
  5. data/config/obsoletion.yml +8 -3
  6. data/exe/rubocop +1 -8
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  8. data/lib/rubocop/cli.rb +19 -4
  9. data/lib/rubocop/config.rb +35 -6
  10. data/lib/rubocop/config_loader.rb +8 -40
  11. data/lib/rubocop/config_loader_resolver.rb +9 -7
  12. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  13. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  14. data/lib/rubocop/config_obsoletion.rb +46 -2
  15. data/lib/rubocop/config_store.rb +5 -0
  16. data/lib/rubocop/config_validator.rb +7 -6
  17. data/lib/rubocop/cop/autocorrect_logic.rb +22 -14
  18. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  19. data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
  20. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  21. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  22. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  23. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +37 -15
  24. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  25. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  26. data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
  27. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
  28. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
  29. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +92 -0
  30. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  31. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  32. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +6 -1
  33. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  34. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  35. data/lib/rubocop/cop/layout/block_alignment.rb +2 -2
  36. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  37. data/lib/rubocop/cop/layout/class_structure.rb +36 -1
  38. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  39. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  40. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  41. data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
  42. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  43. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +32 -14
  44. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  45. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
  46. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  47. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  48. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  49. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  50. data/lib/rubocop/cop/layout/hash_alignment.rb +4 -7
  51. data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
  52. data/lib/rubocop/cop/layout/leading_comment_space.rb +13 -1
  53. data/lib/rubocop/cop/layout/line_length.rb +43 -10
  54. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  55. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  56. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
  57. data/lib/rubocop/cop/layout/redundant_line_break.rb +9 -5
  58. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +11 -5
  59. data/lib/rubocop/cop/layout/space_after_semicolon.rb +10 -0
  60. data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
  61. data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
  62. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  63. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -38
  64. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +12 -3
  65. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  66. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
  67. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  68. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  69. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
  70. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  71. data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -5
  72. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  73. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +13 -7
  74. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  75. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  76. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
  77. data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -23
  78. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  79. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  80. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  81. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  82. data/lib/rubocop/cop/lint/float_comparison.rb +32 -10
  83. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  84. data/lib/rubocop/cop/lint/literal_as_condition.rb +124 -10
  85. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
  86. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  87. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  88. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  89. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
  90. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  91. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  92. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  93. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  94. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
  95. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +43 -13
  96. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  97. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  98. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  99. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  100. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  101. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  102. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
  103. data/lib/rubocop/cop/lint/self_assignment.rb +31 -5
  104. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  105. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -1
  106. data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
  107. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  108. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  109. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  110. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
  111. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -0
  112. data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
  113. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  114. data/lib/rubocop/cop/lint/useless_access_modifier.rb +30 -4
  115. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -0
  116. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +9 -12
  117. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  118. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
  119. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  120. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  121. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
  122. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  123. data/lib/rubocop/cop/lint/void.rb +16 -2
  124. data/lib/rubocop/cop/message_annotator.rb +7 -3
  125. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  126. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  127. data/lib/rubocop/cop/metrics/method_length.rb +1 -0
  128. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  129. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  130. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  131. data/lib/rubocop/cop/mixin/check_line_breakable.rb +3 -3
  132. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
  133. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  134. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  135. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  136. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  137. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  138. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
  139. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  140. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
  141. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
  142. data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
  143. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -0
  144. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
  145. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  146. data/lib/rubocop/cop/mixin/range_help.rb +12 -0
  147. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  148. data/lib/rubocop/cop/mixin/trailing_comma.rb +18 -2
  149. data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
  150. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  151. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  152. data/lib/rubocop/cop/naming/method_name.rb +187 -15
  153. data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
  154. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
  155. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  156. data/lib/rubocop/cop/registry.rb +9 -6
  157. data/lib/rubocop/cop/security/eval.rb +2 -1
  158. data/lib/rubocop/cop/security/json_load.rb +33 -11
  159. data/lib/rubocop/cop/security/open.rb +1 -0
  160. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
  161. data/lib/rubocop/cop/style/accessor_grouping.rb +32 -6
  162. data/lib/rubocop/cop/style/arguments_forwarding.rb +21 -24
  163. data/lib/rubocop/cop/style/array_intersect.rb +113 -38
  164. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  165. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  166. data/lib/rubocop/cop/style/block_delimiters.rb +3 -2
  167. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  168. data/lib/rubocop/cop/style/class_and_module_children.rb +48 -10
  169. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  170. data/lib/rubocop/cop/style/collection_methods.rb +1 -0
  171. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  172. data/lib/rubocop/cop/style/combinable_loops.rb +1 -0
  173. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  174. data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
  175. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  176. data/lib/rubocop/cop/style/conditional_assignment.rb +26 -8
  177. data/lib/rubocop/cop/style/constant_visibility.rb +14 -9
  178. data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
  179. data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
  180. data/lib/rubocop/cop/style/dig_chain.rb +1 -1
  181. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  182. data/lib/rubocop/cop/style/empty_literal.rb +4 -0
  183. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  184. data/lib/rubocop/cop/style/endless_method.rb +176 -18
  185. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  186. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  187. data/lib/rubocop/cop/style/explicit_block_argument.rb +3 -3
  188. data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
  189. data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
  190. data/lib/rubocop/cop/style/float_division.rb +15 -1
  191. data/lib/rubocop/cop/style/for.rb +1 -0
  192. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  193. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  194. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  195. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  196. data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
  197. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -2
  198. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  199. data/lib/rubocop/cop/style/hash_syntax.rb +4 -1
  200. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  201. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  202. data/lib/rubocop/cop/style/identical_conditional_branches.rb +3 -3
  203. data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
  204. data/lib/rubocop/cop/style/if_unless_modifier.rb +35 -8
  205. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
  206. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  207. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  208. data/lib/rubocop/cop/style/inverse_methods.rb +10 -6
  209. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  210. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  211. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  212. data/lib/rubocop/cop/style/it_block_parameter.rb +121 -0
  213. data/lib/rubocop/cop/style/keyword_parameters_order.rb +13 -7
  214. data/lib/rubocop/cop/style/lambda.rb +1 -0
  215. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  216. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  217. data/lib/rubocop/cop/style/map_into_array.rb +4 -1
  218. data/lib/rubocop/cop/style/map_to_hash.rb +12 -3
  219. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  220. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +9 -8
  221. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
  222. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
  223. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  224. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  225. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  226. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  227. data/lib/rubocop/cop/style/next.rb +44 -0
  228. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  229. data/lib/rubocop/cop/style/object_then.rb +1 -0
  230. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
  231. data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
  232. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  233. data/lib/rubocop/cop/style/proc.rb +1 -0
  234. data/lib/rubocop/cop/style/raise_args.rb +8 -8
  235. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  236. data/lib/rubocop/cop/style/redundant_begin.rb +35 -0
  237. data/lib/rubocop/cop/style/redundant_condition.rb +57 -0
  238. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
  239. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  240. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  241. data/lib/rubocop/cop/style/redundant_format.rb +79 -18
  242. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  243. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  244. data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -4
  245. data/lib/rubocop/cop/style/redundant_parentheses.rb +73 -18
  246. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  247. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  248. data/lib/rubocop/cop/style/redundant_self.rb +9 -5
  249. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
  250. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  251. data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
  252. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
  253. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  254. data/lib/rubocop/cop/style/safe_navigation.rb +61 -14
  255. data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
  256. data/lib/rubocop/cop/style/semicolon.rb +23 -7
  257. data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
  258. data/lib/rubocop/cop/style/single_line_methods.rb +10 -7
  259. data/lib/rubocop/cop/style/sole_nested_conditional.rb +75 -101
  260. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  261. data/lib/rubocop/cop/style/string_concatenation.rb +18 -15
  262. data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
  263. data/lib/rubocop/cop/style/super_arguments.rb +1 -2
  264. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  265. data/lib/rubocop/cop/style/symbol_proc.rb +3 -1
  266. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -0
  267. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
  268. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  269. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  270. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  271. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  272. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  273. data/lib/rubocop/cop/team.rb +1 -1
  274. data/lib/rubocop/cop/util.rb +1 -1
  275. data/lib/rubocop/cop/utils/format_string.rb +15 -2
  276. data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
  277. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  278. data/lib/rubocop/cop/variable_force/variable.rb +3 -8
  279. data/lib/rubocop/cop/variable_force.rb +26 -9
  280. data/lib/rubocop/cops_documentation_generator.rb +23 -7
  281. data/lib/rubocop/directive_comment.rb +1 -1
  282. data/lib/rubocop/ext/regexp_node.rb +0 -1
  283. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -5
  284. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  285. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  286. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  287. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  288. data/lib/rubocop/formatter/pacman_formatter.rb +2 -1
  289. data/lib/rubocop/lsp/diagnostic.rb +25 -24
  290. data/lib/rubocop/lsp/routes.rb +65 -9
  291. data/lib/rubocop/lsp/runtime.rb +5 -5
  292. data/lib/rubocop/lsp/server.rb +2 -2
  293. data/lib/rubocop/lsp/stdin_runner.rb +3 -17
  294. data/lib/rubocop/magic_comment.rb +8 -0
  295. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  296. data/lib/rubocop/plugin/configuration_integrator.rb +2 -0
  297. data/lib/rubocop/plugin/load_error.rb +1 -1
  298. data/lib/rubocop/plugin.rb +9 -2
  299. data/lib/rubocop/result_cache.rb +14 -12
  300. data/lib/rubocop/rspec/cop_helper.rb +6 -1
  301. data/lib/rubocop/rspec/expect_offense.rb +9 -3
  302. data/lib/rubocop/rspec/shared_contexts.rb +34 -0
  303. data/lib/rubocop/rspec/support.rb +3 -0
  304. data/lib/rubocop/runner.rb +10 -4
  305. data/lib/rubocop/server/cache.rb +17 -12
  306. data/lib/rubocop/server/client_command/base.rb +10 -0
  307. data/lib/rubocop/server/client_command/exec.rb +2 -1
  308. data/lib/rubocop/server/client_command/start.rb +11 -1
  309. data/lib/rubocop/target_finder.rb +13 -9
  310. data/lib/rubocop/target_ruby.rb +11 -2
  311. data/lib/rubocop/version.rb +14 -7
  312. data/lib/rubocop.rb +17 -2
  313. data/lib/ruby_lsp/rubocop/addon.rb +25 -10
  314. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +57 -5
  315. metadata +24 -8
  316. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Prefer `Enumerable` predicate methods over expressions with `count`.
7
+ #
8
+ # The cop checks calls to `count` without arguments, or with a
9
+ # block. It doesn't register offenses for `count` with a positional
10
+ # argument because its behavior differs from predicate methods (`count`
11
+ # matches the argument using `==`, while `any?`, `none?` and `one?` use
12
+ # `===`).
13
+ #
14
+ # NOTE: This cop doesn't check `length` and `size` methods because they
15
+ # would yield false positives. For example, `String` implements `length`
16
+ # and `size`, but it doesn't include `Enumerable`.
17
+ #
18
+ # @safety
19
+ # The cop is unsafe because receiver might not include `Enumerable`, or
20
+ # it has nonstandard implementation of `count` or any replacement
21
+ # methods.
22
+ #
23
+ # It's also unsafe because for collections with falsey values, expressions
24
+ # with `count` without a block return a different result than methods `any?`,
25
+ # `none?` and `one?`:
26
+ #
27
+ # [source,ruby]
28
+ # ----
29
+ # [nil, false].count.positive?
30
+ # [nil].count == 1
31
+ # # => true
32
+ #
33
+ # [nil, false].any?
34
+ # [nil].one?
35
+ # # => false
36
+ #
37
+ # [nil].count == 0
38
+ # # => false
39
+ #
40
+ # [nil].none?
41
+ # # => true
42
+ # ----
43
+ #
44
+ # Autocorrection is unsafe when replacement methods don't iterate over
45
+ # every element in collection and the given block runs side effects:
46
+ #
47
+ # [source,ruby]
48
+ # ----
49
+ # x.count(&:method_with_side_effects).positive?
50
+ # # calls `method_with_side_effects` on every element
51
+ #
52
+ # x.any?(&:method_with_side_effects)
53
+ # # calls `method_with_side_effects` until first element returns a truthy value
54
+ # ----
55
+ #
56
+ # @example
57
+ #
58
+ # # bad
59
+ # x.count.positive?
60
+ # x.count > 0
61
+ # x.count != 0
62
+ #
63
+ # x.count(&:foo?).positive?
64
+ # x.count { |item| item.foo? }.positive?
65
+ #
66
+ # # good
67
+ # x.any?
68
+ #
69
+ # x.any?(&:foo?)
70
+ # x.any? { |item| item.foo? }
71
+ #
72
+ # # bad
73
+ # x.count.zero?
74
+ # x.count == 0
75
+ #
76
+ # # good
77
+ # x.none?
78
+ #
79
+ # # bad
80
+ # x.count == 1
81
+ # x.one?
82
+ #
83
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
84
+ #
85
+ # # good
86
+ # x.count > 1
87
+ #
88
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
89
+ #
90
+ # # bad
91
+ # x.count > 1
92
+ #
93
+ # # good
94
+ # x.many?
95
+ #
96
+ class CollectionQuerying < Base
97
+ include RangeHelp
98
+ extend AutoCorrector
99
+
100
+ MSG = 'Use `%<prefer>s` instead.'
101
+
102
+ RESTRICT_ON_SEND = %i[positive? > != zero? ==].freeze
103
+
104
+ REPLACEMENTS = {
105
+ [:positive?, nil] => :any?,
106
+ [:>, 0] => :any?,
107
+ [:!=, 0] => :any?,
108
+ [:zero?, nil] => :none?,
109
+ [:==, 0] => :none?,
110
+ [:==, 1] => :one?,
111
+ [:>, 1] => :many?
112
+ }.freeze
113
+
114
+ # @!method count_predicate(node)
115
+ def_node_matcher :count_predicate, <<~PATTERN
116
+ (send
117
+ {
118
+ (any_block $(call !nil? :count) _ _)
119
+ $(call !nil? :count (block-pass _)?)
120
+ }
121
+ {
122
+ :positive? |
123
+ :> (int 0) |
124
+ :!= (int 0) |
125
+ :zero? |
126
+ :== (int 0) |
127
+ :== (int 1) |
128
+ :> (int 1)
129
+ })
130
+ PATTERN
131
+
132
+ def on_send(node)
133
+ return unless (count_node = count_predicate(node))
134
+
135
+ replacement_method = replacement_method(node)
136
+
137
+ return unless replacement_supported?(replacement_method)
138
+
139
+ offense_range = count_node.loc.selector.join(node.source_range.end)
140
+ add_offense(offense_range,
141
+ message: format(MSG, prefer: replacement_method)) do |corrector|
142
+ corrector.replace(count_node.loc.selector, replacement_method)
143
+ corrector.remove(removal_range(node))
144
+ end
145
+ end
146
+
147
+ private
148
+
149
+ def replacement_method(node)
150
+ REPLACEMENTS.fetch([node.method_name, node.first_argument&.value])
151
+ end
152
+
153
+ def replacement_supported?(method_name)
154
+ return true if active_support_extensions_enabled?
155
+
156
+ method_name != :many?
157
+ end
158
+
159
+ def removal_range(node)
160
+ range = (node.loc.dot || node.loc.selector).join(node.source_range.end)
161
+
162
+ range_with_surrounding_space(range, side: :left)
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -80,6 +80,7 @@ module RuboCop
80
80
  # rubocop:enable Metrics/CyclomaticComplexity
81
81
 
82
82
  alias on_numblock on_block
83
+ alias on_itblock on_block
83
84
 
84
85
  def on_for(node)
85
86
  return unless node.parent&.begin_type?
@@ -173,7 +173,7 @@ module RuboCop
173
173
  end
174
174
 
175
175
  def preferred_delimiters_config
176
- config.for_cop('Style/PercentLiteralDelimiters') ['PreferredDelimiters']
176
+ config.for_cop('Style/PercentLiteralDelimiters')['PreferredDelimiters']
177
177
  end
178
178
  end
179
179
  end
@@ -9,8 +9,8 @@ module RuboCop
9
9
  # These keywords are: `class`, `module`, `def`, `begin`, `end`.
10
10
  #
11
11
  # Note that some comments
12
- # (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`)
13
- # and RBS::Inline annotation comments are allowed.
12
+ # (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`),
13
+ # RBS::Inline annotation, and Steep annotation (`steep:ignore`) are allowed.
14
14
  #
15
15
  # Autocorrection removes comments from `end` keyword and keeps comments
16
16
  # for `class`, `module`, `def` and `begin` above the keyword.
@@ -57,8 +57,10 @@ module RuboCop
57
57
 
58
58
  REGEXP = /(?<keyword>\S+).*#/.freeze
59
59
 
60
- SUBCLASS_DEFINITION = /\A\s*class\s+\w+\s*<\s*\w+/.freeze
61
- METHOD_DEFINITION = /\A\s*def\s/.freeze
60
+ SUBCLASS_DEFINITION = /\A\s*class\s+(\w|::)+\s*<\s*(\w|::)+/.freeze
61
+ METHOD_OR_END_DEFINITIONS = /\A\s*(def\s|end)/.freeze
62
+
63
+ STEEP_REGEXP = /#\ssteep:ignore(\s|\z)/.freeze
62
64
 
63
65
  def on_new_investigation
64
66
  processed_source.comments.each do |comment|
@@ -86,6 +88,7 @@ module RuboCop
86
88
  def offensive?(comment)
87
89
  line = source_line(comment)
88
90
  return false if rbs_inline_annotation?(line, comment)
91
+ return false if steep_annotation?(comment)
89
92
 
90
93
  KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
91
94
  ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
@@ -99,12 +102,16 @@ module RuboCop
99
102
  case line
100
103
  when SUBCLASS_DEFINITION
101
104
  comment.text.start_with?(/#\[.+\]/)
102
- when METHOD_DEFINITION
105
+ when METHOD_OR_END_DEFINITIONS
103
106
  comment.text.start_with?('#:')
104
107
  else
105
108
  false
106
109
  end
107
110
  end
111
+
112
+ def steep_annotation?(comment)
113
+ comment.text.match?(STEEP_REGEXP)
114
+ end
108
115
  end
109
116
  end
110
117
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for logical comparison which can be replaced with `Comparable#between?`.
7
+ #
8
+ # NOTE: `Comparable#between?` is on average slightly slower than logical comparison,
9
+ # although the difference generally isn't observable. If you require maximum
10
+ # performance, consider using logical comparison.
11
+ #
12
+ # @safety
13
+ # This cop is unsafe because the receiver may not respond to `between?`.
14
+ #
15
+ # @example
16
+ #
17
+ # # bad
18
+ # x >= min && x <= max
19
+ #
20
+ # # bad
21
+ # x <= max && x >= min
22
+ #
23
+ # # good
24
+ # x.between?(min, max)
25
+ #
26
+ class ComparableBetween < Base
27
+ extend AutoCorrector
28
+
29
+ MSG = 'Prefer `%<prefer>s` over logical comparison.'
30
+
31
+ # @!method logical_comparison_between_by_min_first?(node)
32
+ def_node_matcher :logical_comparison_between_by_min_first?, <<~PATTERN
33
+ (and
34
+ (send
35
+ {$_value :>= $_min | $_min :<= $_value})
36
+ (send
37
+ {$_value :<= $_max | $_max :>= $_value}))
38
+ PATTERN
39
+
40
+ # @!method logical_comparison_between_by_max_first?(node)
41
+ def_node_matcher :logical_comparison_between_by_max_first?, <<~PATTERN
42
+ (and
43
+ (send
44
+ {$_value :<= $_max | $_max :>= $_value})
45
+ (send
46
+ {$_value :>= $_min | $_min :<= $_value}))
47
+ PATTERN
48
+
49
+ def on_and(node)
50
+ logical_comparison_between_by_min_first?(node) do |*args|
51
+ min_and_value, max_and_value = args.each_slice(2).to_a
52
+
53
+ register_offense(node, min_and_value, max_and_value)
54
+ end
55
+
56
+ logical_comparison_between_by_max_first?(node) do |*args|
57
+ max_and_value, min_and_value = args.each_slice(2).to_a
58
+
59
+ register_offense(node, min_and_value, max_and_value)
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def register_offense(node, min_and_value, max_and_value)
66
+ value = (min_and_value & max_and_value).first
67
+ min = min_and_value.find { _1 != value } || value
68
+ max = max_and_value.find { _1 != value } || value
69
+
70
+ prefer = "#{value.source}.between?(#{min.source}, #{max.source})"
71
+ add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
72
+ corrector.replace(node, prefer)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -111,7 +111,7 @@ module RuboCop
111
111
  end
112
112
  end
113
113
 
114
- # Check for `if` and `case` statements where each branch is used for
114
+ # Checks for `if` and `case` statements where each branch is used for
115
115
  # both the assignment and comparison of the same variable
116
116
  # when using the return of the condition can be used instead.
117
117
  #
@@ -314,6 +314,7 @@ module RuboCop
314
314
 
315
315
  def assignment_node(node)
316
316
  assignment = node.send_type? ? node.last_argument : node.expression
317
+ return unless assignment
317
318
 
318
319
  # ignore pseudo-assignments without rhs in for nodes
319
320
  return if node.parent&.for_type?
@@ -436,26 +437,41 @@ module RuboCop
436
437
  # Helper module to provide common methods to ConditionalAssignment
437
438
  # correctors
438
439
  module ConditionalCorrectorHelper
440
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
439
441
  def remove_whitespace_in_branches(corrector, branch, condition, column)
440
442
  branch.each_node do |child|
441
443
  next if child.source_range.nil?
444
+ next if child.parent.dstr_type?
442
445
 
443
446
  white_space = white_space_range(child, column)
444
- corrector.remove(white_space) if white_space.source.strip.empty?
447
+ corrector.remove(white_space) if white_space
445
448
  end
446
449
 
447
- [condition.loc.else, condition.loc.end].each do |loc|
448
- next unless loc
449
-
450
- corrector.remove_preceding(loc, loc.column - column)
450
+ if condition.loc.else && !same_line?(condition.else_branch, condition)
451
+ corrector.remove_preceding(condition.loc.else, condition.loc.else.column - column)
451
452
  end
453
+
454
+ return unless condition.loc.end && !same_line?(
455
+ condition.branches.last.parent.else_branch, condition.loc.end
456
+ )
457
+
458
+ corrector.remove_preceding(condition.loc.end, condition.loc.end.column - column)
459
+ end
460
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
461
+
462
+ def same_line?(node1, node2)
463
+ RuboCop::Cop::Util.same_line?(node1, node2)
452
464
  end
453
465
 
454
466
  def white_space_range(node, column)
455
467
  expression = node.source_range
456
- begin_pos = expression.begin_pos - (expression.column - column - 2)
468
+ end_pos = expression.begin_pos
469
+ begin_pos = end_pos - (expression.column - column - 2)
470
+
471
+ return nil if begin_pos > end_pos
457
472
 
458
- Parser::Source::Range.new(expression.source_buffer, begin_pos, expression.begin_pos)
473
+ white_space = Parser::Source::Range.new(expression.source_buffer, begin_pos, end_pos)
474
+ white_space if white_space.source.strip.empty?
459
475
  end
460
476
 
461
477
  def assignment(node)
@@ -595,6 +611,8 @@ module RuboCop
595
611
 
596
612
  return unless (branch_else = branch.parent.loc.else)
597
613
 
614
+ return if same_line?(branch_else, condition)
615
+
598
616
  corrector.remove_preceding(branch_else, branch_else.column - column)
599
617
  end
600
618
  end
@@ -48,6 +48,11 @@ module RuboCop
48
48
  MSG = 'Explicitly make `%<constant_name>s` public or private using ' \
49
49
  'either `#public_constant` or `#private_constant`.'
50
50
 
51
+ # @!method visibility_declaration_for(node)
52
+ def_node_matcher :visibility_declaration_for, <<~PATTERN
53
+ (send nil? {:public_constant :private_constant} $...)
54
+ PATTERN
55
+
51
56
  def on_casgn(node)
52
57
  return unless class_or_module_scope?(node)
53
58
  return if visibility_declaration?(node)
@@ -77,20 +82,20 @@ module RuboCop
77
82
  end
78
83
  end
79
84
 
85
+ # rubocop:disable Metrics/AbcSize
80
86
  def visibility_declaration?(node)
81
87
  node.parent.each_child_node(:send).any? do |child|
82
- visibility_declaration_for?(child, node.name)
83
- end
84
- end
88
+ next false unless (arguments = visibility_declaration_for(child))
85
89
 
86
- # @!method visibility_declaration_for?(node, const_name)
87
- def_node_matcher :visibility_declaration_for?, <<~PATTERN
88
- (send nil? {:public_constant :private_constant} ({sym str} #match_name?(%1)))
89
- PATTERN
90
+ arguments = arguments.first.children.first.to_a if arguments.first&.splat_type?
91
+ constant_values = arguments.map do |argument|
92
+ argument.value.to_sym if argument.respond_to?(:value)
93
+ end
90
94
 
91
- def match_name?(name, constant_name)
92
- name.to_sym == constant_name.to_sym
95
+ constant_values.include?(node.name)
96
+ end
93
97
  end
98
+ # rubocop:enable Metrics/AbcSize
94
99
  end
95
100
  end
96
101
  end
@@ -4,6 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for inheritance from `Data.define` to avoid creating the anonymous parent class.
7
+ # Inheriting from `Data.define` adds a superfluous level in inheritance tree.
7
8
  #
8
9
  # @safety
9
10
  # Autocorrection is unsafe because it will change the inheritance
@@ -17,12 +18,18 @@ module RuboCop
17
18
  # end
18
19
  # end
19
20
  #
21
+ # Person.ancestors
22
+ # # => [Person, #<Class:0x000000010b4e14a0>, Data, (...)]
23
+ #
20
24
  # # good
21
25
  # Person = Data.define(:first_name, :last_name) do
22
26
  # def age
23
27
  # 42
24
28
  # end
25
29
  # end
30
+ #
31
+ # Person.ancestors
32
+ # # => [Person, Data, (...)]
26
33
  class DataInheritance < Base
27
34
  include RangeHelp
28
35
  extend AutoCorrector
@@ -25,8 +25,9 @@ module RuboCop
25
25
  # # good
26
26
  # def foo = do_something
27
27
  #
28
- # # good (without parentheses it's a syntax error)
28
+ # # good - without parentheses it's a syntax error
29
29
  # def foo() do_something end
30
+ # def foo()=do_something
30
31
  #
31
32
  # # bad
32
33
  # def Baz.foo()
@@ -38,19 +39,31 @@ module RuboCop
38
39
  # do_something
39
40
  # end
40
41
  class DefWithParentheses < Base
42
+ include RangeHelp
41
43
  extend AutoCorrector
42
44
 
43
45
  MSG = "Omit the parentheses in defs when the method doesn't accept any arguments."
44
46
 
45
47
  def on_def(node)
46
- return if node.single_line? && !node.endless?
47
- return unless !node.arguments? && (node_arguments = node.arguments.source_range)
48
+ return unless !node.arguments? && (arguments_range = node.arguments.source_range)
49
+ return if parentheses_required?(node, arguments_range)
48
50
 
49
- add_offense(node_arguments) do |corrector|
50
- corrector.remove(node_arguments)
51
+ add_offense(arguments_range) do |corrector|
52
+ corrector.remove(arguments_range)
51
53
  end
52
54
  end
53
55
  alias on_defs on_def
56
+
57
+ private
58
+
59
+ def parentheses_required?(node, arguments_range)
60
+ return true if node.single_line? && !node.endless?
61
+
62
+ end_pos = arguments_range.end.end_pos
63
+ token_after_argument = range_between(end_pos, end_pos + 1).source
64
+
65
+ token_after_argument == '='
66
+ end
54
67
  end
55
68
  end
56
69
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Check for chained `dig` calls that can be collapsed into a single `dig`.
6
+ # Checks for chained `dig` calls that can be collapsed into a single `dig`.
7
7
  #
8
8
  # @safety
9
9
  # This cop is unsafe because it cannot be guaranteed that the receiver
@@ -96,20 +96,20 @@ module RuboCop
96
96
  elsif last_child.type?(:pair, :hash) || last_child.parent.array_type?
97
97
  false
98
98
  else
99
- last_child.last_line <= node.last_line
99
+ last_child.first_line <= node.first_line
100
100
  end
101
101
  end
102
102
 
103
103
  def find_def_node_from_ascendant(node)
104
104
  return unless (parent = node.parent)
105
- return parent if parent.type?(:def, :defs)
105
+ return parent if parent.any_def_type?
106
106
  return node.parent.child_nodes.first if define_method?(parent)
107
107
 
108
108
  find_def_node_from_ascendant(node.parent)
109
109
  end
110
110
 
111
111
  def define_method?(node)
112
- return false unless node.block_type?
112
+ return false unless node.any_block_type?
113
113
 
114
114
  child = node.child_nodes.first
115
115
  return false unless child.send_type?
@@ -6,6 +6,10 @@ module RuboCop
6
6
  # Checks for the use of a method, the result of which
7
7
  # would be a literal, like an empty array, hash, or string.
8
8
  #
9
+ # NOTE: When frozen string literals are enabled, `String.new`
10
+ # isn't corrected to an empty string since the former is
11
+ # mutable and the latter would be frozen.
12
+ #
9
13
  # @example
10
14
  # # bad
11
15
  # a = Array.new
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for empty strings being assigned inside string interpolation.
7
+ #
8
+ # Empty strings are a meaningless outcome inside of string interpolation, so we remove them.
9
+ # Alternatively, when configured to do so, we prioritise using empty strings.
10
+ #
11
+ # While this cop would also apply to variables that are only going to be used as strings,
12
+ # RuboCop can't detect that, so we only check inside of string interpolation.
13
+ #
14
+ # @example EnforcedStyle: trailing_conditional (default)
15
+ # # bad
16
+ # "#{condition ? 'foo' : ''}"
17
+ #
18
+ # # good
19
+ # "#{'foo' if condition}"
20
+ #
21
+ # # bad
22
+ # "#{condition ? '' : 'foo'}"
23
+ #
24
+ # # good
25
+ # "#{'foo' unless condition}"
26
+ #
27
+ # @example EnforcedStyle: ternary
28
+ # # bad
29
+ # "#{'foo' if condition}"
30
+ #
31
+ # # good
32
+ # "#{condition ? 'foo' : ''}"
33
+ #
34
+ # # bad
35
+ # "#{'foo' unless condition}"
36
+ #
37
+ # # good
38
+ # "#{condition ? '' : 'foo'}"
39
+ #
40
+ class EmptyStringInsideInterpolation < Base
41
+ include ConfigurableEnforcedStyle
42
+ include Interpolation
43
+ extend AutoCorrector
44
+
45
+ MSG_TRAILING_CONDITIONAL = 'Do not use trailing conditionals in string interpolation.'
46
+ MSG_TERNARY = 'Do not return empty strings in string interpolation.'
47
+
48
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
49
+ def on_interpolation(node)
50
+ node.each_child_node(:if) do |child_node|
51
+ if style == :trailing_conditional
52
+ if empty_if_outcome?(child_node)
53
+ ternary_style_autocorrect(child_node, child_node.else_branch.source, 'unless')
54
+ end
55
+
56
+ if empty_else_outcome?(child_node)
57
+ ternary_style_autocorrect(child_node, child_node.if_branch.source, 'if')
58
+ end
59
+ elsif style == :ternary
60
+ next unless child_node.modifier_form?
61
+
62
+ ternary_component = if child_node.unless?
63
+ "'' : #{child_node.if_branch.source}"
64
+ else
65
+ "#{child_node.if_branch.source} : ''"
66
+ end
67
+
68
+ add_offense(node, message: MSG_TRAILING_CONDITIONAL) do |corrector|
69
+ corrector.replace(node, "\#{#{child_node.condition.source} ? #{ternary_component}}")
70
+ end
71
+ end
72
+ end
73
+ end
74
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
75
+
76
+ private
77
+
78
+ def empty_if_outcome?(node)
79
+ empty_branch_outcome?(node.if_branch)
80
+ end
81
+
82
+ def empty_else_outcome?(node)
83
+ empty_branch_outcome?(node.else_branch)
84
+ end
85
+
86
+ def empty_branch_outcome?(branch)
87
+ return false unless branch
88
+
89
+ branch.nil_type? || (branch.str_type? && branch.value.empty?)
90
+ end
91
+
92
+ def ternary_style_autocorrect(node, outcome, condition)
93
+ add_offense(node, message: MSG_TERNARY) do |corrector|
94
+ corrector.replace(node, "#{outcome} #{condition} #{node.condition.source}")
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end