rubocop 1.18.1 → 1.22.3

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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +116 -23
  4. data/lib/rubocop/cli.rb +18 -0
  5. data/lib/rubocop/config.rb +5 -0
  6. data/lib/rubocop/config_loader.rb +5 -3
  7. data/lib/rubocop/config_loader_resolver.rb +22 -7
  8. data/lib/rubocop/config_validator.rb +27 -6
  9. data/lib/rubocop/cop/base.rb +3 -3
  10. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  11. data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
  12. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
  13. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  14. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
  15. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  16. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
  17. data/lib/rubocop/cop/correctors/require_library_corrector.rb +23 -0
  18. data/lib/rubocop/cop/documentation.rb +1 -1
  19. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  20. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +31 -24
  21. data/lib/rubocop/cop/generator.rb +14 -8
  22. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +34 -0
  23. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
  24. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  25. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +71 -0
  26. data/lib/rubocop/cop/internal_affairs.rb +3 -0
  27. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  28. data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
  29. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  30. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  31. data/lib/rubocop/cop/layout/dot_position.rb +34 -5
  32. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  33. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -0
  34. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
  35. data/lib/rubocop/cop/layout/end_alignment.rb +9 -2
  36. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  37. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
  38. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  39. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  40. data/lib/rubocop/cop/layout/hash_alignment.rb +22 -18
  41. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  42. data/lib/rubocop/cop/layout/heredoc_indentation.rb +0 -7
  43. data/lib/rubocop/cop/layout/indentation_style.rb +2 -2
  44. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  45. data/lib/rubocop/cop/layout/leading_comment_space.rb +2 -2
  46. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +36 -17
  47. data/lib/rubocop/cop/layout/line_length.rb +9 -7
  48. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  49. data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -3
  50. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
  51. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  52. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  53. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +23 -10
  54. data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
  55. data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
  56. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
  57. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  58. data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
  59. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
  60. data/lib/rubocop/cop/layout/space_before_comment.rb +2 -2
  61. data/lib/rubocop/cop/layout/space_inside_parens.rb +78 -32
  62. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
  63. data/lib/rubocop/cop/layout/trailing_whitespace.rb +24 -1
  64. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
  65. data/lib/rubocop/cop/lint/ambiguous_range.rb +105 -0
  66. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +5 -2
  67. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  68. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  69. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  70. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  71. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  72. data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
  73. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  74. data/lib/rubocop/cop/lint/duplicate_branch.rb +2 -1
  75. data/lib/rubocop/cop/lint/duplicate_methods.rb +8 -5
  76. data/lib/rubocop/cop/lint/else_layout.rb +10 -6
  77. data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
  78. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  79. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  80. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  81. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
  82. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  83. data/lib/rubocop/cop/lint/loop.rb +4 -3
  84. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  85. data/lib/rubocop/cop/lint/number_conversion.rb +12 -1
  86. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  87. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  88. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  89. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  90. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  91. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  92. data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
  93. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -1
  94. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  95. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  96. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  97. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  98. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
  99. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  100. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  101. data/lib/rubocop/cop/lint/useless_times.rb +5 -4
  102. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  103. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  104. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  105. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  106. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  107. data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
  108. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  109. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  110. data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
  111. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
  112. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -1
  113. data/lib/rubocop/cop/mixin/hash_transform_method.rb +9 -4
  114. data/lib/rubocop/cop/mixin/heredoc.rb +5 -0
  115. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  116. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  117. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  118. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  119. data/lib/rubocop/cop/mixin/percent_array.rb +18 -7
  120. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
  121. data/lib/rubocop/cop/mixin/require_library.rb +59 -0
  122. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  123. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +2 -2
  124. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  125. data/lib/rubocop/cop/mixin/string_literals_help.rb +5 -1
  126. data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
  127. data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
  128. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  129. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  130. data/lib/rubocop/cop/naming/inclusive_language.rb +27 -10
  131. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  132. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  133. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  134. data/lib/rubocop/cop/security/json_load.rb +8 -7
  135. data/lib/rubocop/cop/security/open.rb +4 -0
  136. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  137. data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
  138. data/lib/rubocop/cop/style/and_or.rb +5 -0
  139. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  140. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  141. data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
  142. data/lib/rubocop/cop/style/block_delimiters.rb +50 -2
  143. data/lib/rubocop/cop/style/case_equality.rb +6 -9
  144. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  145. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  146. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  147. data/lib/rubocop/cop/style/collection_methods.rb +8 -6
  148. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  149. data/lib/rubocop/cop/style/comment_annotation.rb +55 -25
  150. data/lib/rubocop/cop/style/commented_keyword.rb +9 -3
  151. data/lib/rubocop/cop/style/conditional_assignment.rb +19 -5
  152. data/lib/rubocop/cop/style/date_time.rb +5 -0
  153. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  154. data/lib/rubocop/cop/style/documentation.rb +23 -8
  155. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -7
  156. data/lib/rubocop/cop/style/double_negation.rb +27 -6
  157. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  158. data/lib/rubocop/cop/style/encoding.rb +26 -15
  159. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  160. data/lib/rubocop/cop/style/explicit_block_argument.rb +46 -11
  161. data/lib/rubocop/cop/style/float_division.rb +10 -2
  162. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +14 -3
  163. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  164. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
  165. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  166. data/lib/rubocop/cop/style/hash_except.rb +4 -3
  167. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  168. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -9
  169. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  170. data/lib/rubocop/cop/style/identical_conditional_branches.rb +32 -5
  171. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
  172. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  173. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  174. data/lib/rubocop/cop/style/lambda_call.rb +1 -1
  175. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -1
  176. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
  177. data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -1
  178. data/lib/rubocop/cop/style/missing_else.rb +7 -0
  179. data/lib/rubocop/cop/style/module_function.rb +8 -9
  180. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  181. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  182. data/lib/rubocop/cop/style/mutable_constant.rb +79 -14
  183. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  184. data/lib/rubocop/cop/style/negated_unless.rb +1 -1
  185. data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
  186. data/lib/rubocop/cop/style/not.rb +2 -2
  187. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  188. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  189. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  190. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  191. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  192. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  193. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  194. data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
  195. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  196. data/lib/rubocop/cop/style/quoted_symbols.rb +10 -6
  197. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  198. data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
  199. data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
  200. data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
  201. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  202. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  203. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
  204. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  205. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
  206. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  207. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  208. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +83 -0
  209. data/lib/rubocop/cop/style/redundant_sort.rb +53 -20
  210. data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
  211. data/lib/rubocop/cop/style/return_nil.rb +2 -1
  212. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  213. data/lib/rubocop/cop/style/select_by_regexp.rb +139 -0
  214. data/lib/rubocop/cop/style/semicolon.rb +32 -24
  215. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  216. data/lib/rubocop/cop/style/single_line_block_params.rb +3 -1
  217. data/lib/rubocop/cop/style/single_line_methods.rb +25 -15
  218. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  219. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
  220. data/lib/rubocop/cop/style/special_global_vars.rb +25 -0
  221. data/lib/rubocop/cop/style/static_class.rb +5 -5
  222. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  223. data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
  224. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  225. data/lib/rubocop/cop/style/struct_inheritance.rb +4 -0
  226. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  227. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  228. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  229. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  230. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  231. data/lib/rubocop/cop/style/word_array.rb +23 -5
  232. data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
  233. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  234. data/lib/rubocop/cop/util.rb +22 -6
  235. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  236. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -1
  237. data/lib/rubocop/magic_comment.rb +44 -15
  238. data/lib/rubocop/options.rb +127 -113
  239. data/lib/rubocop/rake_task.rb +1 -1
  240. data/lib/rubocop/result_cache.rb +3 -3
  241. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  242. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  243. data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
  244. data/lib/rubocop/rspec/support.rb +1 -0
  245. data/lib/rubocop/runner.rb +2 -3
  246. data/lib/rubocop/target_finder.rb +1 -1
  247. data/lib/rubocop/version.rb +1 -1
  248. data/lib/rubocop.rb +14 -2
  249. metadata +21 -5
