rubocop 1.18.1 → 1.22.3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for ambiguous ranges.
7
+ #
8
+ # Ranges have quite low precedence, which leads to unexpected behaviour when
9
+ # using a range with other operators. This cop avoids that by making ranges
10
+ # explicit by requiring parenthesis around complex range boundaries (anything
11
+ # that is not a basic literal: numerics, strings, symbols, etc.).
12
+ #
13
+ # This cop can be configured with `RequireParenthesesForMethodChains` in order to
14
+ # specify whether method chains (including `self.foo`) should be wrapped in parens
15
+ # by this cop.
16
+ #
17
+ # NOTE: Regardless of this configuration, if a method receiver is a basic literal
18
+ # value, it will be wrapped in order to prevent the ambiguity of `1..2.to_a`.
19
+ #
20
+ # @safety
21
+ # The cop auto-corrects by wrapping the entire boundary in parentheses, which
22
+ # makes the outcome more explicit but is possible to not be the intention of the
23
+ # programmer. For this reason, this cop's auto-correct is unsafe (it will not
24
+ # change the behaviour of the code, but will not necessarily match the
25
+ # intent of the program).
26
+ #
27
+ # @example
28
+ # # bad
29
+ # x || 1..2
30
+ # (x || 1..2)
31
+ # 1..2.to_a
32
+ #
33
+ # # good, unambiguous
34
+ # 1..2
35
+ # 'a'..'z'
36
+ # :bar..:baz
37
+ # MyClass::MIN..MyClass::MAX
38
+ # @min..@max
39
+ # a..b
40
+ # -a..b
41
+ #
42
+ # # good, ambiguity removed
43
+ # x || (1..2)
44
+ # (x || 1)..2
45
+ # (x || 1)..(y || 2)
46
+ # (1..2).to_a
47
+ #
48
+ # @example RequireParenthesesForMethodChains: false (default)
49
+ # # good
50
+ # a.foo..b.bar
51
+ # (a.foo)..(b.bar)
52
+ #
53
+ # @example RequireParenthesesForMethodChains: true
54
+ # # bad
55
+ # a.foo..b.bar
56
+ #
57
+ # # good
58
+ # (a.foo)..(b.bar)
59
+ class AmbiguousRange < Base
60
+ extend AutoCorrector
61
+
62
+ MSG = 'Wrap complex range boundaries with parentheses to avoid ambiguity.'
63
+
64
+ def on_irange(node)
65
+ each_boundary(node) do |boundary|
66
+ next if acceptable?(boundary)
67
+
68
+ add_offense(boundary) do |corrector|
69
+ corrector.wrap(boundary, '(', ')')
70
+ end
71
+ end
72
+ end
73
+ alias on_erange on_irange
74
+
75
+ private
76
+
77
+ def each_boundary(range)
78
+ yield range.begin if range.begin
79
+ yield range.end if range.end
80
+ end
81
+
82
+ def acceptable?(node)
83
+ node.begin_type? ||
84
+ node.basic_literal? ||
85
+ node.variable? || node.const_type? || node.self_type? ||
86
+ (node.call_type? && acceptable_call?(node))
87
+ end
88
+
89
+ def acceptable_call?(node)
90
+ return true if node.unary_operation?
91
+
92
+ # Require parentheses when making a method call on a literal
93
+ # to avoid the ambiguity of `1..2.to_a`.
94
+ return false if node.receiver&.basic_literal?
95
+
96
+ require_parentheses_for_method_chain? || node.receiver.nil?
97
+ end
98
+
99
+ def require_parentheses_for_method_chain?
100
+ !cop_config['RequireParenthesesForMethodChains']
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -46,12 +46,11 @@ module RuboCop
46
46
  node = processed_source.ast.each_node(:regexp).find do |regexp_node|
47
47
  regexp_node.source_range.begin_pos == diagnostic.location.begin_pos
48
48
  end
49
-
50
49
  find_offense_node(node.parent, node)
51
50
  end
52
51
 
53
52
  def find_offense_node(node, regexp_receiver)
54
- return node unless node.parent
53
+ return node if first_argument_is_regexp?(node) || !node.parent
55
54
 
56
55
  if (node.parent.send_type? && node.receiver) ||
57
56
  method_chain_to_regexp_receiver?(node, regexp_receiver)
@@ -61,6 +60,10 @@ module RuboCop
61
60
  node
62
61
  end
63
62
 
63
+ def first_argument_is_regexp?(node)
64
+ node.send_type? && node.first_argument&.regexp_type?
65
+ end
66
+
64
67
  def method_chain_to_regexp_receiver?(node, regexp_receiver)
65
68
  return false unless (parent = node.parent)
66
69
  return false unless (parent_receiver = parent.receiver)
@@ -49,7 +49,7 @@ module RuboCop
49
49
  def on_if(node)
