rubocop 1.19.0 → 1.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (236) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +129 -21
  4. data/lib/rubocop/config.rb +5 -0
  5. data/lib/rubocop/config_loader.rb +5 -3
  6. data/lib/rubocop/config_validator.rb +9 -1
  7. data/lib/rubocop/cop/base.rb +3 -3
  8. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  9. data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
  10. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
  11. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  12. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
  13. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  14. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
  15. data/lib/rubocop/cop/documentation.rb +1 -1
  16. data/lib/rubocop/cop/gemspec/date_assignment.rb +2 -10
  17. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
  18. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  19. data/lib/rubocop/cop/gemspec/require_mfa.rb +146 -0
  20. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +31 -24
  21. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
  22. data/lib/rubocop/cop/generator.rb +14 -8
  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.rb +1 -0
  26. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  27. data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
  28. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  29. data/lib/rubocop/cop/layout/class_structure.rb +2 -1
  30. data/lib/rubocop/cop/layout/dot_position.rb +34 -5
  31. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  32. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
  33. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
  34. data/lib/rubocop/cop/layout/end_alignment.rb +2 -3
  35. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  37. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  38. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  39. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  40. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  41. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  42. data/lib/rubocop/cop/layout/line_length.rb +9 -7
  43. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  44. data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -3
  45. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
  46. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  47. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  48. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +6 -5
  49. data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
  50. data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
  51. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
  52. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  53. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
  54. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  55. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
  56. data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -28
  57. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
  58. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
  59. data/lib/rubocop/cop/lint/ambiguous_range.rb +11 -11
  60. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  61. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  62. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  63. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  64. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  65. data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
  66. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  67. data/lib/rubocop/cop/lint/else_layout.rb +10 -6
  68. data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
  69. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  70. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  71. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  72. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
  73. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  74. data/lib/rubocop/cop/lint/loop.rb +4 -3
  75. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  76. data/lib/rubocop/cop/lint/number_conversion.rb +16 -2
  77. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  78. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  79. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  80. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  81. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  82. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  83. data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
  84. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  85. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  86. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  87. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  88. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
  89. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  90. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
  91. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  92. data/lib/rubocop/cop/lint/useless_times.rb +4 -3
  93. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  94. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  95. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  96. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  97. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  98. data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
  99. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  100. data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
  101. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
  102. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -1
  103. data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
  104. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  105. data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
  106. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  107. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  108. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  109. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  110. data/lib/rubocop/cop/mixin/percent_array.rb +11 -3
  111. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
  112. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  113. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  114. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  115. data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
  116. data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
  117. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  118. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  119. data/lib/rubocop/cop/naming/file_name.rb +37 -4
  120. data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
  121. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  122. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  123. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  124. data/lib/rubocop/cop/security/json_load.rb +8 -7
  125. data/lib/rubocop/cop/security/open.rb +4 -0
  126. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  127. data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
  128. data/lib/rubocop/cop/style/and_or.rb +5 -0
  129. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  130. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  131. data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
  132. data/lib/rubocop/cop/style/block_delimiters.rb +23 -6
  133. data/lib/rubocop/cop/style/case_equality.rb +6 -9
  134. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  135. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  136. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  137. data/lib/rubocop/cop/style/collection_methods.rb +8 -6
  138. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  139. data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
  140. data/lib/rubocop/cop/style/commented_keyword.rb +9 -4
  141. data/lib/rubocop/cop/style/date_time.rb +5 -0
  142. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  143. data/lib/rubocop/cop/style/documentation.rb +23 -8
  144. data/lib/rubocop/cop/style/double_negation.rb +27 -6
  145. data/lib/rubocop/cop/style/empty_method.rb +2 -2
  146. data/lib/rubocop/cop/style/encoding.rb +26 -15
  147. data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
  148. data/lib/rubocop/cop/style/float_division.rb +10 -2
  149. data/lib/rubocop/cop/style/format_string_token.rb +2 -1
  150. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +7 -2
  151. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  152. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
  153. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  154. data/lib/rubocop/cop/style/hash_except.rb +4 -3
  155. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
  156. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  157. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
  158. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
  159. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  160. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  161. data/lib/rubocop/cop/style/lambda_call.rb +1 -1
  162. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -1
  163. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
  164. data/lib/rubocop/cop/style/module_function.rb +8 -9
  165. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  166. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  167. data/lib/rubocop/cop/style/mutable_constant.rb +73 -6
  168. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  169. data/lib/rubocop/cop/style/negated_unless.rb +1 -1
  170. data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
  171. data/lib/rubocop/cop/style/not.rb +2 -2
  172. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  173. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  174. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  175. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  176. data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
  177. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  178. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  179. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  180. data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
  181. data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
  182. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  183. data/lib/rubocop/cop/style/quoted_symbols.rb +21 -7
  184. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  185. data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
  186. data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
  187. data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
  188. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  189. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  190. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
  191. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  192. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
  193. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  194. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  195. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +23 -28
  196. data/lib/rubocop/cop/style/redundant_sort.rb +51 -18
  197. data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
  198. data/lib/rubocop/cop/style/return_nil.rb +2 -1
  199. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  200. data/lib/rubocop/cop/style/select_by_regexp.rb +139 -0
  201. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  202. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  203. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
  204. data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
  205. data/lib/rubocop/cop/style/static_class.rb +5 -5
  206. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  207. data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
  208. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  209. data/lib/rubocop/cop/style/struct_inheritance.rb +4 -0
  210. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  211. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  212. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  213. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  214. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  215. data/lib/rubocop/cop/style/word_array.rb +3 -3
  216. data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
  217. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  218. data/lib/rubocop/cop/util.rb +15 -4
  219. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  220. data/lib/rubocop/formatter/html_formatter.rb +5 -2
  221. data/lib/rubocop/formatter/json_formatter.rb +4 -1
  222. data/lib/rubocop/magic_comment.rb +44 -15
  223. data/lib/rubocop/options.rb +126 -112
  224. data/lib/rubocop/rake_task.rb +1 -1
  225. data/lib/rubocop/remote_config.rb +1 -1
  226. data/lib/rubocop/result_cache.rb +3 -3
  227. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  228. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  229. data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
  230. data/lib/rubocop/rspec/support.rb +1 -0
  231. data/lib/rubocop/runner.rb +2 -3
  232. data/lib/rubocop/target_finder.rb +1 -1
  233. data/lib/rubocop/version.rb +1 -1
  234. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  235. data/lib/rubocop.rb +14 -2
  236. metadata +20 -5
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ #
7
+ # This cop checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # IO.select([io], [], [], timeout)
13
+ #
14
+ # # good
15
+ # io.wait_readable(timeout)
16
+ #
17
+ # # bad
18
+ # IO.select([], [io], [], timeout)
19
+ #
20
+ # # good
21
+ # io.wait_writable(timeout)
22
+ #
23
+ class IncompatibleIoSelectWithFiberScheduler < Base
24
+ extend AutoCorrector
25
+
26
+ MSG = 'Use `%<preferred>s` instead of `%<current>s`.'
27
+ RESTRICT_ON_SEND = %i[select].freeze
28
+
29
+ # @!method io_select(node)
30
+ def_node_matcher :io_select, <<~PATTERN
31
+ (send
32
+ (const {nil? cbase} :IO) :select $_ $_ {(array) nil} $...)
33
+ PATTERN
34
+
35
+ def on_send(node)
36
+ return unless (read, write, timeout = io_select(node))
37
+ return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read)
38
+
39
+ preferred = preferred_method(read, write, timeout)
40
+ message = format(MSG, preferred: preferred, current: node.source)
41
+
42
+ add_offense(node, message: message) do |corrector|
43
+ corrector.replace(node, preferred)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def scheduler_compatible?(io1, io2)
50
+ return false unless io1.array_type? && io1.values.size == 1
51
+
52
+ io2.array_type? ? io2.values.empty? : io2.nil_type?
53
+ end
54
+
55
+ def preferred_method(read, write, timeout)
56
+ timeout_argument = timeout.empty? ? '' : "(#{timeout[0].source})"
57
+
58
+ if read.array_type? && read.values[0]
59
+ "#{read.values[0].source}.wait_readable#{timeout_argument}"
60
+ else
61
+ "#{write.values[0].source}.wait_writable#{timeout_argument}"
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -5,6 +5,11 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for interpolation in a single quoted string.
7
7
  #