@@ -6,6 +6,11 @@ module RuboCop
6
6
  # This cop identifies places where `if-elsif` constructions
7
7
  # can be replaced with `case-when`.
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe. `case` statements use `===` for equality,
11
+ # so if the original conditional used a different equality operator, the
12
+ # behaviour may be different.
13
+ #
9
14
  # @example
10
15
  # # bad
11
16
  # if status == :active
@@ -6,6 +6,15 @@ module RuboCop
6
6
  # This cop checks the style of children definitions at classes and
7
7
  # modules. Basically there are two different styles:
8
8
  #
9
+ # @safety
10
+ # Autocorrection is unsafe.
11
+ #
12
+ # Moving from compact to nested children requires knowledge of whether the
13
+ # outer parent is a module or a class. Moving from nested to compact requires
14
+ # verification that the outer parent is defined elsewhere. Rubocop does not
15
+ # have the knowledge to perform either operation safely and thus requires
16
+ # manual oversight.
17
+ #
9
18
  # @example EnforcedStyle: nested (default)
10
19
  # # good
11
20
  # # have each child on its own line
@@ -6,11 +6,13 @@ module RuboCop
6
6
  # This cop checks for places where custom logic on rejection nils from arrays
7
7
  # and hashes can be replaced with `{Array,Hash}#{compact,compact!}`.
