rubocop 1.50.2 → 1.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +7 -5
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +196 -28
  7. data/config/obsoletion.yml +5 -0
  8. data/lib/rubocop/cli/command/auto_generate_config.rb +22 -8
  9. data/lib/rubocop/cli/command/lsp.rb +19 -0
  10. data/lib/rubocop/cli.rb +10 -2
  11. data/lib/rubocop/config.rb +8 -2
  12. data/lib/rubocop/config_finder.rb +14 -4
  13. data/lib/rubocop/config_loader.rb +0 -1
  14. data/lib/rubocop/config_loader_resolver.rb +4 -3
  15. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  16. data/lib/rubocop/config_obsoletion.rb +13 -10
  17. data/lib/rubocop/config_validator.rb +14 -7
  18. data/lib/rubocop/cop/autocorrect_logic.rb +9 -2
  19. data/lib/rubocop/cop/base.rb +23 -4
  20. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  21. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  23. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  24. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  25. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  26. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  27. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  28. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  29. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  30. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  31. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  32. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  33. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  34. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  35. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  36. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  37. data/lib/rubocop/cop/internal_affairs/example_description.rb +45 -24
  38. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  39. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  40. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  41. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  42. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +127 -33
  43. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  44. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  45. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  46. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  47. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  48. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  49. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  50. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  51. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  52. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  53. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
  54. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  55. data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
  56. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  57. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  58. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  59. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
  60. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
  61. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  62. data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
  63. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  64. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  65. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  66. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  67. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  68. data/lib/rubocop/cop/layout/redundant_line_break.rb +30 -7
  69. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  70. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  71. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  72. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  73. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  74. data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
  75. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  76. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  77. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  78. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  79. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  80. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  81. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  82. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  83. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  84. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  85. data/lib/rubocop/cop/lint/debugger.rb +19 -5
  86. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  87. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  88. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  89. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  90. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  91. data/lib/rubocop/cop/lint/erb_new_arguments.rb +6 -7
  92. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  93. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  94. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  95. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  96. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  97. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  98. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  99. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  100. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  101. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  102. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  103. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  104. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  105. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  106. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  107. data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
  108. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  109. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  110. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  111. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  112. data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
  113. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
  114. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  115. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
  116. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  117. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  118. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
  119. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  120. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  121. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  122. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  123. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  124. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  125. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  126. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  127. data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
  128. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  129. data/lib/rubocop/cop/lint/to_enum_arguments.rb +12 -5
  130. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  131. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  132. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  133. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  134. data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
  135. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  136. data/lib/rubocop/cop/lint/void.rb +97 -11
  137. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  138. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  139. data/lib/rubocop/cop/metrics/class_length.rb +8 -3
  140. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  141. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  142. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
  143. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  144. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  145. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  146. data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
  147. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  148. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  149. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  150. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
  151. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  152. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
  153. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  154. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  155. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  156. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  157. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  158. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  159. data/lib/rubocop/cop/naming/block_forwarding.rb +13 -5
  160. data/lib/rubocop/cop/naming/constant_name.rb +2 -3
  161. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  162. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  163. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
  164. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  165. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  166. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  167. data/lib/rubocop/cop/registry.rb +1 -1
  168. data/lib/rubocop/cop/security/open.rb +2 -2
  169. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  170. data/lib/rubocop/cop/style/accessor_grouping.rb +6 -2
  171. data/lib/rubocop/cop/style/alias.rb +9 -8
  172. data/lib/rubocop/cop/style/arguments_forwarding.rb +411 -63
  173. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  174. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  175. data/lib/rubocop/cop/style/attr.rb +11 -1
  176. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  177. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  178. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  179. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  180. data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
  181. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  182. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  183. data/lib/rubocop/cop/style/class_check.rb +1 -0
  184. data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
  185. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  186. data/lib/rubocop/cop/style/collection_compact.rb +32 -12
  187. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  188. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  189. data/lib/rubocop/cop/style/combinable_loops.rb +36 -8
  190. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  191. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  192. data/lib/rubocop/cop/style/conditional_assignment.rb +11 -10
  193. data/lib/rubocop/cop/style/copyright.rb +5 -2
  194. data/lib/rubocop/cop/style/date_time.rb +5 -4
  195. data/lib/rubocop/cop/style/dir.rb +1 -1
  196. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  197. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  198. data/lib/rubocop/cop/style/documentation.rb +1 -1
  199. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  200. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  201. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  202. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  203. data/lib/rubocop/cop/style/eval_with_location.rb +8 -19
  204. data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
  205. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  206. data/lib/rubocop/cop/style/file_read.rb +2 -2
  207. data/lib/rubocop/cop/style/for.rb +3 -1
  208. data/lib/rubocop/cop/style/format_string.rb +24 -3
  209. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  210. data/lib/rubocop/cop/style/guard_clause.rb +28 -0
  211. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  212. data/lib/rubocop/cop/style/hash_each_methods.rb +106 -33
  213. data/lib/rubocop/cop/style/hash_except.rb +21 -9
  214. data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
  215. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  216. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  217. data/lib/rubocop/cop/style/identical_conditional_branches.rb +34 -5
  218. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  219. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  220. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  221. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  222. data/lib/rubocop/cop/style/invertible_unless_condition.rb +54 -8
  223. data/lib/rubocop/cop/style/lambda.rb +3 -3
  224. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  225. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
  226. data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
  227. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +24 -9
  228. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  229. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  230. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  231. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  232. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  233. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  234. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  235. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
  236. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  237. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  238. data/lib/rubocop/cop/style/next.rb +1 -1
  239. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  240. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  241. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  242. data/lib/rubocop/cop/style/object_then.rb +5 -3
  243. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  244. data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
  245. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  246. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  247. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  248. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  249. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  250. data/lib/rubocop/cop/style/redundant_argument.rb +10 -4
  251. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  252. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  253. data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
  254. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  255. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +39 -0
  256. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  257. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  258. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  259. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  260. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  261. data/lib/rubocop/cop/style/redundant_line_continuation.rb +32 -8
  262. data/lib/rubocop/cop/style/redundant_parentheses.rb +72 -23
  263. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  264. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  265. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  266. data/lib/rubocop/cop/style/redundant_return.rb +14 -3
  267. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  268. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  269. data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
  270. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  271. data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
  272. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  273. data/lib/rubocop/cop/style/require_order.rb +11 -5
  274. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  275. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  276. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
  277. data/lib/rubocop/cop/style/sample.rb +3 -4
  278. data/lib/rubocop/cop/style/select_by_regexp.rb +22 -11
  279. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  280. data/lib/rubocop/cop/style/semicolon.rb +20 -4
  281. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  282. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  283. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  284. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  285. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  286. data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -2
  287. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  288. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  289. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  290. data/lib/rubocop/cop/style/strip.rb +7 -4
  291. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  292. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  293. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  294. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  295. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  296. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  297. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  298. data/lib/rubocop/cop/team.rb +1 -1
  299. data/lib/rubocop/cop/util.rb +1 -1
  300. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  301. data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
  302. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  303. data/lib/rubocop/cop/variable_force.rb +1 -0
  304. data/lib/rubocop/cops_documentation_generator.rb +16 -4
  305. data/lib/rubocop/directive_comment.rb +10 -8
  306. data/lib/rubocop/ext/regexp_node.rb +9 -4
  307. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  308. data/lib/rubocop/file_finder.rb +4 -7
  309. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  310. data/lib/rubocop/formatter/html_formatter.rb +35 -14
  311. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  312. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  313. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  314. data/lib/rubocop/formatter.rb +1 -1
  315. data/lib/rubocop/lsp/logger.rb +22 -0
  316. data/lib/rubocop/lsp/routes.rb +246 -0
  317. data/lib/rubocop/lsp/runtime.rb +99 -0
  318. data/lib/rubocop/lsp/server.rb +71 -0
  319. data/lib/rubocop/lsp/severity.rb +27 -0
  320. data/lib/rubocop/lsp.rb +29 -0
  321. data/lib/rubocop/magic_comment.rb +13 -11
  322. data/lib/rubocop/options.rb +22 -9
  323. data/lib/rubocop/path_util.rb +6 -2
  324. data/lib/rubocop/result_cache.rb +5 -2
  325. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  326. data/lib/rubocop/rspec/expect_offense.rb +8 -8
  327. data/lib/rubocop/rspec/shared_contexts.rb +42 -18
  328. data/lib/rubocop/rspec/support.rb +2 -0
  329. data/lib/rubocop/runner.rb +15 -6
  330. data/lib/rubocop/server/cache.rb +1 -1
  331. data/lib/rubocop/server/client_command/exec.rb +3 -3
  332. data/lib/rubocop/server/server_command/exec.rb +0 -1
  333. data/lib/rubocop/string_interpreter.rb +3 -3
  334. data/lib/rubocop/target_finder.rb +91 -81
  335. data/lib/rubocop/target_ruby.rb +85 -78
  336. data/lib/rubocop/version.rb +27 -8
  337. data/lib/rubocop.rb +19 -0
  338. metadata +56 -14
  339. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -26,10 +26,18 @@ module RuboCop