8
+ # @safety
9
+ # This cop is generally safe, but is marked as unsafe because
10
+ # it is possible to actually intentionally have text inside
11
+ # `#{...}` in a single quoted string.
12
+ #
8
13
  # @example
9
14
  #
10
15
  # # bad
@@ -5,9 +5,10 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for uses of `begin...end while/until something`.
7
7
  #
8
- # The cop is marked as unsafe because behaviour can change in some cases, including
9
- # if a local variable inside the loop body is accessed outside of it, or if the
10
- # loop body raises a `StopIteration` exception (which `Kernel#loop` rescues).
8
+ # @safety
9
+ # The cop is unsafe because behaviour can change in some cases, including
10
+ # if a local variable inside the loop body is accessed outside of it, or if the
11
+ # loop body raises a `StopIteration` exception (which `Kernel#loop` rescues).
11
12
  #
12
13
  # @example
13
14
  #
@@ -14,7 +14,11 @@ module RuboCop
14
14
  # `Dir.glob` and `Dir[]` sort globbed results by default in Ruby 3.0.
15
15
  # So all bad cases are acceptable when Ruby 3.0 or higher are used.
16
16
  #
17
- # This cop will be deprecated and removed when supporting only Ruby 3.0 and higher.
17
+ # NOTE: This cop will be deprecated and removed when supporting only Ruby 3.0 and higher.
18
+ #
19
+ # @safety
20
+ # This cop is unsafe in the case where sorting files changes existing
21
+ # expected behaviour.
18
22
  #