8
8
  #
9
- # It is marked as unsafe by default because false positives may occur in the
10
- # nil check of block arguments to the receiver object.
11
- # For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
12
- # and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
13
- # when the receiver is a hash object.
9
+ # @safety
10
+ # It is unsafe by default because false positives may occur in the
11
+ # `nil` check of block arguments to the receiver object.
12
+ #
13
+ # For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
14
+ # and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
15
+ # when the receiver is a hash object.
14
16
  #
15
17
  # @example
16
18
  # # bad
@@ -6,10 +6,6 @@ module RuboCop
6
6
  # This cop enforces the use of consistent method names
7
7
  # from the Enumerable module.
8
8
  #
9
- # Unfortunately we cannot actually know if a method is from
10
- # Enumerable or not (static analysis limitation), so this cop
11
- # can yield some false positives.
12
- #
13
9
  # You can customize the mapping from undesired method to desired method.
14
10
  #
15
11
  # e.g. to use `detect` over `find`:
@@ -18,9 +14,14 @@ module RuboCop
18
14
  # PreferredMethods:
19
15
  # find: detect
20
16
  #
21
- # The default mapping for `PreferredMethods` behaves as follows.
17
+ # @safety
18
+ # This cop is unsafe because it finds methods by name, without actually
19
+ # being able to determine if the receiver is an Enumerable or not, so
20
+ # this cop may register false positives.
22
21
  #
23
22
  # @example
23
+ # # These examples are based on the default mapping for `PreferredMethods`.
24
+ #
24
25
  # # bad
25
26
  # items.collect
26
27
  # items.collect!
@@ -68,7 +69,8 @@ module RuboCop
68
69
  return false unless node.arguments.any?
69
70
 
70
71
  node.last_argument.block_pass_type? ||
71
- node.last_argument.sym_type? && methods_accepting_symbol.include?(node.method_name.to_s)
72
+ (node.last_argument.sym_type? &&
73
+ methods_accepting_symbol.include?(node.method_name.to_s))
72
74
  end
73
75
 
74
76
  def message(node)
@@ -7,8 +7,9 @@ module RuboCop
7
7
  # can be combined into a single loop. It is very likely that combining them
8
8
  # will make the code more efficient and more concise.
9
9
  #