26
26
  MSG = 'Precede `%<method>s` with a `@!method` YARD directive.'
27
27
  MSG_WRONG_NAME = '`@!method` YARD directive has invalid method name, ' \
28
28
  'use `%<expected>s` instead of `%<actual>s`.'
29
+ MSG_MISSING_SCOPE_SELF = 'Follow the `@!method` YARD directive with ' \
30
+ '`@!scope class` if it is a class method.'
31
+ MSG_WRONG_SCOPE_SELF = 'Do not use the `@!scope class` YARD directive if it ' \
32
+ 'is not a class method.'
29
33
  MSG_TOO_MANY = 'Multiple `@!method` YARD directives found for this matcher.'
30
34
 
31
35
  RESTRICT_ON_SEND = %i[def_node_matcher def_node_search].to_set.freeze
32
- REGEXP = /^\s*#\s*@!method\s+(?<method_name>[a-z0-9_]+[?!]?)(?:\((?<args>.*)\))?/.freeze
36
+ REGEXP_METHOD = /
37
+ ^\s*\#\s*
38
+ @!method\s+(?<receiver>self\.)?(?<method_name>[a-z0-9_]+[?!]?)(?:\((?<args>.*)\))?
39
+ /x.freeze
40
+ REGEXP_SCOPE = /^\s*\#\s*@!scope class/.freeze
33
41
 