19
23
  # @example
20
24
  #
@@ -18,6 +18,11 @@ module RuboCop
18
18
  # cop by default). Similarly, Rails' duration methods do not work well
19
19
  # with `Integer()` and can be ignored with `IgnoredMethods`.
20
20
  #
21
+ # @safety
22
+ # Autocorrection is unsafe because it is not guaranteed that the
23
+ # replacement `Kernel` methods are able to properly handle the
24
+ # input if it is not a standard class.
25
+ #
21
26
  # @example
22
27
  #
23
28
  # # bad
@@ -25,6 +30,7 @@ module RuboCop
25
30
  # '10'.to_i
26
31
  # '10.2'.to_f
27
32
  # '10'.to_c
33
+ # '1/3'.to_r
28
34
  # ['1', '2', '3'].map(&:to_i)
29
35
  # foo.try(:to_f)
30
36
  # bar.send(:to_c)
@@ -34,6 +40,7 @@ module RuboCop
34
40
  # Integer('10', 10)
35
41
  # Float('10.2')
36
42
  # Complex('10')
43
+ # Rational('1/3')
37
44
  # ['1', '2', '3'].map { |i| Integer(i, 10) }
38
45
  # foo.try { |i| Float(i) }
39
46
  # bar.send { |i| Complex(i) }
@@ -54,12 +61,14 @@ module RuboCop
54
61
  CONVERSION_METHOD_CLASS_MAPPING = {
55
62
  to_i: "#{Integer.name}(%<number_object>s, 10)",
56
63
  to_f: "#{Float.name}(%<number_object>s)",
57
- to_c: "#{Complex.name}(%<number_object>s)"
64
+ to_c: "#{Complex.name}(%<number_object>s)",
65
+ to_r: "#{Rational.name}(%<number_object>s)"
58
66
  }.freeze
59
67
  MSG = 'Replace unsafe number conversion with number '\
60
68
  'class parsing, instead of using '\
61
69
  '`%<current>s`, use stricter '\
62
70
  '`%<corrected_method>s`.'
71
+ CONVERSION_METHODS = %i[Integer Float Complex Rational to_i to_f to_c to_r].freeze
63
72
  METHODS = CONVERSION_METHOD_CLASS_MAPPING.keys.map(&:inspect).join(' ')
64
73
 
65
74
  # @!method to_method(node)
@@ -127,7 +136,8 @@ module RuboCop
127
136
  end
128
137
 
129
138
  def ignore_receiver?(receiver)