10
- # It is marked as unsafe, because the first loop might modify
11
- # a state that the second loop depends on; these two aren't combinable.
10
+ # @safety
11
+ # The cop is unsafe, because the first loop might modify state that the
12
+ # second loop depends on; these two aren't combinable.
12
13
  #
13
14
  # @example
14
15
  # # bad
@@ -6,13 +6,16 @@ module RuboCop
6
6
  # This cop checks that comment annotation keywords are written according
7
7
  # to guidelines.
8
8
  #
9
+ # Annotation keywords can be specified by overriding the cop's `Keywords`
10
+ # configuration. Keywords are allowed to be single words or phrases.
11
+ #
9
12
  # NOTE: With a multiline comment block (where each line is only a
10
13
  # comment), only the first line will be able to register an offense, even
11
14
  # if an annotation keyword starts another line. This is done to prevent
12
15
  # incorrect registering of keywords (eg. `review`) inside a paragraph as an
13
16
  # annotation.
14
17
  #
15
- # @example
18
+ # @example RequireColon: true (default)
16
19
  # # bad
17
20
  # # TODO make better
18
21
  #
@@ -36,14 +39,35 @@ module RuboCop
36
39
  #
37
40
  # # good
38
41
  # # OPTIMIZE: does not work
42
+ #
43
+ # @example RequireColon: false
44
+ # # bad
45
+ # # TODO: make better
46
+ #
47
+ # # good
48
+ # # TODO make better
49
+ #
50
+ # # bad
51
+ # # fixme does not work
52
+ #
53
+ # # good
54
+ # # FIXME does not work
55
+ #
56
+ # # bad
57
+ # # Optimize does not work
58
+ #
59
+ # # good
60
+ # # OPTIMIZE does not work
39
61
  class CommentAnnotation < Base
40
- include AnnotationComment
41
62
  include RangeHelp
42
63
  extend AutoCorrector
43
64
 
44
- MSG = 'Annotation keywords like `%<keyword>s` should be all ' \
45
- 'upper case, followed by a colon, and a space, ' \
46
- 'then a note describing the problem.'
65
+ MSG_COLON_STYLE = 'Annotation keywords like `%<keyword>s` should be all ' \
66
+ 'upper case, followed by a colon, and a space, ' \
67
+ 'then a note describing the problem.'
68
+ MSG_SPACE_STYLE = 'Annotation keywords like `%<keyword>s` should be all ' \
69
+ 'upper case, followed by a space, ' \
70
+ 'then a note describing the problem.'
47
71
  MISSING_NOTE = 'Annotation comment, with keyword `%<keyword>s`, is missing a note.'
48
72
 
49
73
  def on_new_investigation
@@ -51,25 +75,27 @@ module RuboCop
51
75
  next unless first_comment_line?(processed_source.comments, index) ||
52
76
  inline_comment?(comment)
53
77
 
54
- margin, first_word, colon, space, note = split_comment(comment)
55
- next unless annotation?(comment) && !correct_annotation?(first_word, colon, space, note)
78
+ annotation = AnnotationComment.new(comment, keywords)
79
+ next unless annotation.annotation? && !annotation.correct?(colon: requires_colon?)
56
80
 
57
- range = annotation_range(comment, margin, first_word, colon, space)
58
-
59
- register_offense(range, note, first_word)
81
+ register_offense(annotation)
60
82
  end
61
83
  end
62
84
 
63
85
  private
64
86
 
65
- def register_offense(range, note, first_word)
66
- add_offense(
67
- range,
68
- message: format(note ? MSG : MISSING_NOTE, keyword: first_word)
69
- ) do |corrector|
70
- next if note.nil?
87
+ def register_offense(annotation)
88
+ range = annotation_range(annotation)
89
+ message = if annotation.note
90
+ requires_colon? ? MSG_COLON_STYLE : MSG_SPACE_STYLE
91
+ else
92
+ MISSING_NOTE
93
+ end
94
+
95
+ add_offense(range, message: format(message, keyword: annotation.keyword)) do |corrector|
96
+ next if annotation.note.nil?
71
97
 