34
42
  # @!method pattern_matcher?(node)
35
43
  def_node_matcher :pattern_matcher?, <<~PATTERN
@@ -40,62 +48,131 @@ module RuboCop
40
48
  return if node.arguments.none?
41
49
  return unless valid_method_name?(node)
42
50
 
43
- actual_name = node.arguments.first.value
51
+ actual_name = node.first_argument.value.to_s
52
+
53
+ # Ignore cases where the method has a receiver that isn't self
54
+ return if actual_name.include?('.') && !actual_name.start_with?('self.')
55
+
44
56
  directives = method_directives(node)
45
57
  return too_many_directives(node) if directives.size > 1
46
58
 
47
- directive = directives.first
48
- return if directive_correct?(directive, actual_name)
49
-
50
- register_offense(node, directive, actual_name)
59
+ process_directive(node, actual_name, directives.first)
51
60
  end
52
61
 
53
62
  private
54
63
 
55
64
  def valid_method_name?(node)
56
- node.arguments.first.str_type? || node.arguments.first.sym_type?
65
+ node.first_argument.str_type? || node.first_argument.sym_type?
57
66
  end
58
67
 
59
68
  def method_directives(node)
60
69
  comments = processed_source.ast_with_comments[node]
61
-
62
- comments.map do |comment|
63
- match = comment.text.match(REGEXP)
70
+ group_comments(comments).filter_map do |comment_method, comment_scope|
71
+ match = comment_method.text.match(REGEXP_METHOD)
64
72
  next unless match
65
73
 
66
- { node: comment, method_name: match[:method_name], args: match[:args] }
67
- end.compact
74
+ {
75
+ node_method: comment_method,
76
+ node_scope: comment_scope,
77
+ method_name: match[:method_name],
78
+ args: match[:args],
79
+ receiver: match[:receiver],
80
+ has_scope_directive: comment_scope&.text&.match?(REGEXP_SCOPE)
81
+ }
82
+ end
83
+ end
84
+
85
+ def group_comments(comments)
86
+ result = []
87
+ comments.each.with_index do |comment, index|
88
+ # Grab the scope directive if it is preceded by a method directive
89
+ if comment.text.include?('@!method')
90
+ result << if (next_comment = comments[index + 1])&.text&.include?('@!scope')
91
+ [comment, next_comment]
92
+ else
93
+ [comment, nil]
94
+ end
95
+ end
96
+ end
97
+ result
68
98
  end
69
99
 
70
100
  def too_many_directives(node)
71
101
  add_offense(node, message: MSG_TOO_MANY)
72
102
  end
73
103
 