130
- if receiver.send_type? && ignored_method?(receiver.method_name)
139
+ if receiver.numeric_type? || (receiver.send_type? &&
140
+ (conversion_method?(receiver.method_name) || ignored_method?(receiver.method_name)))
131
141
  true
132
142
  elsif (receiver = top_receiver(receiver))
133
143
  receiver.const_type? && ignored_class?(receiver.const_name)
@@ -142,6 +152,10 @@ module RuboCop
142
152
  receiver
143
153
  end
144
154
 
155
+ def conversion_method?(method_name)
156
+ CONVERSION_METHODS.include?(method_name)
157
+ end
158
+
145
159
  def ignored_classes
146
160
  cop_config.fetch('IgnoredClasses', [])
147
161
  end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
11
11
  # -e:1: warning: `_1' is reserved for numbered parameter; consider another name
12
12
  #
13
- # Assiging to numbered parameter (from `_1` to `_9`) cause an error in Ruby 3.0.
13
+ # Assigning to a numbered parameter (from `_1` to `_9`) causes an error in Ruby 3.0.
14
14
  #
15
15
  # % ruby -ve '_1 = :value'
16
16
  # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
@@ -9,8 +9,10 @@ module RuboCop
9
9
  # should always be the same. If constants are assigned in multiple
10
10
  # locations, the result may vary depending on the order of `require`.
11
11
  #
12
- # Also, if you already have such an implementation, auto-correction may
13
- # change the result.
12
+ # @safety
13
+ # This cop is unsafe because code that is already conditionally
14
+ # assigning a constant may have its behaviour changed by
15
+ # auto-correction.
14
16
  #
15
17
  # @example
16
18
  #
@@ -6,6 +6,23 @@ module RuboCop
6
6
  # This cops looks for references of Regexp captures that are out of range
7
7
  # and thus always returns nil.
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe because it is naive in how it determines what
11
+ # references are available based on the last encountered regexp, but
12
+ # it cannot handle some cases, such as conditional regexp matches, which
13
+ # leads to false positives, such as:
14
+ #
15
+ # [source,ruby]
16
+ # ----
17
+ # foo ? /(c)(b)/ =~ str : /(b)/ =~ str
18
+ # do_something if $2
19
+ # # $2 is defined for the first condition but not the second, however
20
+ # # the cop will mark this as an offense.
21
+ # ----
22
+ #
23
+ # This might be a good indication of code that should be refactored,
24
+ # however.
25
+ #
9
26
  # @example
10
27
  #
11
28
  # /(foo)bar/ =~ 'foobar'
@@ -9,6 +9,16 @@ module RuboCop
9
9
  # example, mistranslating an array of literals to percent string notation)
10
10
  # rather than meant to be part of the resulting strings.
11
11
  #
12
+ # @safety
13
+ # The cop is unsafe because the correction changes the values in the array
14
+ # and that might have been done purposely.
15
+ #
16
+ # [source,ruby]
17
+ # ----
18
+ # %w('foo', "bar") #=> ["'foo',", '"bar"']
19
+ # %w(foo bar) #=> ['foo', 'bar']
20
+ # ----
21
+ #
12
22
  # @example
13
23
  #
14
24
  # # bad
@@ -13,6 +13,10 @@ module RuboCop
13
13
  # `Exception`. Alternatively, make `Exception` a fully qualified class
14
14
  # name with an explicit namespace.
15
15
  #
16
+ # @safety
17
+ # This cop is unsafe because it will change the exception class being
18
+ # raised, which is a change in behaviour.
19
+ #
16
20
  # @example
17
21
  # # bad
18
22
  # raise Exception, 'Error message here'
@@ -7,13 +7,14 @@ module RuboCop
7
7
  # `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods
8
8
  # are checked by default. These are customizable with `AllowedMethods` option.
9
9
  #
10
- # This cop is marked as unsafe, because auto-correction can change the
11
- # return type of the expression. An offending expression that previously
12
- # could return `nil` will be auto-corrected to never return `nil`.
13
- #
14
10
  # In the example below, the safe navigation operator (`&.`) is unnecessary
15
11
  # because `NilClass` has methods like `respond_to?` and `is_a?`.
16
12
  #
