rubocop 1.67.0 → 1.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +168 -19
  5. data/config/internal_affairs.yml +16 -0
  6. data/lib/rubocop/cached_data.rb +12 -4
  7. data/lib/rubocop/cli/command/execute_runner.rb +4 -4
  8. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  9. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  10. data/lib/rubocop/cli/command/version.rb +2 -2
  11. data/lib/rubocop/comment_config.rb +2 -2
  12. data/lib/rubocop/config.rb +17 -4
  13. data/lib/rubocop/config_loader.rb +48 -8
  14. data/lib/rubocop/config_loader_resolver.rb +35 -10
  15. data/lib/rubocop/config_validator.rb +19 -9
  16. data/lib/rubocop/cop/autocorrect_logic.rb +36 -19
  17. data/lib/rubocop/cop/base.rb +7 -1
  18. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  19. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  20. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  21. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  22. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
  23. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
  24. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  25. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  26. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  27. data/lib/rubocop/cop/generator.rb +6 -0
  28. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  29. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -2
  30. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  31. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  32. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
  33. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  34. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  35. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  36. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  37. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  38. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  39. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  40. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  41. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  42. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  43. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  44. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  45. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  46. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  47. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  48. data/lib/rubocop/cop/internal_affairs.rb +6 -16
  49. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  50. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -9
  51. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  52. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  53. data/lib/rubocop/cop/layout/block_alignment.rb +3 -2
  54. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  55. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  56. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  57. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
  58. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  59. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +29 -4
  60. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  61. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +4 -5
  62. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  63. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  64. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  65. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  66. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  67. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  68. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  69. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  70. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  71. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  72. data/lib/rubocop/cop/layout/indentation_width.rb +7 -7
  73. data/lib/rubocop/cop/layout/leading_comment_space.rb +44 -1
  74. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  75. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  76. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  77. data/lib/rubocop/cop/layout/line_length.rb +119 -4
  78. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  79. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  80. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  81. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  82. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  83. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
  84. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  85. data/lib/rubocop/cop/layout/redundant_line_break.rb +10 -41
  86. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -3
  87. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  88. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  89. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  90. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  91. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  92. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -1
  93. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  94. data/lib/rubocop/cop/layout/space_around_operators.rb +19 -20
  95. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  96. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  97. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  98. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
  99. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
  100. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
  101. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  102. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  103. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  104. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  105. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  106. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
  107. data/lib/rubocop/cop/lint/circular_argument_reference.rb +6 -0
  108. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  109. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  110. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  111. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  112. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +2 -1
  113. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  114. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  115. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
  116. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  117. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  118. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  119. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  120. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  121. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  122. data/lib/rubocop/cop/lint/float_comparison.rb +20 -14
  123. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -4
  124. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  125. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  126. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  127. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  128. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
  129. data/lib/rubocop/cop/lint/literal_as_condition.rb +105 -7
  130. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  131. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  132. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  133. data/lib/rubocop/cop/lint/mixed_case_range.rb +4 -7
  134. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  135. data/lib/rubocop/cop/lint/nested_method_definition.rb +9 -5
  136. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  137. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  138. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +12 -3
  139. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
  140. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  141. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  142. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  143. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +93 -0
  144. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
  145. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +3 -2
  146. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  147. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  148. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  149. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  150. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +12 -7
  151. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  152. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  153. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +252 -0
  154. data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
  155. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  156. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  157. data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
  158. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -1
  159. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +5 -1
  160. data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
  161. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  162. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  163. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  164. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  165. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  166. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  167. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  168. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  169. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  170. data/lib/rubocop/cop/lint/unreachable_code.rb +51 -2
  171. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  172. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  173. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  174. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  175. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +80 -0
  176. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  177. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
  178. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  179. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  180. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  181. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  182. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  183. data/lib/rubocop/cop/lint/void.rb +14 -11
  184. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  185. data/lib/rubocop/cop/metrics/class_length.rb +9 -9
  186. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  187. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  188. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  189. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  190. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  191. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  192. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -3
  193. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  194. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  195. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  196. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  197. data/lib/rubocop/cop/mixin/check_line_breakable.rb +20 -10
  198. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  199. data/lib/rubocop/cop/mixin/comments_help.rb +8 -3
  200. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  201. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  202. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -2
  203. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  204. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  205. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  206. data/lib/rubocop/cop/mixin/line_length_help.rb +5 -4
  207. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  208. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -9
  209. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  210. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +68 -30
  211. data/lib/rubocop/cop/mixin/range_help.rb +3 -4
  212. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  213. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  214. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  215. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  216. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  217. data/lib/rubocop/cop/mixin/trailing_comma.rb +15 -3
  218. data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
  219. data/lib/rubocop/cop/naming/block_forwarding.rb +20 -16
  220. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  221. data/lib/rubocop/cop/naming/file_name.rb +0 -2
  222. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
  223. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  224. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +6 -14
  225. data/lib/rubocop/cop/naming/variable_name.rb +63 -6
  226. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  227. data/lib/rubocop/cop/offense.rb +2 -3
  228. data/lib/rubocop/cop/security/compound_hash.rb +2 -0
  229. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  230. data/lib/rubocop/cop/style/access_modifier_declarations.rb +86 -28
  231. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  232. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  233. data/lib/rubocop/cop/style/and_or.rb +1 -1
  234. data/lib/rubocop/cop/style/arguments_forwarding.rb +39 -23
  235. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  236. data/lib/rubocop/cop/style/array_intersect.rb +5 -4
  237. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  238. data/lib/rubocop/cop/style/block_delimiters.rb +41 -24
  239. data/lib/rubocop/cop/style/case_like_if.rb +8 -11
  240. data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
  241. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  242. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  243. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  244. data/lib/rubocop/cop/style/commented_keyword.rb +11 -1
  245. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  246. data/lib/rubocop/cop/style/conditional_assignment.rb +25 -25
  247. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  248. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  249. data/lib/rubocop/cop/style/documentation.rb +1 -1
  250. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  251. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  252. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  253. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  254. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  255. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  256. data/lib/rubocop/cop/style/endless_method.rb +150 -18
  257. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  258. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -3
  259. data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
  260. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  261. data/lib/rubocop/cop/style/fetch_env_var.rb +2 -1
  262. data/lib/rubocop/cop/style/file_null.rb +89 -0
  263. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  264. data/lib/rubocop/cop/style/float_division.rb +8 -4
  265. data/lib/rubocop/cop/style/for.rb +0 -1
  266. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  267. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  268. data/lib/rubocop/cop/style/guard_clause.rb +15 -2
  269. data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
  270. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -6
  271. data/lib/rubocop/cop/style/hash_except.rb +35 -147
  272. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  273. data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
  274. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  275. data/lib/rubocop/cop/style/if_inside_else.rb +0 -1
  276. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  277. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -3
  278. data/lib/rubocop/cop/style/if_with_semicolon.rb +20 -9
  279. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  280. data/lib/rubocop/cop/style/inverse_methods.rb +6 -7
  281. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  282. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  283. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  284. data/lib/rubocop/cop/style/lambda_call.rb +3 -2
  285. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  286. data/lib/rubocop/cop/style/map_into_array.rb +7 -2
  287. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  288. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  289. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +20 -13
  290. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  291. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +8 -11
  292. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  293. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  294. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  295. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  296. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  297. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  298. data/lib/rubocop/cop/style/multiple_comparison.rb +52 -51
  299. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  300. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -5
  301. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  302. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  303. data/lib/rubocop/cop/style/not.rb +1 -1
  304. data/lib/rubocop/cop/style/object_then.rb +14 -15
  305. data/lib/rubocop/cop/style/one_line_conditional.rb +25 -4
  306. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  307. data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
  308. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  309. data/lib/rubocop/cop/style/parallel_assignment.rb +9 -18
  310. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  311. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  312. data/lib/rubocop/cop/style/proc.rb +1 -2
  313. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  314. data/lib/rubocop/cop/style/raise_args.rb +7 -5
  315. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  316. data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
  317. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  318. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  319. data/lib/rubocop/cop/style/redundant_condition.rb +72 -23
  320. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  321. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  322. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  323. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  324. data/lib/rubocop/cop/style/redundant_format.rb +250 -0
  325. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  326. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  327. data/lib/rubocop/cop/style/redundant_line_continuation.rb +54 -15
  328. data/lib/rubocop/cop/style/redundant_parentheses.rb +36 -24
  329. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  330. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  331. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  332. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  333. data/lib/rubocop/cop/style/redundant_self.rb +8 -15
  334. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  335. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  336. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  337. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  338. data/lib/rubocop/cop/style/rescue_modifier.rb +2 -3
  339. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  340. data/lib/rubocop/cop/style/safe_navigation.rb +14 -2
  341. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  342. data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
  343. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  344. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  345. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  346. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  347. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  348. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  349. data/lib/rubocop/cop/style/single_line_do_end_block.rb +12 -3
  350. data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
  351. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  352. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -5
  353. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  354. data/lib/rubocop/cop/style/string_concatenation.rb +15 -14
  355. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  356. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  357. data/lib/rubocop/cop/style/super_arguments.rb +65 -17
  358. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  359. data/lib/rubocop/cop/style/ternary_parentheses.rb +25 -4
  360. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  361. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  362. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  363. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  364. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  365. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  366. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  367. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  368. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  369. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  370. data/lib/rubocop/cop/util.rb +12 -5
  371. data/lib/rubocop/cop/utils/format_string.rb +7 -5
  372. data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
  373. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  374. data/lib/rubocop/cop/variable_force/variable.rb +18 -2
  375. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  376. data/lib/rubocop/cop/variable_force.rb +4 -10
  377. data/lib/rubocop/cops_documentation_generator.rb +44 -23
  378. data/lib/rubocop/directive_comment.rb +44 -10
  379. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  380. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  381. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  382. data/lib/rubocop/lsp/logger.rb +2 -2
  383. data/lib/rubocop/lsp/routes.rb +7 -23
  384. data/lib/rubocop/lsp/runtime.rb +17 -49
  385. data/lib/rubocop/lsp/server.rb +0 -2
  386. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  387. data/lib/rubocop/magic_comment.rb +3 -3
  388. data/lib/rubocop/options.rb +28 -12
  389. data/lib/rubocop/path_util.rb +15 -8
  390. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  391. data/lib/rubocop/plugin/load_error.rb +26 -0
  392. data/lib/rubocop/plugin/loader.rb +100 -0
  393. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  394. data/lib/rubocop/plugin.rb +46 -0
  395. data/lib/rubocop/rake_task.rb +4 -1
  396. data/lib/rubocop/result_cache.rb +13 -13
  397. data/lib/rubocop/rspec/cop_helper.rb +9 -0
  398. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  399. data/lib/rubocop/rspec/shared_contexts.rb +19 -1
  400. data/lib/rubocop/rspec/support.rb +2 -2
  401. data/lib/rubocop/runner.rb +21 -14
  402. data/lib/rubocop/server/cache.rb +35 -2
  403. data/lib/rubocop/server/cli.rb +2 -2
  404. data/lib/rubocop/target_finder.rb +1 -0
  405. data/lib/rubocop/target_ruby.rb +16 -1
  406. data/lib/rubocop/version.rb +41 -7
  407. data/lib/rubocop.rb +27 -1
  408. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  409. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +47 -0
  410. metadata +73 -20
  411. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  412. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for Style/HashExcept and Style/HashSlice cops.