72
- corrector.replace(range, "#{first_word.upcase}: ")
98
+ correct_offense(corrector, range, annotation.keyword)
73
99
  end
74
100
  end
75
101
 
@@ -81,18 +107,22 @@ module RuboCop
81
107
  !comment_line?(comment.loc.expression.source_line)
82
108
  end
83
109
 
84
- def annotation_range(comment, margin, first_word, colon, space)
85
- start = comment.loc.expression.begin_pos + margin.length
86
- length = concat_length(first_word, colon, space)
87
- range_between(start, start + length)
110
+ def annotation_range(annotation)
111
+ range_between(*annotation.bounds)
112
+ end
113
+
114
+ def correct_offense(corrector, range, keyword)
115
+ return corrector.replace(range, "#{keyword.upcase}: ") if requires_colon?
116
+
117
+ corrector.replace(range, "#{keyword.upcase} ")
88
118
  end
89
119
 
90
- def concat_length(*args)
91
- args.reduce(0) { |acc, elem| acc + elem.to_s.length }
120
+ def requires_colon?
121
+ cop_config['RequireColon']
92
122
  end
93
123
 
94
- def correct_annotation?(first_word, colon, space, note)
95
- keyword?(first_word) && (colon && space && note || !colon && !note)
124
+ def keywords
125
+ cop_config['Keywords']
96
126
  end
97
127
  end
98
128
  end
@@ -13,6 +13,10 @@ module RuboCop
13
13
  # Auto-correction removes comments from `end` keyword and keeps comments
14
14
  # for `class`, `module`, `def` and `begin` above the keyword.
15
15
  #
16
+ # @safety
17
+ # Auto-correction is unsafe because it may remove a comment that is
18
+ # meaningful.
19
+ #
16
20
  # @example
17
21
  # # bad
18
22
  # if condition
@@ -48,9 +52,11 @@ module RuboCop
48
52
  ALLOWED_COMMENTS = %w[:nodoc: :yields: rubocop:disable rubocop:todo].freeze
49
53
  ALLOWED_COMMENT_REGEXES = ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ }.freeze
50
54
 
55
+ REGEXP = /(?<keyword>\S+).*#/.freeze
56
+
51
57
  def on_new_investigation
52
58
  processed_source.comments.each do |comment|