74
- def directive_correct?(directive, actual_name)
75
- directive && directive[:method_name] == actual_name.to_s
104
+ def process_directive(node, actual_name, directive)
105
+ return unless (offense_type = directive_offense_type(directive, actual_name))
106
+
107
+ register_offense(offense_type, node, directive, actual_name)
76
108
  end
77
109
 
78
- def register_offense(node, directive, actual_name)
79
- message = formatted_message(directive, actual_name, node.method_name)
110
+ def directive_offense_type(directive, actual_name)
111
+ return :missing_directive unless directive
112
+
113
+ return :wrong_scope if wrong_scope(directive, actual_name)
114
+ return :no_scope if no_scope(directive, actual_name)
115
+
116
+ # The method directive being prefixed by 'self.' is always an offense.
117
+ # The matched method_name does not contain the receiver but the
118
+ # def_node_match method name may so it must be removed.
119
+ if directive[:method_name] != remove_receiver(actual_name) || directive[:receiver]
120
+ :wrong_name
121
+ end
122
+ end
123
+
124
+ def wrong_scope(directive, actual_name)
125
+ !actual_name.start_with?('self.') && directive[:has_scope_directive]
126
+ end
127
+
128
+ def no_scope(directive, actual_name)
129
+ actual_name.start_with?('self.') && !directive[:has_scope_directive]
130
+ end
131
+
132
+ def register_offense(offense_type, node, directive, actual_name)
133
+ message = formatted_message(offense_type, directive, actual_name, node.method_name)
80
134
 
81
135
  add_offense(node, message: message) do |corrector|
82
- if directive
83
- correct_directive(corrector, directive, actual_name)
84
- else
85
- insert_directive(corrector, node, actual_name)
136
+ case offense_type
137
+ when :wrong_name
138
+ correct_method_directive(corrector, directive, actual_name)
139
+ when :wrong_scope
140
+ remove_scope_directive(corrector, directive)
141
+ when :no_scope
142
+ insert_scope_directive(corrector, directive[:node_method])
143
+ when :missing_directive
144
+ insert_method_directive(corrector, node, actual_name)
86
145
  end
87
146
  end
88
147
  end
89
148
 
90
- def formatted_message(directive, actual_name, method_name)
91
- if directive
92
- format(MSG_WRONG_NAME, expected: actual_name, actual: directive[:method_name])
93
- else
149
+ # rubocop:disable Metrics/MethodLength
150
+ def formatted_message(offense_type, directive, actual_name, method_name)
151
+ case offense_type
152
+ when :wrong_name
153
+ # Add the receiver to the name when showing an offense
154
+ current_name = if directive[:receiver]
155
+ directive[:receiver] + directive[:method_name]
156
+ else
157
+ directive[:method_name]
158
+ end
159
+ # The correct name will never include a receiver, remove it
160
+ format(MSG_WRONG_NAME, expected: remove_receiver(actual_name), actual: current_name)
161
+ when :wrong_scope
162
+ MSG_WRONG_SCOPE_SELF
163
+ when :no_scope
164
+ MSG_MISSING_SCOPE_SELF
165
+ when :missing_directive
94
166
  format(MSG, method: method_name)
95
167
  end
96
168
  end
169
+ # rubocop:enable Metrics/MethodLength
170
+
171
+ def remove_receiver(current)
172
+ current.delete_prefix('self.')
173
+ end
97
174
 
98
- def insert_directive(corrector, node, actual_name)
175
+ def insert_method_directive(corrector, node, actual_name)
99
176
  # If the pattern matcher uses arguments (`%1`, `%2`, etc.), include them in the directive
100
177
  arguments = pattern_arguments(node.arguments[1].source)
101
178
 
@@ -107,6 +184,14 @@ module RuboCop
107
184
  corrector.insert_before(range, directive)
108
185
  end
109
186
 
187
+ def insert_scope_directive(corrector, node)
188
+ range = range_with_surrounding_space(node.source_range, side: :left, newlines: false)
189
+ indentation = range.source.match(/^\s*/)[0]
190
+ directive = "\n#{indentation}# @!scope class"
191
+
192
+ corrector.insert_after(node, directive)
193
+ end
194
+
110
195
  def pattern_arguments(pattern)
111
196
  arguments = %w[node]
112
197
  max_pattern_var = pattern.scan(/(?<=%)\d+/).map(&:to_i).max
@@ -117,11 +202,11 @@ module RuboCop
117
202
  def add_newline?(node)
118
203
  # Determine if a blank line should be inserted before the new directive