13
+ # @safety
14
+ # This cop is unsafe, because auto-correction can change the return type of
15
+ # the expression. An offending expression that previously could return `nil`
16
+ # will be auto-corrected to never return `nil`.
17
+ #
17
18
  # @example
18
19
  # # bad
19
20
  # do_something if attrs&.respond_to?(:[])
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for uses a file requiring itself with `require_relative`.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ #
12
+ # # foo.rb
13
+ # require_relative 'foo'
14
+ # require_relative 'bar'
15
+ #
16
+ # # good
17
+ #
18
+ # # foo.rb
19
+ # require_relative 'bar'
20
+ #
21
+ class RequireRelativeSelfPath < Base
22
+ include RangeHelp
23
+ extend AutoCorrector
24
+
25
+ MSG = 'Remove the `require_relative` that requires itself.'
26
+ RESTRICT_ON_SEND = %i[require_relative].freeze
27
+
28
+ def on_send(node)
29
+ return unless (required_feature = node.first_argument)
30
+ return unless required_feature.respond_to?(:value)
31
+ return unless same_file?(processed_source.file_path, required_feature.value)
32
+
33
+ add_offense(node) do |corrector|
34
+ corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def same_file?(file_path, required_feature)
41
+ file_path == required_feature || remove_ext(file_path) == required_feature
42
+ end
43
+
44
+ def remove_ext(file_path)
45
+ File.basename(file_path, File.extname(file_path))
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  #
11
11
  # NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
12
12
  # because `Ractor` should not access outer variables.
13
- # eg. following syle is encouraged:
13
+ # eg. following style is encouraged:
14
14
  #
15
15
  # worker_id, pipe = env
16
16
  # Ractor.new(worker_id, pipe) do |worker_id, pipe|
@@ -143,7 +143,7 @@ module RuboCop
143
143
  # Although some operators can be converted to symbols normally
144
144
  # (ie. `:==`), these are not accepted as hash keys and will
145
145
  # raise a syntax error (eg. `{ ==: ... }`). Therefore, if the
146
- # symbol does not start with an alpha-numeric or underscore, it
146
+ # symbol does not start with an alphanumeric or underscore, it
147
147
  # will be ignored.
148
148
  return unless node.value.to_s.match?(/\A[a-z0-9_]/i)
149
149
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # This cop checks for "triple quotes" (strings delimted by any odd number
6
+ # This cop checks for "triple quotes" (strings delimited by any odd number
7
7
  # of quotes greater than 1).
8
8
  #
9
9
  # Ruby allows multiple strings to be implicitly concatenated by just
@@ -13,14 +13,19 @@ module RuboCop
13
13
  # Keyword arguments (including `**kwargs`) do not get counted towards
14
14
  # this, as they are not used by the methods in question.
15
15
  #
16
- # NOTE: This cop matches for method names only and hence cannot tell apart
17
- # methods with same name in different classes.
18
- #
19
16
  # Method names and their expected arity can be configured like this:
20
17
  #
18
+ # [source,yaml]
19
+ # ----
21
20
  # Methods:
22
21
  # inject: 2
23
22
  # reduce: 2
23
+ # ----
24
+ #
25
+ # @safety
26
+ # This cop matches for method names only and hence cannot tell apart
27
+ # methods with same name in different classes, which may lead to a
28
+ # false positive.
24
29
  #
25
30
  # @example
26
31
  # # bad
@@ -87,9 +87,8 @@ module RuboCop
87
87
  end
88
88
 
89
89
  def ignored_method?(body)
90
- cop_config['IgnoreEmptyMethods'] && body.nil? ||
91
- cop_config['IgnoreNotImplementedMethods'] &&
92
- not_implemented?(body)
90
+ (cop_config['IgnoreEmptyMethods'] && body.nil?) ||
91
+ (cop_config['IgnoreNotImplementedMethods'] && not_implemented?(body))
93
92
  end
94
93
 
95
94
  def message(variable)
@@ -6,8 +6,9 @@ module RuboCop
6
6
  # This cop checks for useless method definitions, specifically: empty constructors
7
7
  # and methods just delegating to `super`.
8
8
  #
9
- # This cop is marked as unsafe as it can trigger false positives for cases when
10
- # an empty constructor just overrides the parent constructor, which is bad anyway.
9
+ # @safety
10
+ # This cop is unsafe as it can register false positives for cases when an empty
11
+ # constructor just overrides the parent constructor, which is bad anyway.
11
12
  #