53
- next unless (match = line(comment).match(/(?<keyword>\S+).*#/)) && offensive?(comment)
59
+ next unless offensive?(comment) && (match = source_line(comment).match(REGEXP))
54
60
 
55
61
  register_offense(comment, match[:keyword])
56
62
  end
@@ -72,12 +78,12 @@ module RuboCop
72
78
  end
73
79
 
74
80
  def offensive?(comment)
75
- line = line(comment)
81
+ line = source_line(comment)
76
82
  KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
77
83
  ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
78
84
  end
79
85
 
80
- def line(comment)
86
+ def source_line(comment)
81
87
  comment.location.expression.source_line
82
88
  end
83
89
  end
@@ -26,7 +26,7 @@ module RuboCop
26
26
  # `when` nodes contain the entire branch including the condition.
27
27
  # We only need the contents of the branch, not the condition.
28
28
  def expand_when_branches(when_branches)
29
- when_branches.map { |branch| branch.children[1] }
29
+ when_branches.map(&:body)
30
30
  end
31
31
 
32
32
  def tail(branch)
@@ -272,6 +272,16 @@ module RuboCop
272
272
  check_node(node, branches)
273
273
  end
274
274
 
275
+ def on_case_match(node)
276
+ return unless style == :assign_to_condition
277
+ return unless node.else_branch
278
+
279
+ in_pattern_branches = expand_when_branches(node.in_pattern_branches)
280
+ branches = [*in_pattern_branches, node.else_branch]
281
+
282
+ check_node(node, branches)
283
+ end
284
+
275
285
  private
276
286
 
277
287
  def check_assignment_to_condition(node)
@@ -297,7 +307,7 @@ module RuboCop
297
307
  end
298
308
 
299
309
  # @!method candidate_condition?(node)
300
- def_node_matcher :candidate_condition?, '[{if case} !#allowed_ternary?]'
310
+ def_node_matcher :candidate_condition?, '[{if case case_match} !#allowed_ternary?]'
301
311
 
302
312
  def allowed_ternary?(assignment)
303
313
  assignment.if_type? && assignment.ternary? && !include_ternary?
@@ -319,7 +329,7 @@ module RuboCop
319
329
  end
320
330
 
321
331
  def move_assignment_outside_condition(corrector, node)
322
- if node.case_type?
332
+ if node.case_type? || node.case_match_type?
323
333
  CaseCorrector.correct(corrector, self, node)
324
334
  elsif node.ternary?
325
335
  TernaryCorrector.correct(corrector, node)
@@ -333,7 +343,7 @@ module RuboCop
333
343
 
334
344
  if ternary_condition?(condition)
335
345
  TernaryCorrector.move_assignment_inside_condition(corrector, node)
336
- elsif condition.case_type?
346
+ elsif condition.case_type? || condition.case_match_type?
337
347
  CaseCorrector.move_assignment_inside_condition(corrector, node)
338
348
  elsif condition.if_type?
339
349
  IfCorrector.move_assignment_inside_condition(corrector, node)
@@ -631,7 +641,11 @@ module RuboCop
631
641
  end
632
642
 
633
643
  def extract_branches(case_node)
634
- when_branches = expand_when_branches(case_node.when_branches)
644
+ when_branches = if case_node.case_type?
645
+ expand_when_branches(case_node.when_branches)
646
+ else
647
+ expand_when_branches(case_node.in_pattern_branches)
648
+ end
635
649
 
636
650
  [when_branches, case_node.else_branch]
637
651
  end
@@ -9,6 +9,11 @@ module RuboCop
9
9
  # replaceable in certain situations when dealing with multiple timezones
10
10
  # and/or DST.
11
11
  #
12
+ # @safety
13
+ # Autocorrection is not safe, because `DateTime` and `Time` do not have
14
+ # exactly the same behaviour, although in most cases the autocorrection
15
+ # will be fine.
16
+ #
12
17
  # @example
13
18
  #
14
19
  # # bad - uses `DateTime` for current time
@@ -86,7 +86,7 @@ module RuboCop
86
86
 
87
87
  return unless arg_node&.dstr_type? && interpolated?(arg_node)
88
88
  return if inline_comment_docs?(arg_node) ||
89
- arg_node.heredoc? && comment_block_docs?(arg_node)
89
+ (arg_node.heredoc? && comment_block_docs?(arg_node))
90
90
 
91
91
  add_offense(node.loc.selector)
92
92
  end
@@ -71,8 +71,9 @@ module RuboCop
71
71
  #
72
72
  class Documentation < Base
73
73
  include DocumentationComment
74
+ include RangeHelp
74
75
 
75
- MSG = 'Missing top-level %<type>s documentation comment.'
76
+ MSG = 'Missing top-level documentation comment for `%<type>s %<identifier>s`.'
76
77
 
77
78
  # @!method constant_definition?(node)
78
79
  def_node_matcher :constant_definition?, '{class module casgn}'
@@ -88,33 +89,35 @@ module RuboCop
88
89
  def on_class(node)
89
90
  return unless node.body
90
91
 
91
- check(node, node.body, :class)
92
+ check(node, node.body)
92
93
  end
93
94
 
94
95
  def on_module(node)
95
- check(node, node.body, :module)
96
+ check(node, node.body)
96
97
  end
97
98
 
98
99
  private
99
100
 
100
- def check(node, body, type)
101
+ def check(node, body)
101
102
  return if namespace?(body)
102
103
  return if documentation_comment?(node)
103
104
  return if constant_allowed?(node)
104
105
  return if nodoc_self_or_outer_module?(node)
105
106
  return if macro_only?(body)
106
107
 
107
- add_offense(node.loc.keyword, message: format(MSG, type: type))
108
+ range = range_between(node.loc.expression.begin_pos, node.loc.name.end_pos)
109
+ message = format(MSG, type: node.type, identifier: identifier(node))
110
+ add_offense(range, message: message)
108
111
  end
109
112
 
110
113
  def nodoc_self_or_outer_module?(node)
111
114
  nodoc_comment?(node) ||
112
- compact_namespace?(node) && nodoc_comment?(outer_module(node).first)
115
+ (compact_namespace?(node) && nodoc_comment?(outer_module(node).first))
113
116
  end
114
117
 
115
118
  def macro_only?(body)
116
- body.respond_to?(:macro?) && body.macro? ||
117
- body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) }
119
+ (body.respond_to?(:macro?) && body.macro?) ||
120
+ (body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) })
118
121
  end