119
204
  # in order to spread out pattern matchers
120
- return if node.sibling_index&.zero?
121
- return unless node.parent
205
+ return false if node.sibling_index&.zero?
206
+ return false unless node.parent
122
207
 
123
208
  prev_sibling = node.parent.child_nodes[node.sibling_index - 1]
124
- return unless prev_sibling && pattern_matcher?(prev_sibling)
209
+ return false unless prev_sibling && pattern_matcher?(prev_sibling)
125
210
 
126
211
  node.loc.line == last_line(prev_sibling) + 1
127
212
  end
@@ -134,12 +219,21 @@ module RuboCop
134
219
  end
135
220
  end
136
221
 
137
- def correct_directive(corrector, directive, actual_name)
138
- correct = "@!method #{actual_name}"
139
- regexp = /@!method\s+#{Regexp.escape(directive[:method_name])}/
222
+ def correct_method_directive(corrector, directive, actual_name)
223
+ correct = "@!method #{remove_receiver(actual_name)}"
224
+ current_name = (directive[:receiver] || '') + directive[:method_name]
225
+ regexp = /@!method\s+#{Regexp.escape(current_name)}/
226
+
227
+ replacement = directive[:node_method].text.gsub(regexp, correct)
228
+ corrector.replace(directive[:node_method], replacement)
229
+ end
140
230
 
141
- replacement = directive[:node].text.gsub(regexp, correct)
142
- corrector.replace(directive[:node], replacement)
231
+ def remove_scope_directive(corrector, directive)
232
+ range = range_by_whole_lines(
233
+ directive[:node_scope].source_range,
234
+ include_final_newline: true
235
+ )
236
+ corrector.remove(range)
143
237
  end
144
238
  end
145
239
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for redundant arguments of `RuboCop::RSpec::ExpectOffense`'s methods.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # expect_no_offenses('code', keyword: keyword)
12
+ #
13
+ # # good
14
+ # expect_no_offenses('code')
15
+ #
16
+ class RedundantExpectOffenseArguments < Base
17
+ extend AutoCorrector
18
+
19
+ MSG = 'Remove the redundant arguments.'
20
+ RESTRICT_ON_SEND = %i[expect_no_offenses].freeze
21
+
22
+ def on_send(node)
23
+ return if node.arguments.one? || !node.arguments[1]&.hash_type?
24
+
25
+ range = node.first_argument.source_range.end.join(node.last_argument.source_range.end)
26
+
27
+ add_offense(range) do |corrector|
28
+ corrector.remove(range)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -14,6 +14,12 @@ module RuboCop
14
14
  # node.method_name
15
15
  #
16
16
  # # bad
17
+ # node.send_node.method?(:method_name)
18
+ #
19
+ # # good
20
+ # node.method?(:method_name)
21
+ #
22
+ # # bad
17
23
  # node.send_node.receiver
18
24
  #
19
25
  # # good
@@ -24,11 +30,14 @@ module RuboCop
24
30
  extend AutoCorrector
25
31
 
26
32
  MSG = 'Remove the redundant `send_node`.'
27
- RESTRICT_ON_SEND = %i[method_name receiver].freeze
33
+ RESTRICT_ON_SEND = %i[method_name method? receiver].freeze
28
34
 
29
35
  # @!method dispatch_method(node)
30
36
  def_node_matcher :dispatch_method, <<~PATTERN
31
- (send $(send _ :send_node) _)
37
+ {
38
+ (send $(send _ :send_node) {:method_name :receiver})
39
+ (send $(send _ :send_node) :method? _)
40
+ }
32
41
  PATTERN
33
42
 
34
43
  def on_send(node)
@@ -27,6 +27,8 @@ module RuboCop
27
27
  PATTERN
28
28
 
29
29
  def on_new_investigation
30
+ return if processed_source.blank?
31
+
30
32
  assertions_using_described_class_msg.each { |node| add_offense(node) }
31
33
  end
32
34
 
@@ -12,6 +12,7 @@ require_relative 'internal_affairs/location_line_equality_comparison'
12
12
  require_relative 'internal_affairs/method_name_end_with'
13
13
  require_relative 'internal_affairs/method_name_equal'
14
14
  require_relative 'internal_affairs/node_destructuring'
15
+ require_relative 'internal_affairs/node_first_or_last_argument'
15
16
  require_relative 'internal_affairs/node_matcher_directive'