6
+ # It registers an offense on methods with blocks that are equivalent
7
+ # to Hash#except or Hash#slice.
8
+ # rubocop:disable Metrics/ModuleLength
9
+ module HashSubset
10
+ include RangeHelp
11
+ extend NodePattern::Macros
12
+
13
+ RESTRICT_ON_SEND = %i[reject select filter].freeze
14
+
15
+ SUBSET_METHODS = %i[== != eql? include?].freeze
16
+ ACTIVE_SUPPORT_SUBSET_METHODS = (SUBSET_METHODS + %i[in? exclude?]).freeze
17
+
18
+ MSG = 'Use `%<prefer>s` instead.'
19
+
20
+ # @!method block_with_first_arg_check?(node)
21
+ def_node_matcher :block_with_first_arg_check?, <<~PATTERN
22
+ (block
23
+ (call _ _)
24
+ (args
25
+ $(arg _key)
26
+ $(arg _))
27
+ {
28
+ $(send
29
+ {(lvar _key) $_ _ | _ $_ (lvar _key)})
30
+ (send
31
+ $(send
32
+ {(lvar _key) $_ _ | _ $_ (lvar _key)}) :!)
33
+ })
34
+ PATTERN
35
+
36
+ def on_send(node)
37
+ offense_range, key_source = extract_offense(node)
38
+
39
+ return unless offense_range
40
+ return unless semantically_subset_method?(node)
41
+
42
+ preferred_method = "#{preferred_method_name}(#{key_source})"
43
+ add_offense(offense_range, message: format(MSG, prefer: preferred_method)) do |corrector|
44
+ corrector.replace(offense_range, preferred_method)
45
+ end
46
+ end
47
+ alias on_csend on_send
48
+
49
+ private
50
+
51
+ def semantically_subset_method?(node)
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def preferred_method_name
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def extract_offense(node)
60
+ block = node.parent
61
+ return unless extracts_hash_subset?(block)
62
+
63
+ except_key = except_key(block)
64
+ return if except_key.nil? || !safe_to_register_offense?(block, except_key)
65
+
66
+ [offense_range(node), except_key_source(except_key)]
67
+ end
68
+
69
+ def extracts_hash_subset?(block)
70
+ block_with_first_arg_check?(block) do |key_arg, value_arg, send_node, method|
71
+ # Only consider methods that have one argument
72
+ return false unless send_node.arguments.one?
73
+
74
+ return false unless supported_subset_method?(method)
75
+ return false if range_include?(send_node)
76
+
77
+ case method
78
+ when :include?, :exclude?
79
+ slices_key?(send_node, :first_argument, key_arg, value_arg)
80
+ when :in?
81
+ slices_key?(send_node, :receiver, key_arg, value_arg)
82
+ else
83
+ true
84
+ end
85
+ end
86
+ end
87
+
88
+ def slices_key?(send_node, method, key_arg, value_arg)
89
+ return false if using_value_variable?(send_node, value_arg)
90
+
91
+ node = method == :receiver ? send_node.receiver : send_node.first_argument
92
+ node.source == key_arg.source
93
+ end
94
+
95
+ def range_include?(send_node)
96
+ # When checking `include?`, `exclude?` and `in?` for offenses, if the receiver
97
+ # or first argument is a range, an offense should not be registered.
98
+ # ie. `(1..5).include?(k)` or `k.in?('a'..'z')`
99
+
100
+ return true if send_node.first_argument.range_type?
101
+
102
+ receiver = send_node.receiver
103
+ receiver = receiver.child_nodes.first while receiver.begin_type?
104
+ receiver.range_type?
105
+ end
106
+
107
+ def using_value_variable?(send_node, value_arg)
108
+ # If the receiver of `include?` or `exclude?`, or the first argument of `in?` is the
109
+ # hash value block argument, an offense should not be registered.
110
+ # ie. `v.include?(k)` or `k.in?(v)`
111
+ (send_node.receiver.lvar_type? && send_node.receiver.name == value_arg.name) ||
112
+ (send_node.first_argument.lvar_type? && send_node.first_argument.name == value_arg.name)
113
+ end
114
+
115
+ def supported_subset_method?(method)
116
+ if active_support_extensions_enabled?
117
+ ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)
118
+ else
119
+ SUBSET_METHODS.include?(method)
120
+ end
121
+ end
122
+
123
+ def semantically_except_method?(node)
124
+ block = node.parent
125
+ body, negated = extract_body_if_negated(block.body)
126
+
127
+ if node.method?('reject')
128
+ body.method?('==') || body.method?('eql?') || included?(body, negated)
129
+ else
130
+ body.method?('!=') || not_included?(body, negated)
131
+ end
132
+ end
133
+
134
+ def semantically_slice_method?(node)
135
+ !semantically_except_method?(node)
136
+ end
137
+
138
+ def included?(body, negated)
139
+ if negated
140
+ body.method?('exclude?')
141
+ else
142
+ body.method?('include?') || body.method?('in?')
143
+ end
144
+ end
145
+
146
+ def not_included?(body, negated)
147
+ included?(body, !negated)
148
+ end
149
+
150
+ def safe_to_register_offense?(block, except_key)
151
+ body = block.body
152
+
153
+ if body.method?('==') || body.method?('!=')
154
+ except_key.type?(:sym, :str)
155
+ else
156
+ true
157
+ end
158
+ end
159
+
160
+ def extract_body_if_negated(body)
161
+ if body.method?('!')
162
+ [body.receiver, true]
163
+ else
164
+ [body, false]
165
+ end
166
+ end
167
+
168
+ def except_key_source(key)
169
+ if key.array_type?
170
+ key = if key.percent_literal?
171
+ key.each_value.map { |v| decorate_source(v) }
172
+ else
173
+ key.each_value.map(&:source)
174
+ end
175
+ return key.join(', ')
176
+ end
177
+
178
+ key.literal? ? key.source : "*#{key.source}"
179
+ end
180
+
181
+ def decorate_source(value)
182
+ return ":\"#{value.source}\"" if value.dsym_type?
183
+ return "\"#{value.source}\"" if value.dstr_type?
184
+ return ":#{value.source}" if value.sym_type?
185
+
186
+ "'#{value.source}'"
187
+ end
188
+
189
+ def except_key(node)
190
+ key_arg = node.argument_list.first.source
191
+ body, = extract_body_if_negated(node.body)
192
+ lhs, _method_name, rhs = *body
193
+
194
+ lhs.source == key_arg ? rhs : lhs
195
+ end
196
+
197
+ def offense_range(node)
198
+ range_between(node.loc.selector.begin_pos, node.parent.loc.end.end_pos)
199
+ end
200
+ end
201
+ # rubocop:enable Metrics/ModuleLength
202
+ end
203
+ end
@@ -9,6 +9,80 @@ module RuboCop
9
9
 