12
13
  # @example
13
14
  # # bad
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop looks for `ruby2_keywords` calls for methods that do not need it.
7
+ #
8
+ # `ruby2_keywords` should only be called on methods that accept an argument splat
9
+ # (`*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
10
+ # a keyword splat (`**kwargs`).
11
+ #
12
+ # @example
13
+ # # good (splat argument without keyword arguments)
14
+ # ruby2_keywords def foo(*args); end
15
+ #
16
+ # # bad (no arguments)
17
+ # ruby2_keywords def foo; end
18
+ #
19
+ # # good
20
+ # def foo; end
21
+ #
22
+ # # bad (positional argument)
23
+ # ruby2_keywords def foo(arg); end
24
+ #
25
+ # # good
26
+ # def foo(arg); end
27
+ #
28
+ # # bad (double splatted argument)
29
+ # ruby2_keywords def foo(**args); end
30
+ #
31
+ # # good
32
+ # def foo(**args); end
33
+ #
34
+ # # bad (keyword arguments)
35
+ # ruby2_keywords def foo(i:, j:); end
36
+ #
37
+ # # good
38
+ # def foo(i:, j:); end
39
+ #
40
+ # # bad (splat argument with keyword arguments)
41
+ # ruby2_keywords def foo(*args, i:, j:); end
42
+ #
43
+ # # good
44
+ # def foo(*args, i:, j:); end
45
+ #
46
+ # # bad (splat argument with double splat)
47
+ # ruby2_keywords def foo(*args, **kwargs); end
48
+ #
49
+ # # good
50
+ # def foo(*args, **kwargs); end
51
+ #
52
+ # # bad (ruby2_keywords given a symbol)
53
+ # def foo; end
54
+ # ruby2_keywords :foo
55
+ #
56
+ # # good
57
+ # def foo; end
58
+ #
59
+ # # bad (ruby2_keywords with dynamic method)
60
+ # define_method(:foo) { |arg| }
61
+ # ruby2_keywords :foo
62
+ #
63
+ # # good
64
+ # define_method(:foo) { |arg| }
65
+ #
66
+ class UselessRuby2Keywords < Base
67
+ MSG = '`ruby2_keywords` is unnecessary for method `%<method_name>s`.'
68
+ RESTRICT_ON_SEND = %i[ruby2_keywords].freeze
69
+
70
+ # Looks for statically or dynamically defined methods with a given name
71
+ # @!method method_definition(node, method_name)
72
+ def_node_matcher :method_definition, <<~PATTERN
73
+ {
74
+ (def %1 ...)
75
+ ({block numblock} (send _ :define_method (sym %1)) ...)
76
+ }
77
+ PATTERN
78
+
79
+ def on_send(node)
80
+ if node.first_argument.def_type?
81
+ inspect_def(node, node.first_argument)
82
+ elsif node.first_argument.sym_type?
83
+ inspect_sym(node, node.first_argument)
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def inspect_def(node, def_node)
90
+ return if allowed_arguments(def_node.arguments)
91
+
92
+ add_offense(node.loc.selector, message: format(MSG, method_name: def_node.method_name))
93
+ end
94
+
95
+ def inspect_sym(node, sym_node)
96
+ return unless node.parent
97
+
98
+ method_name = sym_node.value
99
+ definition = node.parent.each_child_node.detect { |n| method_definition(n, method_name) }
100
+
101
+ return unless definition
102
+ return if allowed_arguments(definition.arguments)
103
+
104
+ add_offense(node, message: format(MSG, method_name: method_name))
105
+ end
106
+
107
+ # `ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
108
+ def allowed_arguments(arguments)
109
+ return false if arguments.empty?
110
+
111
+ arguments.each_child_node(:restarg).any? &&
112
+ arguments.each_child_node(:kwarg, :kwoptarg, :kwrestarg).none?
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -5,11 +5,14 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for setter call to local variable as the final
7
7
  # expression of a function definition.
8
- # Its auto-correction is marked as unsafe because return value will be changed.
9
8
  #