50
50
  return if node.condition.block_type?
51
51
 
52
- traverse_node(node.condition, ASGN_TYPES) do |asgn_node|
52
+ traverse_node(node.condition) do |asgn_node|
53
53
  next :skip_children if skip_children?(asgn_node)
54
54
  next if allowed_construct?(asgn_node)
55
55
 
@@ -83,13 +83,15 @@ module RuboCop
83
83
  (safe_assignment_allowed? && safe_assignment?(asgn_node))
84
84
  end
85
85
 
86
- # each_node/visit_descendants_with_types with :skip_children
87
- def traverse_node(node, types, &block)
88
- result = yield node if types.include?(node.type)
86
+ def traverse_node(node, &block)
87
+ # if the node is a block, any assignments are irrelevant
88
+ return if node.block_type?
89
+
90
+ result = yield node if ASGN_TYPES.include?(node.type)
89
91
 
90
92
  return if result == :skip_children
91
93
 
92
- node.each_child_node { |child| traverse_node(child, types, &block) }
94
+ node.each_child_node { |child| traverse_node(child, &block) }
93
95
  end
94
96
  end
95
97
  end
@@ -5,15 +5,28 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for places where binary operator has identical operands.
7
7
  #
8
- # It covers arithmetic operators: `+`, `-`, `*`, `/`, `%`, `**`;
8
+ # It covers arithmetic operators: `-`, `/`, `%`;
9
9
  # comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, `<=`;
10
- # bitwise operators: `|`, `^`, `&`, `<<`, `>>`;
10
+ # bitwise operators: `|`, `^`, `&`;
11
11
  # boolean operators: `&&`, `||`
12
12
  # and "spaceship" operator - `<=>`.
13
13
  #
14
- # This cop is marked as unsafe as it does not consider side effects when calling methods
15
- # and thus can generate false positives:
14
+ # Simple arithmetic operations are allowed by this cop: `+`, `*`, `**`, `<<` and `>>`.
15
+ # Although these can be rewritten in a different way, it should not be necessary to
16
+ # do so. This does not include operations such as `-` or `/` where the result will
17
+ # always be the same (`x - x` will always be 0; `x / x` will always be 1), and
18
+ # thus are legitimate offenses.
19
+ #
20
+ # @safety
21
+ # This cop is unsafe as it does not consider side effects when calling methods
22
+ # and thus can generate false positives, for example:
23
+ #
24
+ # [source,ruby]
25
+ # ----
16
26
  # if wr.take_char == '\0' && wr.take_char == '\0'
27
+ # # ...
28
+ # end
29
+ # ----
17
30
  #
18
31
  # @example
19
32
  # # bad
@@ -24,7 +37,7 @@ module RuboCop
24
37
  # do_something
25
38
  # end
26
39
  #
27
- # def childs?
40
+ # def child?
28
41
  # left_child || left_child
29
42
  # end
30
43
  #
@@ -6,6 +6,11 @@ module RuboCop
6
6
  # This cop checks for `:true` and `:false` symbols.
7
7
  # In most cases it would be a typo.
8
8
  #
9
+ # @safety
10
+ # Autocorrection is unsafe for this cop because code relying
11
+ # on `:true` or `:false` symbols will break when those are
12
+ # changed to actual booleans.
13
+ #
9
14
  # @example
10
15
  #
11
16
  # # bad
@@ -7,8 +7,8 @@ module RuboCop
7
7
  # not be kept for production code.
8
8
  #
9
9
  # The cop can be configured using `DebuggerMethods`. By default, a number of gems
10
- # debug entrypoints are configured (`Kernel`, `Byebug`, `Capybara`, `Pry`, `Rails`,
11
- # and `WebConsole`). Additional methods can be added.
10
+ # debug entrypoints are configured (`Kernel`, `Byebug`, `Capybara`, `debug.rb`,
11
+ # `Pry`, `Rails`, `RubyJard`, and `WebConsole`). Additional methods can be added.
12
12
  #
13
13
  # Specific default groups can be disabled if necessary:
14
14
  #
@@ -57,8 +57,6 @@ module RuboCop
57
57
  class Debugger < Base
58
58
  MSG = 'Remove debugger entry point `%<source>s`.'
59
59
 
60
- RESTRICT_ON_SEND = [].freeze
61
-
62
60
  # @!method kernel?(node)
63
61
  def_node_matcher :kernel?, <<~PATTERN
64
62
  (const {nil? cbase} :Kernel)
@@ -58,12 +58,12 @@ module RuboCop
58
58
  end
59
59
 
60
60
  def to_s
61
- [class_constant, method].compact.join(delimeter)
61
+ [class_constant, method].compact.join(delimiter)
62
62
  end
63
63
 
64
64
  private
65
65
 