16
17
  require_relative 'internal_affairs/node_type_predicate'
17
18
  require_relative 'internal_affairs/numblock_handler'
@@ -19,6 +20,7 @@ require_relative 'internal_affairs/offense_location_keyword'
19
20
  require_relative 'internal_affairs/processed_source_buffer_name'
20
21
  require_relative 'internal_affairs/redundant_context_config_parameter'
21
22
  require_relative 'internal_affairs/redundant_described_class_as_subject'
23
+ require_relative 'internal_affairs/redundant_expect_offense_arguments'
22
24
  require_relative 'internal_affairs/redundant_let_rubocop_config_new'
23
25
  require_relative 'internal_affairs/redundant_location_argument'
24
26
  require_relative 'internal_affairs/redundant_message_argument'
@@ -79,7 +79,7 @@ module RuboCop
79
79
 
80
80
  def arguments_with_last_arg_pairs(node)
81
81
  items = node.arguments[0..-2]
82
- last_arg = node.arguments.last
82
+ last_arg = node.last_argument
83
83
 
84
84
  if last_arg.hash_type? && !last_arg.braces?
85
85
  items += last_arg.pairs
@@ -68,6 +68,13 @@ module RuboCop
68
68
  # - extend
69
69
  # ----
70
70
  #
71
+ # @safety
72
+ # Autocorrection is unsafe because class methods and module inclusion
73
+ # can behave differently, based on which methods or constants have
74
+ # already been defined.
75
+ #
76
+ # Constants will only be moved when they are assigned with literals.
77
+ #
71
78
  # @example
72
79
  # # bad
73
80
  # # Expect extend be before constant
@@ -3,7 +3,6 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- #
7
6
  # Checks the indentation of here document closings.
8
7
  #
9
8
  # @example
@@ -73,7 +72,7 @@ module RuboCop
73
72
  end
74
73
 
75
74
  def argument_indentation_correct?(node)
76
- return unless node.argument? || node.chained?
75
+ return false unless node.argument? || node.chained?
77
76
 