10
- # NOTE: There are edge cases in which the local variable references a
11
- # value that is also accessible outside the local scope. This is not
12
- # detected by the cop, and it can yield a false positive.
9
+ # @safety
10
+ # There are edge cases in which the local variable references a
11
+ # value that is also accessible outside the local scope. This is not
12
+ # detected by the cop, and it can yield a false positive.
13
+ #
14
+ # As well, auto-correction is unsafe because the method's
15
+ # return value will be changed.
13
16
  #
14
17
  # @example
15
18
  #
@@ -7,8 +7,9 @@ module RuboCop
7
7
  # (when the integer <= 0) or that will only ever yield once
8
8
  # (`1.times`).
9
9
  #
10
- # This cop is marked as unsafe as `times` returns its receiver, which
11
- # is *usually* OK, but might change behavior.
10
+ # @safety
11
+ # This cop is unsafe as `times` returns its receiver, which is
12
+ # *usually* OK, but might change behavior.
12
13
  #
13
14
  # @example
14
15
  # # bad
@@ -65,7 +66,7 @@ module RuboCop
65
66
  private
66
67
 
67
68
  def never_process?(count, node)
68
- count < 1 || node.block_type? && node.body.nil?
69
+ count < 1 || (node.block_type? && node.body.nil?)
69
70
  end
70
71
 
71
72
  def remove_node(corrector, node)
@@ -8,6 +8,12 @@ module RuboCop
8
8
  # (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric
9
9
  # and https://en.wikipedia.org/wiki/ABC_Software_Metric.
10
10
  #
11
+ # Interpreting ABC size:
12
+ #
13
+ # * <= 17 satisfactory
14
+ # * 18..30 unsatisfactory
15
+ # * > 30 dangerous
16
+ #
11
17
  # You can have repeated "attributes" calls count as a single "branch".
12
18
  # For this purpose, attributes are any method with no argument; no attempt
13
19
  # is meant to distinguish actual `attr_reader` from other methods.
@@ -9,6 +9,9 @@ module RuboCop
9
9
  # Keyword arguments can optionally be excluded from the total count,
10
10
  # as they add less complexity than positional or optional parameters.
11
11
  #
12
+ # NOTE: Explicit block argument `&block` is not counted to prevent
13
+ # erroneous change that is avoided by making block argument implicit.
14
+ #
12
15
  # @example Max: 3
13
16
  # # good
14
17
  # def foo(a, b, c = 1)
@@ -94,9 +97,9 @@ module RuboCop
94
97
 
95
98
  def args_count(node)
96
99
  if count_keyword_args?
97
- node.children.size
100
+ node.children.count { |a| !a.blockarg_type? }
98
101
  else
99
- node.children.count { |a| !NAMED_KEYWORD_TYPES.include?(a.type) }
102
+ node.children.count { |a| !NAMED_KEYWORD_TYPES.include?(a.type) && !a.blockarg_type? }
100
103
  end
101
104
  end
102
105
 
@@ -45,7 +45,7 @@ module RuboCop
45
45
  else
46
46
  # Otherwise, the case node gets 0.8 complexity points and each
47
47
  # when gets 0.2.
48
- (0.8 + 0.2 * nb_branches).round
48
+ (0.8 + (0.2 * nb_branches)).round
49
49
  end
50
50
  when :if
51
51
  node.else? && !node.elsif? ? 2 : 1
@@ -46,7 +46,7 @@ module RuboCop
46
46
  visit_depth_last(@node) { |child| calculate_node(child) }
47
47
 
48
48
  [
49
- Math.sqrt(@assignment**2 + @branch**2 + @condition**2).round(2),
49
+ Math.sqrt((@assignment**2) + (@branch**2) + (@condition**2)).round(2),
50
50
  "<#{@assignment}, #{@branch}, #{@condition}>"
51
51
  ]
52
52
  end
@@ -147,7 +147,7 @@ module RuboCop
147
147
 
148
148
  # Returns true for lines that shall not be included in the count.
149
149
  def irrelevant_line?(source_line)
150
- source_line.blank? || !count_comments? && comment_line?(source_line)
150
+ source_line.blank? || (!count_comments? && comment_line?(source_line))
151
151
  end
152
152
 
153
153
  def count_comments?