66
- def delimeter
66
+ def delimiter
67
67
  CLASS_METHOD_DELIMETER
68
68
  end
69
69
  end
@@ -81,12 +81,12 @@ module RuboCop
81
81
  end
82
82
 
83
83
  def to_s
84
- [class_constant, method].compact.join(delimeter)
84
+ [class_constant, method].compact.join(delimiter)
85
85
  end
86
86
 
87
87
  private
88
88
 
89
- def delimeter
89
+ def delimiter
90
90
  instance_method? ? INSTANCE_METHOD_DELIMETER : CLASS_METHOD_DELIMETER
91
91
  end
92
92
 
@@ -42,11 +42,12 @@ module RuboCop
42
42
  # Maybe further investigation of RuboCop AST will lead to an essential solution.
43
43
  return unless node.loc
44
44
 
45
- constant = node.absolute? ? constant_name(node, node.short_name.to_s) : node.source
45
+ constant = node.absolute? ? constant_name(node, node.short_name) : node.source
46
46
  return unless (deprecated_constant = deprecated_constants[constant])
47
47
 
48
48
  alternative = deprecated_constant['Alternative']
49
49
  version = deprecated_constant['DeprecatedVersion']
50
+ return if target_ruby_version < version.to_f
50
51
 
51
52
  add_offense(node, message: message(alternative, node.source, version)) do |corrector|
52
53
  corrector.replace(node, alternative)
@@ -56,7 +57,7 @@ module RuboCop
56
57
  private
57
58
 
58
59
  def constant_name(node, nested_constant_name)
59
- return nested_constant_name unless node.namespace.const_type?
60
+ return nested_constant_name.to_s unless node.namespace.const_type?
60
61
 
61
62
  constant_name(node.namespace, "#{node.namespace.short_name}::#{nested_constant_name}")
62
63
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # This cop checks constructors for disjunctive assignments that should
6
+ # This cop checks constructors for disjunctive assignments (`||=`) that should
7
7
  # be plain assignments.
8
8
  #
9
9
  # So far, this cop is only concerned with disjunctive assignment of
@@ -12,6 +12,29 @@ module RuboCop
12
12
  # In ruby, an instance variable is nil until a value is assigned, so the
13
13
  # disjunction is unnecessary. A plain assignment has the same effect.
14
14
  #
15
+ # @safety
16
+ # This cop is unsafe because it can register a false positive when a
17
+ # method is redefined in a subclass that calls super. For example:
18
+ #
19
+ # [source,ruby]
20
+ # ----
21
+ # class Base
22
+ # def initialize
23
+ # @config ||= 'base'
24
+ # end
25
+ # end
26
+ #
27
+ # class Derived < Base
28
+ # def initialize
29
+ # @config = 'derived'
30
+ # super
31
+ # end
32
+ # end
33
+ # ----
34
+ #
35
+ # Without the disjunctive assignment, `Derived` will be unable to override
36
+ # the value for `@config`.
37
+ #
15
38
  # @example
16
39
  # # bad
17
40
  # def initialize
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Lint
6
6
  # This cop checks that there are no repeated bodies
7
- # within `if/unless`, `case-when` and `rescue` constructs.
7
+ # within `if/unless`, `case-when`, `case-in` and `rescue` constructs.
8
8
  #
9
9
  # With `IgnoreLiteralBranches: true`, branches are not registered
10
10
  # as offenses if they return a basic literal value (string, symbol,
@@ -97,6 +97,7 @@ module RuboCop
97
97
  end
98
98
  alias on_if on_branching_statement
99
99
  alias on_case on_branching_statement
100
+ alias on_case_match on_branching_statement
100
101
  alias on_rescue on_branching_statement
101
102
 
102
103
  private
@@ -135,11 +135,14 @@ module RuboCop
135
135
  def found_instance_method(node, name)
136
136
  return unless (scope = node.parent_module_name)
137
137
 
138
- if scope =~ /\A#<Class:(.*)>\Z/
139
- found_method(node, "#{Regexp.last_match(1)}.#{name}")
140
- else
141
- found_method(node, "#{scope}##{name}")
142
- end
138
+ # Humanize the scope
139
+ scope = scope.sub(
140
+ /(?:(?<name>.*)::)#<Class:\k<name>>|#<Class:(?<name>.*)>(?:::)?/,
141
+ '\k<name>.'
142
+ )
143
+ scope << '#' unless scope.end_with?('.')
144
+
145
+ found_method(node, "#{scope}#{name}")
143
146
  end
144
147
 
145
148
  def found_method(node, method_name)
@@ -49,6 +49,9 @@ module RuboCop
49
49
  def on_if(node)
50
50
  return if node.ternary?
51
51
 
52
+ # If the if is on a single line, it'll be handled by `Style/OneLineConditional`
53
+ return if node.single_line?
54
+
52
55
  check(node)
53
56
  end