119
122
 
120
123
  def namespace?(node)
@@ -165,6 +168,18 @@ module RuboCop
165
168
  def allowed_constants
166
169
  @allowed_constants ||= cop_config.fetch('AllowedConstants', []).map(&:intern)
167
170
  end
171
+
172
+ def identifier(node)
173
+ # Get the fully qualified identifier for a class/module
174
+ nodes = [node, *node.each_ancestor(:class, :module)]
175
+ nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
176
+ end
177
+
178
+ def qualify_const(node)
179
+ return if node.nil?
180
+
181
+ [qualify_const(node.namespace), node.short_name].compact
182
+ end
168
183
  end
169
184
  end
170
185
  end
@@ -36,13 +36,7 @@ module RuboCop
36
36
  next unless comment.text.scan(/# rubocop:(?:disable|todo)/).size > 1
37
37
 
38
38
  add_offense(comment) do |corrector|
39
- prefix = if comment.text.start_with?('# rubocop:disable')
40
- '# rubocop:disable'
41
- else
42
- '# rubocop:todo'
43
- end
44
-
45
- corrector.replace(comment, comment.text[/#{prefix} \S+/])
39
+ corrector.replace(comment, comment.text.gsub(%r{ # rubocop:(disable|todo)}, ','))
46
40
  end
47
41
  end
48
42
  end
@@ -9,6 +9,21 @@ module RuboCop
9
9
  # that use boolean as a return value. When using `EnforcedStyle: forbidden`, double negation
10
10
  # should be forbidden always.
11
11
  #
12
+ # NOTE: when `something` is a boolean value
13
+ # `!!something` and `!something.nil?` are not the same thing.
14
+ # As you're unlikely to write code that can accept values of any type
15
+ # this is rarely a problem in practice.
16
+ #
17
+ # @safety
18
+ # Autocorrection is unsafe when the value is `false`, because the result
19
+ # of the expression will change.
20
+ #
21
+ # [source,ruby]
22
+ # ----
23
+ # !!false #=> false
24
+ # !false.nil? #=> true
25
+ # ----
26
+ #
12
27
  # @example
13
28
  # # bad
14
29
  # !!something
@@ -27,11 +42,6 @@ module RuboCop
27
42
  # def foo?
28
43
  # !!return_value
29
44
  # end
30
- #
31
- # Please, note that when something is a boolean value
32
- # !!something and !something.nil? are not the same thing.
33
- # As you're unlikely to write code that can accept values of any type
34
- # this is rarely a problem in practice.
35
45
  class DoubleNegation < Base
36
46
  include ConfigurableEnforcedStyle
37
47
  extend AutoCorrector
@@ -62,7 +72,7 @@ module RuboCop
62
72
  def end_of_method_definition?(node)
63
73
  return false unless (def_node = find_def_node_from_ascendant(node))
64
74
 
65
- last_child = def_node.child_nodes.last
75
+ last_child = find_last_child(def_node.body)
66
76
 
67
77
  last_child.last_line == node.last_line
68
78
  end
@@ -73,6 +83,17 @@ module RuboCop
73
83
 
74
84
  find_def_node_from_ascendant(node.parent)
75
85
  end
86
+
87
+ def find_last_child(node)
88
+ case node.type
89
+ when :rescue
90
+ find_last_child(node.body)
91
+ when :ensure
92
+ find_last_child(node.child_nodes.first)
93
+ else
94
+ node.child_nodes.last
95
+ end
96
+ end
76
97
  end
77
98
  end
78
99
  end
@@ -62,7 +62,7 @@ module RuboCop
62
62
  end
63
63
 
64
64
  def correct_style?(node)
65
- compact_style? && compact?(node) || expanded_style? && expanded?(node)
65
+ (compact_style? && compact?(node)) || (expanded_style? && expanded?(node))
66
66
  end
67
67
 
68
68
  def corrected(node)
@@ -13,38 +13,49 @@ module RuboCop
13
13
  include RangeHelp
14
14
  extend AutoCorrector
15
15
 
16
- MSG_UNNECESSARY = 'Unnecessary utf-8 encoding comment.'
16
+ MSG = 'Unnecessary utf-8 encoding comment.'
17
17
  ENCODING_PATTERN = /#.*coding\s?[:=]\s?(?:UTF|utf)-8/.freeze
18
18
  SHEBANG = '#!'
19
19
 
20
20
  def on_new_investigation
21
21
  return if processed_source.buffer.source.empty?
22
22
 
23
- line_number = encoding_line_number(processed_source)
24
- return unless (@message = offense(processed_source, line_number))
23
+ comments.each do |line_number, comment|
24
+ next unless offense?(comment)
25
25
 
26
- range = processed_source.buffer.line_range(line_number + 1)
27
- add_offense(range, message: @message) do |corrector|
28
- corrector.remove(range_with_surrounding_space(range: range, side: :right))
26
+ register_offense(line_number, comment)
29
27
  end
30
28
  end
31
29
 
32
30
  private
33
31
 
34
- def offense(processed_source, line_number)
35
- line = processed_source[line_number]
32
+ def comments
33
+ processed_source.lines.each.with_index.with_object({}) do |(line, line_number), comments|
34
+ next if line.start_with?(SHEBANG)
36
35
 
37
- MSG_UNNECESSARY if encoding_omitable?(line)
36
+ comment = MagicComment.parse(line)
37
+ return comments unless comment.valid?
38
+
39
+ comments[line_number + 1] = comment
40
+ end
38
41
  end
39
42
 
40
- def encoding_omitable?(line)
41
- ENCODING_PATTERN.match?(line)
43
+ def offense?(comment)
44
+ comment.encoding_specified? && comment.encoding.casecmp('utf-8').zero?
42
45
  end
43
46
 
44
- def encoding_line_number(processed_source)
45
- line_number = 0
46
- line_number += 1 if processed_source[line_number].start_with?(SHEBANG)
47
- line_number
47
+ def register_offense(line_number, comment)
48
+ range = processed_source.buffer.line_range(line_number)
49
+
50
+ add_offense(range) do |corrector|
51
+ text = comment.without(:encoding)
52
+
53
+ if text.blank?
54
+ corrector.remove(range_with_surrounding_space(range: range, side: :right))
55
+ else
56
+ corrector.replace(range, text)
57
+ end
58
+ end
48
59
  end
49
60
  end
50
61
  end
@@ -43,7 +43,7 @@ module RuboCop
43
43
  # RUBY
44
44
  #
45
45
  # This cop works only when a string literal is given as a code string.
46
- # No offence is reported if a string variable is given as below:
46
+ # No offense is reported if a string variable is given as below:
47
47
  #
48
48
  # @example
49
49
  # # not checked