10
10
  RESTRICT_ON_SEND = %i[[] to_h].freeze
11
11
 
12
+ # Internal helper class to hold match data
13
+ Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
14
+ def noop_transformation?
15
+ transforming_body_expr.lvar_type? &&
16
+ transforming_body_expr.children == [transformed_argname]
17
+ end
18
+
19
+ def transformation_uses_both_args?
20
+ transforming_body_expr.descendants.include?(unchanged_body_expr)
21
+ end
22
+
23
+ def use_transformed_argname?
24
+ transforming_body_expr.each_descendant(:lvar).any? do |node|
25
+ node.source == transformed_argname.to_s
26
+ end
27
+ end
28
+ end
29
+
30
+ # Internal helper class to hold autocorrect data
31
+ Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
32
+ def self.from_each_with_object(node, match)
33
+ new(match, node, 0, 0)
34
+ end
35
+
36
+ def self.from_hash_brackets_map(node, match)
37
+ new(match, node.children.last, 'Hash['.length, ']'.length)
38
+ end
39
+
40
+ def self.from_map_to_h(node, match)
41
+ if node.parent&.block_type? && node.parent.send_node == node
42
+ strip_trailing_chars = 0
43
+ else
44
+ map_range = node.children.first.source_range
45
+ node_range = node.source_range
46
+ strip_trailing_chars = node_range.end_pos - map_range.end_pos
47
+ end
48
+
49
+ new(match, node.children.first, 0, strip_trailing_chars)
50
+ end
51
+
52
+ def self.from_to_h(node, match)
53
+ new(match, node, 0, 0)
54
+ end
55
+
56
+ def strip_prefix_and_suffix(node, corrector)
57
+ expression = node.source_range
58
+ corrector.remove_leading(expression, leading)
59
+ corrector.remove_trailing(expression, trailing)
60
+ end
61
+
62
+ def set_new_method_name(new_method_name, corrector)
63
+ range = block_node.send_node.loc.selector
64
+ if (send_end = block_node.send_node.loc.end)
65
+ # If there are arguments (only true in the `each_with_object`
66
+ # case)
67
+ range = range.begin.join(send_end)
68
+ end
69
+ corrector.replace(range, new_method_name)
70
+ end
71
+
72
+ def set_new_arg_name(transformed_argname, corrector)
73
+ corrector.replace(block_node.arguments, "|#{transformed_argname}|")
74
+ end
75
+
76
+ def set_new_body_expression(transforming_body_expr, corrector)
77
+ body_source = transforming_body_expr.source
78
+ if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
79
+ body_source = "{ #{body_source} }"
80
+ end
81
+
82
+ corrector.replace(block_node.body, body_source)
83
+ end
84
+ end
85
+
12
86
  # @!method array_receiver?(node)