54
57
 
@@ -66,13 +69,10 @@ module RuboCop
66
69
 
67
70
  def check_else(node)
68
71
  else_branch = node.else_branch
69
-
70
- return unless else_branch.begin_type?
71
-
72
- first_else = else_branch.children.first
72
+ first_else = else_branch.begin_type? ? else_branch.children.first : else_branch
73
73
 
74
74
  return unless first_else
75
- return unless first_else.source_range.line == node.loc.else.line
75
+ return unless same_line?(first_else, node.loc.else)
76
76
 
77
77
  add_offense(first_else) { |corrector| autocorrect(corrector, node, first_else) }
78
78
  end
@@ -81,9 +81,13 @@ module RuboCop
81
81
  corrector.insert_after(node.loc.else, "\n")
82
82
 
83
83
  blank_range = range_between(node.loc.else.end_pos, first_else.loc.expression.begin_pos)
84
- indentation = indent(node.else_branch.children[1])
84
+ indentation = indent(node, offset: indentation_width)
85
85
  corrector.replace(blank_range, indentation)
86
86
  end
87
+
88
+ def indentation_width
89
+ @config.for_cop('Layout/IndentationWidth')['Width'] || 2
90
+ end
87
91
  end
88
92
  end
89
93
  end
@@ -51,7 +51,7 @@ module RuboCop
51
51
 
52
52
  def on_case_match(node)
53
53
  node.in_pattern_branches.each do |branch|
54
- next if branch.body || cop_config['AllowComments'] && comment_lines?(node)
54
+ next if branch.body || (cop_config['AllowComments'] && comment_lines?(node))
55
55
 
56
56
  add_offense(branch)
57
57
  end
@@ -118,7 +118,7 @@ module RuboCop
118
118
  end
119
119
 
120
120
  def correct_arguments?(arguments)
121
- arguments.size == 1 || arguments.size == 2 && arguments[1].hash_type?
121
+ arguments.size == 1 || (arguments.size == 2 && arguments[1].hash_type?)
122
122
  end
123
123
 
124
124
  def build_kwargs(node)
@@ -24,7 +24,7 @@ module RuboCop
24
24
  def on_float(node)
25
25
  value, = *node
26
26
 
27
- return unless value.infinite? || value.zero? && /[1-9]/.match?(node.source)
27
+ return unless value.infinite? || (value.zero? && /[1-9]/.match?(node.source))
28
28
 
29
29
  add_offense(node)
30
30
  end
@@ -3,10 +3,19 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Prefer using `Hash#compare_by_identity` than using `object_id` for hash keys.
6
+ # Prefer using `Hash#compare_by_identity` rather than using `object_id`
7
+ # for hash keys.
7
8
  #
8
- # This cop is marked as unsafe as a hash possibly can contain other keys
9
- # besides `object_id`s.
9
+ # This cop looks for hashes being keyed by objects' `object_id`, using
10
+ # one of these methods: `key?`, `has_key?`, `fetch`, `[]` and `[]=`.
11
+ #
12
+ # @safety
13
+ # This cop is unsafe. Although unlikely, the hash could store both object
14
+ # ids and other values that need be compared by value, and thus
15
+ # could be a false positive.
16
+ #
17
+ # Furthermore, this cop cannot guarantee that the receiver of one of the
18
+ # methods (`key?`, etc.) is actually a hash.
10
19
  #
11
20
  # @example
12
21
  # # bad
@@ -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
@@ -60,6 +65,7 @@ module RuboCop
60
65
  'class parsing, instead of using '\
61
66
  '`%<current>s`, use stricter '\
62
67
  '`%<corrected_method>s`.'
68
+ CONVERSION_METHODS = %i[Integer Float Complex to_i to_f to_c].freeze
63
69
  METHODS = CONVERSION_METHOD_CLASS_MAPPING.keys.map(&:inspect).join(' ')
64
70
 
65
71
  # @!method to_method(node)
@@ -127,7 +133,8 @@ module RuboCop
127
133
  end
128
134
 
129
135
  def ignore_receiver?(receiver)
130
- if receiver.send_type? && ignored_method?(receiver.method_name)
136
+ if receiver.numeric_type? || (receiver.send_type? &&
137
+ (conversion_method?(receiver.method_name) || ignored_method?(receiver.method_name)))
131
138
  true
132
139
  elsif (receiver = top_receiver(receiver))
133
140
  receiver.const_type? && ignored_class?(receiver.const_name)
@@ -142,6 +149,10 @@ module RuboCop
142
149
  receiver
143
150
  end
144
151
 
152
+ def conversion_method?(method_name)
153
+ CONVERSION_METHODS.include?(method_name)
154
+ end
155
+
145
156
  def ignored_classes
146
157
  cop_config.fetch('IgnoredClasses', [])
147
158
  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'