78
77
  opening_indentation(
79
78
  find_node_used_heredoc_argument(node.parent)
@@ -32,7 +32,7 @@ module RuboCop
32
32
  end
33
33
 
34
34
  def on_send(node)
35
- return unless node.dot? || ampersand_dot?(node)
35
+ return unless node.dot? || node.safe_navigation?
36
36
 
37
37
  return correct_style_detected if proper_dot_position?(node)
38
38
 
@@ -133,10 +133,6 @@ module RuboCop
133
133
  # l.(1) has no selector, so we use the opening parenthesis instead
134
134
  node.loc.selector || node.loc.begin
135
135
  end
136
-
137
- def ampersand_dot?(node)
138
- node.loc.respond_to?(:dot) && node.loc.dot && node.loc.dot.is?('&.')
139
- end
140
136
  end
141
137
  end
142
138
  end
@@ -3,7 +3,23 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Enforces empty line after guard clause
6
+ # Enforces empty line after guard clause.
7
+ #
8
+ # This cop allows `# :nocov:` directive after guard clause because
9
+ # SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
10
+ #
11
+ # [source,ruby]
12
+ # ----
13
+ # def foo
14
+ # # :nocov:
15
+ # return if condition
16
+ # # :nocov:
17
+ # bar
18
+ # end
19
+ # ----
20
+ #
21
+ # Refer to SimpleCov's documentation for more details:
22
+ # https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
7
23
  #
8
24
  # @example
9
25
  #
@@ -42,19 +58,22 @@ module RuboCop
42
58
 
43
59
  MSG = 'Add empty line after guard clause.'
44
60
  END_OF_HEREDOC_LINE = 1
61
+ SIMPLE_DIRECTIVE_COMMENT_PATTERN = /\A# *:nocov:\z/.freeze
45
62
 
46
63
  def on_if(node)
47
64
  return if correct_style?(node)
48
65
  return if multiple_statements_on_line?(node)
49
66
 
50
67
  if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
51
- return if next_line_empty_or_enable_directive_comment?(heredoc_line(node, heredoc_node))
68
+ if next_line_empty_or_allowed_directive_comment?(heredoc_line(node, heredoc_node))
69
+ return
70
+ end
52
71
 
53
72
  add_offense(heredoc_node.loc.heredoc_end) do |corrector|
54
73
  autocorrect(corrector, heredoc_node)
55
74
  end
56
75
  else
57
- return if next_line_empty_or_enable_directive_comment?(node.last_line)
76
+ return if next_line_empty_or_allowed_directive_comment?(node.last_line)
58
77
 
59
78
  add_offense(offense_location(node)) { |corrector| autocorrect(corrector, node) }
60
79
  end
@@ -70,7 +89,7 @@ module RuboCop
70
89
  end
71
90
 
72
91
  next_line = node_range.last_line + 1
73
- if next_line_enable_directive_comment?(next_line)
92
+ if next_line_allowed_directive_comment?(next_line)
74
93
  node_range = processed_source.comment_at_line(next_line)
75
94
  end
76
95
 
@@ -88,21 +107,21 @@ module RuboCop
88
107
  node.if_branch&.guard_clause?
89
108
  end
90
109
 
91
- def next_line_empty_or_enable_directive_comment?(line)
110
+ def next_line_empty_or_allowed_directive_comment?(line)
92
111
  return true if next_line_empty?(line)
93
112
 
94
113
  next_line = line + 1
95
- next_line_enable_directive_comment?(next_line) && next_line_empty?(next_line)
114
+ next_line_allowed_directive_comment?(next_line) && next_line_empty?(next_line)
96
115
  end
97
116
 
98
117
  def next_line_empty?(line)
99
118
  processed_source[line].blank?
100
119
  end
101
120
 
102
- def next_line_enable_directive_comment?(line)
121
+ def next_line_allowed_directive_comment?(line)
103
122
  return false unless (comment = processed_source.comment_at_line(line))
104
123
 
105
- DirectiveComment.new(comment).enabled?
124
+ DirectiveComment.new(comment).enabled? || simplecov_directive_comment?(comment)
106
125
  end
107
126
 
108
127
  def next_line_rescue_or_ensure?(node)
@@ -137,7 +156,7 @@ module RuboCop
137
156
  return node if node
138
157
  end
139
158
 
140
- return last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
159
+ last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
141
160
  end
142
161
 
143
162
  def last_heredoc_argument_node(node)
@@ -145,6 +164,8 @@ module RuboCop
145
164
 
146
165
  if node.if_branch.and_type?
147
166
  node.if_branch.children.first
167
+ elsif use_heredoc_in_condition?(node.condition)
168
+ node.condition
148
169
  else
149
170
  node.if_branch.children.last
150
171
  end
@@ -161,6 +182,12 @@ module RuboCop
161
182
  node.respond_to?(:heredoc?) && node.heredoc?
162
183
  end
163
184
 
185
+ def use_heredoc_in_condition?(condition)
186
+ condition.descendants.any? do |descendant|
187
+ descendant.respond_to?(:heredoc?) && descendant.heredoc?
188
+ end
189
+ end
190
+
164
191
  def offense_location(node)
165
192
  if node.loc.respond_to?(:end) && node.loc.end
166
193
  node.loc.end
@@ -175,6 +202,12 @@ module RuboCop
175
202
 
176
203
  parent.begin_type? && parent.single_line?
177
204
  end
205
+
206
+ # SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
207
+ # https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
208
+ def simplecov_directive_comment?(comment)
209
+ SIMPLE_DIRECTIVE_COMMENT_PATTERN.match?(comment.text)
210
+ end
178
211
  end
179
212
  end
180
213
  end
@@ -27,9 +27,9 @@ module RuboCop
27
27
  MSG = 'Add an empty line after magic comments.'
28
28
 
29
29
  def on_new_investigation
30
- return unless processed_source.ast &&
31
- (last_magic_comment = last_magic_comment(processed_source))
32
- return if processed_source[last_magic_comment.loc.line].strip.empty?
30
+ return unless (last_magic_comment = last_magic_comment(processed_source))
31
+ return unless (next_line = processed_source[last_magic_comment.loc.line])
32
+ return if next_line.strip.empty?
33
33
 
34
34
  offending_range = offending_range(last_magic_comment)
35
35
 
@@ -46,18 +46,25 @@ module RuboCop
46
46
 
47
47
  # Find the last magic comment in the source file.
48
48
  #
49
- # Take all comments that precede the first line of code, select the
49
+ # Take all comments that precede the first line of code (or just take
50
+ # them all in the case when there is no code), select the
50
51
  # magic comments, and return the last magic comment in the file.
51
52
  #
52
53
  # @return [Parser::Source::Comment] if magic comments exist before code
53
54
  # @return [nil] otherwise
54
55
  def last_magic_comment(source)
55
- source
56
- .comments
57
- .take_while { |comment| comment.loc.line < source.ast.loc.line }
56
+ comments_before_code(source)
58
57
  .reverse
59
58
  .find { |comment| MagicComment.parse(comment.text).any? }
60
59
  end
60
+
61
+ def comments_before_code(source)
62
+ if source.ast
63
+ source.comments.take_while { |comment| comment.loc.line < source.ast.loc.line }
64
+ else
65
+ source.comments
66
+ end
67
+ end
61
68
  end
62
69
  end
63
70
  end
@@ -135,7 +135,8 @@ module RuboCop
135
135
  return if nodes.all?(&:single_line?) && cop_config['AllowAdjacentOneLineDefs']
136
136
 
137
137
  correction_node = nodes.last
138
- location = correction_node.loc.keyword.join(correction_node.loc.name)
138
+
139
+ location = def_location(correction_node)
139
140
  add_offense(location, message: message(correction_node, count: count)) do |corrector|
140
141
  autocorrect(corrector, *nodes, count)
141
142
  end
@@ -159,10 +160,28 @@ module RuboCop
159
160
 
160
161
  private
161
162
 
163
+ def def_location(correction_node)
164
+ if correction_node.block_type?
165
+ correction_node.source_range.join(correction_node.children.first.source_range)
166
+ else
167
+ correction_node.loc.keyword.join(correction_node.loc.name)
168
+ end
169
+ end
170
+
162
171
  def candidate?(node)
163
- return unless node
172
+ return false unless node
164
173
 
165
- method_candidate?(node) || class_candidate?(node) || module_candidate?(node)
174
+ method_candidate?(node) || class_candidate?(node) || module_candidate?(node) ||
175
+ macro_candidate?(node)
176
+ end
177
+
178
+ def empty_line_between_macros
179
+ cop_config.fetch('DefLikeMacros', []).map(&:to_sym)
180
+ end
181
+
182
+ def macro_candidate?(node)
183
+ node.block_type? && node.children.first.macro? &&
184
+ empty_line_between_macros.include?(node.children.first.method_name)
166
185
  end
167
186
 
168
187
  def method_candidate?(node)
@@ -226,7 +245,11 @@ module RuboCop
226
245
  end
227
246
 
228
247
  def def_start(node)
229
- node.loc.keyword.line
248
+ if node.block_type? && node.children.first.send_type?
249
+ node.source_range.line
250
+ else
251
+ node.loc.keyword.line
252
+ end
230
253
  end
231
254
 
232
255
  def def_end(node)
@@ -68,6 +68,8 @@ module RuboCop
68
68
  check_body(node.body, node.loc.line)
69
69
  end
70
70
  alias on_defs on_def
71
+ alias on_block on_def
72
+ alias on_numblock on_def
71
73
 
72
74
  def on_kwbegin(node)
73
75
  body, = *node
@@ -20,7 +20,9 @@ module RuboCop
20
20
  # This `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`)
21
21
  # by default. On the other hand, `Layout/BeginEndAlignment` cop aligns with
22
22
  # `EnforcedStyleAlignWith: start_of_line` by default due to `||= begin` tends
23
- # to align with the start of the line. These style can be configured by each cop.
23
+ # to align with the start of the line. `Layout/DefEndAlignment` cop also aligns with
24
+ # `EnforcedStyleAlignWith: start_of_line` by default.
25
+ # These style can be configured by each cop.
24
26
  #
25
27
  # @example EnforcedStyleAlignWith: keyword (default)
26
28
  # # bad
@@ -83,7 +85,11 @@ module RuboCop
83
85
  end
84
86
 
85
87
  def on_sclass(node)
86
- check_other_alignment(node)
88
+ if node.parent&.assignment?
89
+ check_asgn_alignment(node.parent, node)
90
+ else
91
+ check_other_alignment(node)
92
+ end
87
93
  end
88
94
 
89
95
  def on_module(node)
@@ -163,7 +169,13 @@ module RuboCop
163
169
  when :keyword
164
170
  node
165
171
  when :variable
166
- alignment_node_for_variable_style(node)
172
+ align_to = alignment_node_for_variable_style(node)
173
+
174
+ while (parent = align_to.parent) && parent.send_type? && same_line?(align_to, parent)
175
+ align_to = parent
176
+ end
177
+
178
+ align_to
167
179
  else
168
180
  start_line_range(node)
169
181
  end