13
87
  def_node_matcher :array_receiver?, <<~PATTERN
14
88
  {(array ...) (send _ :each_with_index) (send _ :with_index _ ?) (send _ :zip ...)}
@@ -113,80 +187,6 @@ module RuboCop
113
187
  correction.set_new_arg_name(captures.transformed_argname, corrector)
114
188
  correction.set_new_body_expression(captures.transforming_body_expr, corrector)
115
189
  end
116
-
117
- # Internal helper class to hold match data
118
- Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
119
- def noop_transformation?
120
- transforming_body_expr.lvar_type? &&
121
- transforming_body_expr.children == [transformed_argname]
122
- end
123
-
124
- def transformation_uses_both_args?
125
- transforming_body_expr.descendants.include?(unchanged_body_expr)
126
- end
127
-
128
- def use_transformed_argname?
129
- transforming_body_expr.each_descendant(:lvar).any? do |node|
130
- node.source == transformed_argname.to_s
131
- end
132
- end
133
- end
134
-
135
- # Internal helper class to hold autocorrect data
136
- Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
137
- def self.from_each_with_object(node, match)
138
- new(match, node, 0, 0)
139
- end
140
-
141
- def self.from_hash_brackets_map(node, match)
142
- new(match, node.children.last, 'Hash['.length, ']'.length)
143
- end
144
-
145
- def self.from_map_to_h(node, match)
146
- if node.parent&.block_type? && node.parent.send_node == node
147
- strip_trailing_chars = 0
148
- else
149
- map_range = node.children.first.source_range
150
- node_range = node.source_range
151
- strip_trailing_chars = node_range.end_pos - map_range.end_pos
152
- end
153
-
154
- new(match, node.children.first, 0, strip_trailing_chars)
155
- end
156
-
157
- def self.from_to_h(node, match)
158
- new(match, node, 0, 0)
159
- end
160
-
161
- def strip_prefix_and_suffix(node, corrector)
162
- expression = node.source_range
163
- corrector.remove_leading(expression, leading)
164
- corrector.remove_trailing(expression, trailing)
165
- end
166
-
167
- def set_new_method_name(new_method_name, corrector)
168
- range = block_node.send_node.loc.selector
169
- if (send_end = block_node.send_node.loc.end)
170
- # If there are arguments (only true in the `each_with_object`
171
- # case)
172
- range = range.begin.join(send_end)
173
- end
174
- corrector.replace(range, new_method_name)
175
- end
176
-
177
- def set_new_arg_name(transformed_argname, corrector)
178
- corrector.replace(block_node.arguments, "|#{transformed_argname}|")
179
- end
180
-
181
- def set_new_body_expression(transforming_body_expr, corrector)
182
- body_source = transforming_body_expr.source
183
- if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
184
- body_source = "{ #{body_source} }"
185
- end
186
-
187
- corrector.replace(block_node.body, body_source)
188
- end
189
- end
190
190
  end
191
191
  end
192
192
  end
@@ -37,12 +37,13 @@ module RuboCop
37
37
  last_uri_match = match_uris(line).last
38
38
  return nil unless last_uri_match
39
39
 
40
- begin_position, end_position = last_uri_match.offset(0).map do |pos|
41
- pos + indentation_difference(line)
42
- end
43
-
40
+ begin_position, end_position = last_uri_match.offset(0)
44
41
  end_position = extend_uri_end_position(line, end_position)
45
42
 
43
+ line_indentation_difference = indentation_difference(line)
44
+ begin_position += line_indentation_difference
45
+ end_position += line_indentation_difference
46
+
46
47
  return nil if begin_position < max_line_length && end_position < max_line_length
47
48
 
48
49
  begin_position...end_position
@@ -35,7 +35,7 @@ module RuboCop
35
35
 
36
36
  # @!method define_method?(node)
37
37
  def_node_matcher :define_method?, <<~PATTERN
38
- ({block numblock}
38
+ (any_block
39
39
  (send nil? :define_method ({sym str} $_)) _ _)
40
40
  PATTERN
41
41
 
@@ -121,12 +121,10 @@ module RuboCop
121
121
 
122
122
  def indented_keyword_expression(node)
123
123
  if node.for_type?
124
- expression = node.collection
124
+ node.collection
125
125
  else
126
- expression, = *node
126
+ node.children.first
127
127
  end
128
-
129
- expression
130
128
  end
131
129
 
132
130
  def argument_in_method_call(node, kind) # rubocop:todo Metrics/CyclomaticComplexity
@@ -187,12 +185,10 @@ module RuboCop
187
185
 
188
186
  def assignment_rhs(node)
189
187
  case node.type
190
- when :casgn then _scope, _lhs, rhs = *node
191
- when :op_asgn then _lhs, _op, rhs = *node
192
- when :send, :csend then rhs = node.last_argument
193
- else _lhs, rhs = *node
188
+ when :casgn, :op_asgn then node.rhs
189
+ when :send, :csend then node.last_argument
190
+ else node.children.last
194
191
  end
195
- rhs
196
192
  end
197
193
 
198
194
  def not_for_this_cop?(node)
@@ -21,7 +21,7 @@ module RuboCop
21
21
  end
22
22
 
23
23
  def begin_source(node)
24
- node.loc.begin.source if node.loc.respond_to?(:begin) && node.loc.begin
24
+ node.loc.begin.source if node.loc?(:begin)
25
25
  end
26
26
 
27
27
  def type(node)
@@ -4,7 +4,12 @@ module RuboCop
4
4
  module Cop
5
5
  # Common functionality for checking whether an AST node/token is aligned
6
6
  # with something on a preceding or following line
7
+ # rubocop:disable Metrics/ModuleLength
7
8
  module PrecedingFollowingAlignment
9
+ # Tokens that end with an `=`, as well as `<<`, that can be aligned together:
10
+ # `=`, `==`, `===`, `!=`, `<=`, `>=`, `<<` and operator assignment (`+=`, etc).
11
+ ASSIGNMENT_OR_COMPARISON_TOKENS = %i[tEQL tEQ tEQQ tNEQ tLEQ tGEQ tOP_ASGN tLSHFT].freeze
12
+
8
13
  private
9
14
 
10
15
  def allow_for_alignment?
@@ -19,16 +24,20 @@ module RuboCop
19
24
  aligned_with_adjacent_line?(range, method(:aligned_operator?))
20
25
  end
21
26
 
22
- def aligned_with_preceding_assignment(token)
27
+ # Allows alignment with a preceding operator that ends with an `=`,
28
+ # including assignment and comparison operators.
29
+ def aligned_with_preceding_equals_operator(token)
23
30
  preceding_line_range = token.line.downto(1)
24
31
 
25
- aligned_with_assignment(token, preceding_line_range)
32
+ aligned_with_equals_sign(token, preceding_line_range)
26
33
  end
27
34
 
28
- def aligned_with_subsequent_assignment(token)
35
+ # Allows alignment with a subsequent operator that ends with an `=`,
36
+ # including assignment and comparison operators.
37
+ def aligned_with_subsequent_equals_operator(token)
29
38
  subsequent_line_range = token.line.upto(processed_source.lines.length)
30
39
 
31
- aligned_with_assignment(token, subsequent_line_range)
40
+ aligned_with_equals_sign(token, subsequent_line_range)
32
41
  end
33
42
 
34
43
  def aligned_with_adjacent_line?(range, predicate)
@@ -62,7 +71,7 @@ module RuboCop
62
71
  next unless index
63
72
  next if indent && indent != index
64
73
 
65
- return yield(range, line)
74
+ return yield(range, line, lineno + 1)
66
75
  end
67
76
  false
68
77
  end
@@ -74,12 +83,12 @@ module RuboCop
74
83
  end.map(&:line)
75
84
  end
76
85
 
77
- def aligned_token?(range, line)
78
- aligned_words?(range, line) || aligned_assignment?(range, line)
86
+ def aligned_token?(range, line, lineno)
87
+ aligned_words?(range, line) || aligned_equals_operator?(range, lineno)
79
88
  end
80
89
 
81
- def aligned_operator?(range, line)
82
- aligned_identical?(range, line) || aligned_assignment?(range, line)
90
+ def aligned_operator?(range, line, lineno)
91
+ aligned_identical?(range, line) || aligned_equals_operator?(range, lineno)
83
92
  end
84
93
 
85
94
  def aligned_words?(range, line)
@@ -90,23 +99,42 @@ module RuboCop
90
99
  token == line[left_edge, token.length]
91
100
  end
92
101
 
93
- def aligned_assignment?(range, line)
94
- (range.source[-1] == '=' && line[range.last_column - 1] == '=') ||
95
- aligned_with_append_operator?(range, line)
102
+ def aligned_equals_operator?(range, lineno)
103
+ # Check that the operator is aligned with a previous assignment or comparison operator
104
+ # ie. an equals sign, an operator assignment (eg. `+=`), a comparison (`==`, `<=`, etc.).
105
+ # Since append operators (`<<`) are a type of assignment, they are allowed as well,
106
+ # despite not ending with a literal equals character.
107
+ line_range = processed_source.buffer.line_range(lineno)
108
+ return false unless line_range
109
+
110
+ # Find the specific token to avoid matching up to operators inside strings
111
+ operator_token = processed_source.tokens_within(line_range).detect do |token|
112
+ ASSIGNMENT_OR_COMPARISON_TOKENS.include?(token.type)
113
+ end
114
+
115
+ aligned_with_preceding_equals?(range, operator_token) ||
116
+ aligned_with_append_operator?(range, operator_token)
96
117
  end
97
118
 
98
- def aligned_with_append_operator?(range, line)
99
- last_column = range.last_column
119
+ def aligned_with_preceding_equals?(range, token)
120
+ return false unless token
100
121
 
101
- (range.source == '<<' && line[last_column - 1] == '=') ||
102
- (range.source[-1] == '=' && line[(last_column - 2)..(last_column - 1)] == '<<')
122
+ range.source[-1] == '=' && range.last_column == token.pos.last_column
123
+ end
124
+
125
+ def aligned_with_append_operator?(range, token)
126
+ return false unless token
127
+
128
+ ((range.source == '<<' && token.equal_sign?) ||
129
+ (range.source[-1] == '=' && token.type == :tLSHFT)) &&
130
+ token && range.last_column == token.pos.last_column
103
131
  end
104
132
 
105
133
  def aligned_identical?(range, line)
106
134
  range.source == line[range.column, range.size]
107
135
  end
108
136
 
109
- def aligned_with_assignment(token, line_range)
137
+ def aligned_with_equals_sign(token, line_range)
110
138
  token_line_indent = processed_source.line_indentation(token.line)
111
139
  assignment_lines = relevant_assignment_lines(line_range)
112
140
  relevant_line_number = assignment_lines[1]
@@ -116,12 +144,9 @@ module RuboCop
116
144
  relevant_indent = processed_source.line_indentation(relevant_line_number)
117
145
 
118
146
  return :none if relevant_indent < token_line_indent
147
+ return :none unless processed_source.lines[relevant_line_number - 1]
119
148
 
120
- assignment_line = processed_source.lines[relevant_line_number - 1]
121
-
122
- return :none unless assignment_line
123
-
124
- aligned_assignment?(token.pos, assignment_line) ? :yes : :no
149
+ aligned_equals_operator?(token.pos, relevant_line_number) ? :yes : :no
125
150
  end
126
151
 
127
152
  def assignment_lines
@@ -132,10 +157,14 @@ module RuboCop
132
157
  @assignment_tokens ||= begin
133
158
  tokens = processed_source.tokens.select(&:equal_sign?)
134
159
 
135
- # we don't want to operate on equals signs which are part of an
136
- # optarg in a method definition
137
- # e.g.: def method(optarg = default_val); end
138
- tokens = remove_optarg_equals(tokens, processed_source)
160
+ # We don't want to operate on equals signs which are part of an `optarg` in a
161
+ # method definition, or the separator of an endless method definition.
162
+ # For example (the equals sign to ignore is highlighted with ^):
163
+ # def method(optarg = default_val); end
164
+ # ^
165
+ # def method = foo
166
+ # ^
167
+ tokens = remove_equals_in_def(tokens, processed_source)
139
168
 
140
169
  # Only attempt to align the first = on each line
141
170
  Set.new(tokens.uniq(&:line))
@@ -171,11 +200,20 @@ module RuboCop
171
200
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
172
201
  # rubocop:enable Metrics/PerceivedComplexity, Metrics/MethodLength
173
202
 
174
- def remove_optarg_equals(asgn_tokens, processed_source)
175
- optargs = processed_source.ast.each_node(:optarg)
176
- optarg_eql = optargs.to_set { |o| o.loc.operator.begin_pos }
177
- asgn_tokens.reject { |t| optarg_eql.include?(t.begin_pos) }
203
+ def remove_equals_in_def(asgn_tokens, processed_source)
204
+ nodes = processed_source.ast.each_node(:optarg, :def)
205
+ eqls_to_ignore = nodes.with_object([]) do |node, arr|
206
+ loc = if node.def_type?
207
+ node.loc.assignment if node.endless?
208
+ else
209
+ node.loc.operator
210
+ end
211
+ arr << loc.begin_pos if loc
212
+ end
213
+
214
+ asgn_tokens.reject { |t| eqls_to_ignore.include?(t.begin_pos) }
178
215
  end
179
216
  end
217
+ # rubocop:enable Metrics/ModuleLength
180
218
  end
181
219
  end
@@ -4,9 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  # Methods that calculate and return Parser::Source::Ranges
6
6
  module RangeHelp
7
- private
8
-
9
7
  BYTE_ORDER_MARK = 0xfeff # The Unicode codepoint
8
+ NOT_GIVEN = Module.new
9
+
10
+ private
10
11
 
11
12
  def source_range(source_buffer, line_number, column, length = 1)
12
13
  if column.is_a?(Range)
@@ -51,12 +52,10 @@ module RuboCop
51
52
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
52
53
  end
53
54
 
54
- NOT_GIVEN = Module.new
55
55
  def range_with_surrounding_space(range_positional = NOT_GIVEN, # rubocop:disable Metrics/ParameterLists
56
56
  range: NOT_GIVEN, side: :both, newlines: true,
57
57
  whitespace: false, continuations: false,
58
58
  buffer: @processed_source.buffer)
59
-
60
59
  range = range_positional unless range_positional == NOT_GIVEN
61
60
 
62
61
  src = buffer.source
@@ -36,7 +36,7 @@ module RuboCop
36
36
  end
37
37
 
38
38
  def space_required_after?(token)
39
- (token.left_curly_brace? || token.type == :tLAMBEG) && space_required_after_lcurly?
39
+ token.left_curly_brace? && space_required_after_lcurly?
40
40
  end
41
41
 
42
42
  def space_required_after_lcurly?
@@ -55,14 +55,19 @@ module RuboCop
55
55
  end
56
56
 
57
57
  def if_body_source(if_body)
58
- if if_body.call_type? &&
59
- if_body.last_argument&.hash_type? && if_body.last_argument.pairs.last&.value_omission?
58
+ if if_body.call_type? && !if_body.method?(:[]=) && omitted_value_in_last_hash_arg?(if_body)
60
59
  "#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
61
60
  else
62
61
  if_body.source
63
62
  end
64
63
  end
65
64
 
65
+ def omitted_value_in_last_hash_arg?(if_body)
66
+ return false unless (last_argument = if_body.last_argument)
67
+
68
+ last_argument.hash_type? && last_argument.pairs.last&.value_omission?
69
+ end
70
+
66
71
  def method_source(if_body)
67
72
  end_range = if_body.implicit_call? ? if_body.loc.dot.end : if_body.loc.selector
68
73
 
@@ -96,7 +101,7 @@ module RuboCop
96
101
  end
97
102
 
98
103
  def max_line_length
99
- return unless config.for_cop('Layout/LineLength')['Enabled']
104
+ return unless config.cop_enabled?('Layout/LineLength')
100
105
 
101
106
  config.for_cop('Layout/LineLength')['Max']
102
107
  end