rubocop 1.19.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +86 -14
  4. data/lib/rubocop/config.rb +5 -0
  5. data/lib/rubocop/config_loader.rb +4 -2
  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_filename.rb +103 -0
  9. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
  10. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  11. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
  12. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  13. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
  14. data/lib/rubocop/cop/documentation.rb +1 -1
  15. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  16. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +1 -1
  17. data/lib/rubocop/cop/generator.rb +14 -8
  18. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  19. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  20. data/lib/rubocop/cop/layout/class_structure.rb +2 -1
  21. data/lib/rubocop/cop/layout/dot_position.rb +25 -2
  22. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  23. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  24. data/lib/rubocop/cop/layout/line_length.rb +8 -6
  25. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  26. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
  27. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  28. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +5 -4
  29. data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
  30. data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
  31. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
  32. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  33. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
  34. data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -24
  35. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
  36. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
  37. data/lib/rubocop/cop/lint/ambiguous_range.rb +8 -8
  38. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  39. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  40. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  41. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  42. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  43. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  44. data/lib/rubocop/cop/lint/else_layout.rb +9 -5
  45. data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
  46. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  47. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  48. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  49. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
  50. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  51. data/lib/rubocop/cop/lint/loop.rb +4 -3
  52. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  53. data/lib/rubocop/cop/lint/number_conversion.rb +12 -1
  54. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  55. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  56. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  57. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  58. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  59. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  60. data/lib/rubocop/cop/lint/require_relative_self_path.rb +49 -0
  61. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  62. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  63. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  64. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  65. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
  66. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  67. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  68. data/lib/rubocop/cop/lint/useless_times.rb +4 -3
  69. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  70. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  71. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  72. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  73. data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
  74. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  75. data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
  76. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -1
  77. data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
  78. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  79. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  80. data/lib/rubocop/cop/mixin/percent_array.rb +11 -3
  81. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
  82. data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
  83. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  84. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  85. data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
  86. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  87. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  88. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  89. data/lib/rubocop/cop/security/json_load.rb +8 -7
  90. data/lib/rubocop/cop/security/open.rb +4 -0
  91. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  92. data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
  93. data/lib/rubocop/cop/style/and_or.rb +5 -0
  94. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  95. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  96. data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
  97. data/lib/rubocop/cop/style/block_delimiters.rb +23 -6
  98. data/lib/rubocop/cop/style/case_equality.rb +6 -9
  99. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  100. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  101. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  102. data/lib/rubocop/cop/style/collection_methods.rb +8 -6
  103. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  104. data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
  105. data/lib/rubocop/cop/style/commented_keyword.rb +4 -1
  106. data/lib/rubocop/cop/style/date_time.rb +5 -0
  107. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  108. data/lib/rubocop/cop/style/documentation.rb +23 -8
  109. data/lib/rubocop/cop/style/double_negation.rb +27 -6
  110. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  111. data/lib/rubocop/cop/style/encoding.rb +26 -15
  112. data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
  113. data/lib/rubocop/cop/style/float_division.rb +10 -2
  114. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +7 -2
  115. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  116. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
  117. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  118. data/lib/rubocop/cop/style/hash_except.rb +4 -3
  119. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
  120. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  121. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
  122. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
  123. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  124. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  125. data/lib/rubocop/cop/style/lambda_call.rb +1 -1
  126. data/lib/rubocop/cop/style/line_end_concatenation.rb +13 -0
  127. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
  128. data/lib/rubocop/cop/style/module_function.rb +8 -9
  129. data/lib/rubocop/cop/style/mutable_constant.rb +73 -6
  130. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  131. data/lib/rubocop/cop/style/negated_unless.rb +1 -1
  132. data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
  133. data/lib/rubocop/cop/style/not.rb +2 -2
  134. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  135. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  136. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  137. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  138. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  139. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  140. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  141. data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
  142. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  143. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  144. data/lib/rubocop/cop/style/redundant_argument.rb +14 -7
  145. data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
  146. data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
  147. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  148. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  149. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
  150. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  151. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
  152. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  153. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  154. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +23 -28
  155. data/lib/rubocop/cop/style/redundant_sort.rb +51 -18
  156. data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
  157. data/lib/rubocop/cop/style/return_nil.rb +2 -1
  158. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  159. data/lib/rubocop/cop/style/select_by_regexp.rb +106 -0
  160. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  161. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  162. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
  163. data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
  164. data/lib/rubocop/cop/style/static_class.rb +5 -5
  165. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  166. data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
  167. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  168. data/lib/rubocop/cop/style/struct_inheritance.rb +4 -0
  169. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  170. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  171. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  172. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  173. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  174. data/lib/rubocop/cop/style/word_array.rb +3 -3
  175. data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
  176. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  177. data/lib/rubocop/cop/util.rb +2 -2
  178. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  179. data/lib/rubocop/magic_comment.rb +44 -15
  180. data/lib/rubocop/options.rb +126 -112
  181. data/lib/rubocop/result_cache.rb +1 -1
  182. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  183. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  184. data/lib/rubocop/runner.rb +1 -2
  185. data/lib/rubocop/version.rb +1 -1
  186. data/lib/rubocop.rb +10 -2
  187. metadata +13 -5
@@ -67,17 +67,27 @@ module RuboCop
67
67
  # so this can cause crashes in haml_lint
68
68
  return unless def_node
69
69
 
70
+ block_name = extract_block_name(def_node)
71
+
70
72
  add_offense(block_node) do |corrector|
71
73
  corrector.remove(block_body_range(block_node, send_node))
72
74
 
73
- add_block_argument(send_node, corrector)
74
- add_block_argument(def_node, corrector) if @def_nodes.add?(def_node)
75
+ add_block_argument(send_node, corrector, block_name)
76
+ add_block_argument(def_node, corrector, block_name) if @def_nodes.add?(def_node)
75
77
  end
76
78
  end
77
79
  end
78
80
 
79
81
  private
80
82
 
83
+ def extract_block_name(def_node)
84
+ if def_node.block_argument?
85
+ def_node.arguments.last.name
86
+ else
87
+ 'block'
88
+ end
89
+ end
90
+
81
91
  def yielding_arguments?(block_args, yield_args)
82
92
  yield_args = yield_args.dup.fill(
83
93
  nil,
@@ -91,15 +101,15 @@ module RuboCop
91
101
  end
92
102
  end
93
103
 
94
- def add_block_argument(node, corrector)
104
+ def add_block_argument(node, corrector, block_name)
95
105
  if node.arguments?
96
- insert_argument(node, corrector)
106
+ insert_argument(node, corrector, block_name)
97
107
  elsif empty_arguments?(node)
98
- corrector.replace(node.arguments, '(&block)')
108
+ corrector.replace(node.arguments, "(&#{block_name})")
99
109
  elsif call_like?(node)
100
- correct_call_node(node, corrector)
110
+ correct_call_node(node, corrector, block_name)
101
111
  else
102
- corrector.insert_after(node.loc.name, '(&block)')
112
+ corrector.insert_after(node.loc.name, "(&#{block_name})")
103
113
  end
104
114
  end
105
115
 
@@ -112,16 +122,16 @@ module RuboCop
112
122
  node.call_type? || node.zsuper_type? || node.super_type?
113
123
  end
114
124
 
115
- def insert_argument(node, corrector)
125
+ def insert_argument(node, corrector, block_name)
116
126
  last_arg = node.arguments.last
117
127
  arg_range = range_with_surrounding_comma(last_arg.source_range, :right)
118
- replacement = ' &block'
128
+ replacement = " &#{block_name}"
119
129
  replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
120
130
  corrector.insert_after(arg_range, replacement) unless last_arg.blockarg_type?
121
131
  end
122
132
 
123
- def correct_call_node(node, corrector)
124
- corrector.insert_after(node, '(&block)')
133
+ def correct_call_node(node, corrector, block_name)
134
+ corrector.insert_after(node, "(&#{block_name})")
125
135
  return unless node.parenthesized?
126
136
 
127
137
  args_begin = Util.args_begin(node)
@@ -7,8 +7,16 @@ module RuboCop
7
7
  # It is recommended to either always use `fdiv` or coerce one side only.
8
8
  # This cop also provides other options for code consistency.
9
9
  #
10
- # This cop is marked as unsafe, because if operand variable is a string object
11
- # then `.to_f` will be removed and an error will occur.
10
+ # @safety
11
+ # This cop is unsafe, because if the operand variable is a string object
12
+ # then `.to_f` will be removed and an error will occur.
13
+ #
14
+ # [source,ruby]
15
+ # ----
16
+ # a = '1.2'
17
+ # b = '3.4'
18
+ # a.to_f / b.to_f # Both `to_f` calls are required here
19
+ # ----
12
20
  #
13
21
  # @example EnforcedStyle: single_coerce (default)
14
22
  # # bad
@@ -10,12 +10,17 @@ module RuboCop
10
10
  # default in future Ruby. The comment will be added below a shebang and
11
11
  # encoding comment.
12
12
  #
13
- # Note that the cop will ignore files where the comment exists but is set
13
+ # Note that the cop will accept files where the comment exists but is set
14
14
  # to `false` instead of `true`.
15
15
  #
16
16
  # To require a blank line after this comment, please see
17
17
  # `Layout/EmptyLineAfterMagicComment` cop.
18
18
  #
19
+ # @safety
20
+ # This cop's autocorrection is unsafe since any strings mutations will
21
+ # change from being accepted to raising `FrozenError`, as all strings
22
+ # will become frozen by default, and will need to be manually refactored.
23
+ #
19
24
  # @example EnforcedStyle: always (default)
20
25
  # # The `always` style will always add the frozen string literal comment
21
26
  # # to a file, regardless of the Ruby version or if `freeze` or `<<` are
@@ -141,7 +146,7 @@ module RuboCop
141
146
 
142
147
  def frozen_string_literal_comment(processed_source)
143
148
  processed_source.find_token do |token|
144
- token.text.start_with?(FrozenStringLiteral::FROZEN_STRING_LITERAL)
149
+ token.text.start_with?(FROZEN_STRING_LITERAL)
145
150
  end
146
151
  end
147
152
 
@@ -8,6 +8,10 @@ module RuboCop
8
8
  # reassign (possibly to redirect some stream) constants in Ruby, you'll get
9
9
  # an interpreter warning if you do so.
10
10
  #
11
+ # @safety
12
+ # Autocorrection is unsafe because `STDOUT` and `$stdout` may point to different
13
+ # objects, for example.
14
+ #
11
15
  # @example
12
16
  # # bad
13
17
  # STDOUT.puts('hello')
@@ -29,6 +29,7 @@ module RuboCop
29
29
  # # good
30
30
  # [{ one: 1 }, { two: 2 }]
31
31
  class HashAsLastArrayItem < Base
32
+ include RangeHelp
32
33
  include ConfigurableEnforcedStyle
33
34
  extend AutoCorrector
34
35
 
@@ -74,6 +75,7 @@ module RuboCop
74
75
  return if node.children.empty? # Empty hash cannot be "unbraced"
75
76
 
76
77
  add_offense(node, message: 'Omit the braces around the hash.') do |corrector|
78
+ remove_last_element_trailing_comma(corrector, node.parent)
77
79
  corrector.remove(node.loc.begin)
78
80
  corrector.remove(node.loc.end)
79
81
  end
@@ -82,6 +84,15 @@ module RuboCop
82
84
  def braces_style?
83
85
  style == :braces
84
86
  end
87
+
88
+ def remove_last_element_trailing_comma(corrector, node)
89
+ range = range_with_surrounding_space(
90
+ range: node.children.last.source_range,
91
+ side: :right
92
+ ).end.resize(1)
93
+
94
+ corrector.remove(range) if range.source == ','
95
+ end
85
96
  end
86
97
  end
87
98
  end
@@ -9,6 +9,11 @@ module RuboCop
9
9
  # parentheses around the block arguments to indicate that you're not
10
10
  # working with a hash, and suppress RuboCop offenses.
11
11
  #
12
+ # @safety
13
+ # This cop is unsafe because it cannot be guaranteed that the receiver
14
+ # is a `Hash`. The `AllowedReceivers` configuration can mitigate,
15
+ # but not fully resolve, this safety issue.
16
+ #
12
17
  # @example
13
18
  # # bad
14
19
  # hash.keys.each { |k| p k }
@@ -49,7 +49,7 @@ module RuboCop
49
49
  return unless bad_method?(block) && semantically_except_method?(node, block)
50
50
 
51
51
  except_key = except_key(block)
52
- return unless safe_to_register_offense?(block, except_key)
52
+ return if except_key.nil? || !safe_to_register_offense?(block, except_key)
53
53
 
54
54
  range = offense_range(node)
55
55
  preferred_method = "except(#{except_key.source})"
@@ -81,10 +81,11 @@ module RuboCop
81
81
  end
82
82
 
83
83
  def except_key(node)
84
- key_argument = node.argument_list.first
84
+ key_argument = node.argument_list.first.source
85
85
  lhs, _method_name, rhs = *node.body
86
+ return if [lhs, rhs].map(&:source).none?(key_argument)
86
87
 
87
- [lhs, rhs].find { |operand| operand.source != key_argument.source }
88
+ [lhs, rhs].find { |operand| operand.source != key_argument }
88
89
  end
89
90
 
90
91
  def offense_range(node)
@@ -8,12 +8,10 @@ module RuboCop
8
8
  # transforming the keys of a hash, and tries to use a simpler & faster
9
9
  # call to `transform_keys` instead.
10
10
  #
11
- # This can produce false positives if we are transforming an enumerable
12
- # of key-value-like pairs that isn't actually a hash, e.g.:
13
- # `[[k1, v1], [k2, v2], ...]`
14
- #
15
- # This cop should only be enabled on Ruby version 2.5 or newer
16
- # (`transform_keys` was added in Ruby 2.5.)
11
+ # @safety
12
+ # This cop is unsafe, as it can produce false positives if we are
13
+ # transforming an enumerable of key-value-like pairs that isn't actually
14
+ # a hash, e.g.: `[[k1, v1], [k2, v2], ...]`
17
15
  #
18
16
  # @example
19
17
  # # bad
@@ -8,12 +8,10 @@ module RuboCop
8
8
  # transforming the values of a hash, and tries to use a simpler & faster
9
9
  # call to `transform_values` instead.
10
10
  #
11
- # This can produce false positives if we are transforming an enumerable
12
- # of key-value-like pairs that isn't actually a hash, e.g.:
13
- # `[[k1, v1], [k2, v2], ...]`
14
- #
15
- # This cop should only be enabled on Ruby version 2.4 or newer
16
- # (`transform_values` was added in Ruby 2.4.)
11
+ # @safety
12
+ # This cop is unsafe, as it can produce false positives if we are
13
+ # transforming an enumerable of key-value-like pairs that isn't actually
14
+ # a hash, e.g.: `[[k1, v1], [k2, v2], ...]`
17
15
  #
18
16
  # @example
19
17
  # # bad
@@ -7,26 +7,28 @@ module RuboCop
7
7
  # each branch of a conditional expression. Such expressions should normally
8
8
  # be placed outside the conditional expression - before or after it.
9
9
  #
10
- # This cop is marked unsafe auto-correction as the order of method invocations
11
- # must be guaranteed in the following case:
12
- #
13
- # [source,ruby]
14
- # ----
15
- # if method_that_modifies_global_state # 1
16
- # method_that_relies_on_global_state # 2
17
- # foo # 3
18
- # else
19
- # method_that_relies_on_global_state # 2
20
- # bar # 3
21
- # end
22
- # ----
23
- #
24
- # In such a case, auto-correction may change the invocation order.
25
- #
26
10
  # NOTE: The cop is poorly named and some people might think that it actually
27
11
  # checks for duplicated conditional branches. The name will probably be changed
28
12
  # in a future major RuboCop release.
29
13
  #
14
+ # @safety
15
+ # Auto-correction is unsafe because changing the order of method invocations
16
+ # may change the behaviour of the code. For example:
17
+ #
18
+ # [source,ruby]
19
+ # ----
20
+ # if method_that_modifies_global_state # 1
21
+ # method_that_relies_on_global_state # 2
22
+ # foo # 3
23
+ # else
24
+ # method_that_relies_on_global_state # 2
25
+ # bar # 3
26
+ # end
27
+ # ----
28
+ #
29
+ # In this example, `method_that_relies_on_global_state` will be moved before
30
+ # `method_that_modifies_global_state`, which changes the behaviour of the program.
31
+ #
30
32
  # @example
31
33
  # # bad
32
34
  # if condition
@@ -6,8 +6,10 @@ module RuboCop
6
6
  # This cop checks for redundant `if` with boolean literal branches.
7
7
  # It checks only conditions to return boolean value (`true` or `false`) for safe detection.
8
8
  # The conditions to be checked are comparison methods, predicate methods, and double negative.
9
- # However, auto-correction is unsafe because there is no guarantee that all predicate methods
10
- # will return boolean value. Those methods can be allowed with `AllowedMethods` config.
9
+ #
10
+ # @safety
11
+ # Auto-correction is unsafe because there is no guarantee that all predicate methods
12
+ # will return a boolean value. Those methods can be allowed with `AllowedMethods` config.
11
13
  #
12
14
  # @example
13
15
  # # bad
@@ -23,6 +25,17 @@ module RuboCop
23
25
  # # good
24
26
  # foo == bar
25
27
  #
28
+ # @example
29
+ # # bad
30
+ # if foo.do_something?
31
+ # true
32
+ # else
33
+ # false
34
+ # end
35
+ #
36
+ # # good (but potentially an unsafe correction)
37
+ # foo.do_something?
38
+ #
26
39
  # @example AllowedMethods: ['nonzero?']
27
40
  # # good
28
41
  # num.nonzero? ? true : false
@@ -109,12 +122,13 @@ module RuboCop
109
122
  end
110
123
 
111
124
  def opposite_condition?(node)
112
- !node.unless? && node.if_branch.false_type? || node.unless? && node.if_branch.true_type?
125
+ (!node.unless? && node.if_branch.false_type?) ||
126
+ (node.unless? && node.if_branch.true_type?)
113
127
  end
114
128
 
115
129
  def require_parentheses?(condition)
116
130
  condition.and_type? || condition.or_type? ||
117
- condition.send_type? && condition.comparison_method?
131
+ (condition.send_type? && condition.comparison_method?)
118
132
  end
119
133
  end
120
134
  end
@@ -5,9 +5,10 @@ module RuboCop
5
5
  module Style
6
6
  # Use `Kernel#loop` for infinite loops.
7
7
  #
8
- # This cop is marked as unsafe as the rule does not necessarily
9
- # apply if the body might raise a `StopIteration` exception; contrary to
10
- # other infinite loops, `Kernel#loop` silently rescues that and returns `nil`.
8
+ # @safety
9
+ # This cop is unsafe as the rule should not necessarily apply if the loop
10
+ # body might raise a `StopIteration` exception; contrary to other infinite
11
+ # loops, `Kernel#loop` silently rescues that and returns `nil`.
11
12
  #
12
13
  # @example
13
14
  # # bad
@@ -5,11 +5,18 @@ module RuboCop
5
5
  module Style
6
6
  # This cop check for usages of not (`not` or `!`) called on a method
7
7
  # when an inverse of that method can be used instead.
8
+ #
8
9
  # Methods that can be inverted by a not (`not` or `!`) should be defined
9
- # in `InverseMethods`
10
+ # in `InverseMethods`.
11
+ #
10
12
  # Methods that are inverted by inverting the return
11
13
  # of the block that is passed to the method should be defined in
12
- # `InverseBlocks`
14
+ # `InverseBlocks`.
15
+ #
16
+ # @safety
17
+ # This cop is unsafe because it cannot be guaranteed that the method
18
+ # and its inverse method are both defined on receiver, and also are
19
+ # actually inverse of each other.
13
20
  #
14
21
  # @example
15
22
  # # bad
@@ -52,7 +52,7 @@ module RuboCop
52
52
  private
53
53
 
54
54
  def offense?(node)
55
- explicit_style? && node.implicit_call? || implicit_style? && !node.implicit_call?
55
+ (explicit_style? && node.implicit_call?) || (implicit_style? && !node.implicit_call?)
56
56
  end
57
57
 
58
58
  def message(_node)
@@ -6,6 +6,19 @@ module RuboCop
6
6
  # This cop checks for string literal concatenation at
7
7
  # the end of a line.
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe because it cannot be guaranteed that the
11
+ # receiver is a string, in which case replacing `<<` with `\`
12
+ # would result in a syntax error.
13
+ #
14
+ # For example, this would be a false positive:
15
+ # [source,ruby]
16
+ # ----
17
+ # array << 'foo' <<
18
+ # 'bar' <<
19
+ # 'baz'
20
+ # ----
21
+ #
9
22
  # @example
10
23
  #
11
24
  # # bad
@@ -93,8 +93,8 @@ module RuboCop
93
93
  parent = node.parent&.block_type? ? node.parent.parent : node.parent
94
94
  parent &&
95
95
  (logical_operator?(parent) ||
96
- parent.send_type? &&
97
- parent.arguments.any? { |argument| logical_operator?(argument) })
96
+ (parent.send_type? &&
97
+ parent.arguments.any? { |argument| logical_operator?(argument) }))
98
98
  end
99
99
 
100
100
  def call_in_optional_arguments?(node)
@@ -122,14 +122,14 @@ module RuboCop
122
122
 
123
123
  def call_as_argument_or_chain?(node)
124
124
  node.parent &&
125
- (node.parent.send_type? && !assigned_before?(node.parent, node) ||
125
+ ((node.parent.send_type? && !assigned_before?(node.parent, node)) ||
126
126
  node.parent.csend_type? || node.parent.super_type? || node.parent.yield_type?)
127
127
  end
128
128
 
129
129
  def hash_literal_in_arguments?(node)
130
130
  node.arguments.any? do |n|
131
131
  hash_literal?(n) ||
132
- n.send_type? && node.descendants.any? { |descendant| hash_literal?(descendant) }
132
+ (n.send_type? && node.descendants.any? { |descendant| hash_literal?(descendant) })
133
133
  end
134
134
  end
135
135
 
@@ -171,8 +171,8 @@ module RuboCop
171
171
  end
172
172
 
173
173
  def unary_literal?(node)
174
- node.numeric_type? && node.sign? ||
175
- node.parent&.send_type? && node.parent&.unary_operation?
174
+ (node.numeric_type? && node.sign?) ||
175
+ (node.parent&.send_type? && node.parent&.unary_operation?)
176
176
  end
177
177
 
178
178
  def assigned_before?(node, target)
@@ -6,7 +6,14 @@ module RuboCop
6
6
  # This cop checks for use of `extend self` or `module_function` in a
7
7
  # module.
8
8
  #
9
- # Supported styles are: module_function, extend_self, forbidden.
9
+ # Supported styles are: module_function, extend_self, forbidden. `forbidden`
10
+ # style prohibits the usage of both styles.
11
+ #
12
+ # NOTE: the cop won't be activated when the module contains any private methods.
13
+ #
14
+ # @safety
15
+ # Autocorrection is unsafe (and is disabled by default) because `extend self`
16
+ # and `module_function` do not behave exactly the same.
10
17
  #
11
18
  # @example EnforcedStyle: module_function (default)
12
19
  # # bad
@@ -21,9 +28,6 @@ module RuboCop
21
28
  # # ...
22
29
  # end
23
30
  #
24
- # In case there are private methods, the cop won't be activated.
25
- # Otherwise, it forces to change the flow of the default code.
26
- #
27
31
  # @example EnforcedStyle: module_function (default)
28
32
  # # good
29
33
  # module Test
@@ -46,8 +50,6 @@ module RuboCop
46
50
  # # ...
47
51
  # end
48
52
  #
49
- # The option `forbidden` prohibits the usage of both styles.
50
- #
51
53
  # @example EnforcedStyle: forbidden
52
54
  # # bad
53
55
  # module Test
@@ -68,9 +70,6 @@ module RuboCop
68
70
  # private
69
71
  # # ...
70
72
  # end
71
- #
72
- # These offenses are not safe to auto-correct since there are different
73
- # implications to each approach.
74
73
  class ModuleFunction < Base
75
74
  include ConfigurableEnforcedStyle
76
75
  extend AutoCorrector
@@ -14,8 +14,25 @@ module RuboCop
14
14
  # positives. Luckily, there is no harm in freezing an already
15
15
  # frozen object.
16
16
  #
17
+ # From Ruby 3.0, this cop honours the magic comment
18
+ # 'shareable_constant_value'. When this magic comment is set to any
19
+ # acceptable value other than none, it will suppress the offenses
20
+ # raised by this cop. It enforces frozen state.
21
+ #
17
22
  # NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
18
23
  #
24
+ # NOTE: From Ruby 3.0, interpolated strings are not frozen when
25
+ # `# frozen-string-literal: true` is used, so this cop enforces explicit
26
+ # freezing for such strings.
27
+ #
28
+ # NOTE: From Ruby 3.0, this cop allows explicit freezing of constants when
29
+ # the `shareable_constant_value` directive is used.
30
+ #
31
+ # @safety
32
+ # This cop's autocorrection is unsafe since any mutations on objects that
33
+ # are made frozen will change from being accepted to raising `FrozenError`,
34
+ # and will need to be manually refactored.
35
+ #
19
36
  # @example EnforcedStyle: literals (default)
20
37
  # # bad
21
38
  # CONST = [1, 2, 3]
@@ -52,7 +69,55 @@ module RuboCop
52
69
  # puts 1
53
70
  # end
54
71
  # end.freeze
72
+ #
73
+ # @example
74
+ # # Magic comment - shareable_constant_value: literal
75
+ #
76
+ # # bad
77
+ # CONST = [1, 2, 3]
78
+ #
79
+ # # good
80
+ # # shareable_constant_value: literal
81
+ # CONST = [1, 2, 3]
82
+ #
55
83
  class MutableConstant < Base
84
+ # Handles magic comment shareable_constant_value with O(n ^ 2) complexity
85
+ # n - number of lines in the source
86
+ # Iterates over all lines before a CONSTANT
87
+ # until it reaches shareable_constant_value
88
+ module ShareableConstantValue
89
+ module_function
90
+
91
+ def recent_shareable_value?(node)
92
+ shareable_constant_comment = magic_comment_in_scope node
93
+ return false if shareable_constant_comment.nil?
94
+
95
+ shareable_constant_value = MagicComment.parse(shareable_constant_comment)
96
+ .shareable_constant_value
97
+ shareable_constant_value_enabled? shareable_constant_value
98
+ end
99
+
100
+ # Identifies the most recent magic comment with valid shareable constant values
101
+ # that's in scope for this node
102
+ def magic_comment_in_scope(node)
103
+ processed_source_till_node(node).reverse_each.find do |line|
104
+ MagicComment.parse(line).valid_shareable_constant_value?
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def processed_source_till_node(node)
111
+ processed_source.lines[0..(node.last_line - 1)]
112
+ end
113
+
114
+ def shareable_constant_value_enabled?(value)
115
+ %w[literal experimental_everything experimental_copy].include? value
116
+ end
117
+ end
118
+ private_constant :ShareableConstantValue
119
+
120
+ include ShareableConstantValue
56
121
  include FrozenStringLiteral
57
122
  include ConfigurableEnforcedStyle
58
123
  extend AutoCorrector
@@ -85,18 +150,18 @@ module RuboCop
85
150
  return if immutable_literal?(value)
86
151
  return if operation_produces_immutable_object?(value)
87
152
  return if frozen_string_literal?(value)
153
+ return if shareable_constant_value?(value)
88
154
 
89
155
  add_offense(value) { |corrector| autocorrect(corrector, value) }
90
156
  end
91
157
 
92
158
  def check(value)
93
159
  range_enclosed_in_parentheses = range_enclosed_in_parentheses?(value)
94
-
95
160
  return unless mutable_literal?(value) ||
96
- target_ruby_version <= 2.7 && range_enclosed_in_parentheses
161
+ (target_ruby_version <= 2.7 && range_enclosed_in_parentheses)
97
162
 
98
- return if FROZEN_STRING_LITERAL_TYPES.include?(value.type) &&
99
- frozen_string_literals_enabled?
163
+ return if frozen_string_literal?(value)
164
+ return if shareable_constant_value?(value)
100
165
 
101
166
  add_offense(value) { |corrector| autocorrect(corrector, value) }
102
167
  end
@@ -126,8 +191,10 @@ module RuboCop
126
191
  frozen_regexp_or_range_literals?(node) || node.immutable_literal?
127
192
  end
128
193
 
129
- def frozen_string_literal?(node)
130
- FROZEN_STRING_LITERAL_TYPES.include?(node.type) && frozen_string_literals_enabled?
194
+ def shareable_constant_value?(node)
195
+ return false if target_ruby_version < 3.0
196
+
197
+ recent_shareable_value? node
131
198
  end
132
199
 
133
200
  def frozen_regexp_or_range_literals?(node)
@@ -90,7 +90,7 @@ module RuboCop
90
90
  end
91
91
 
92
92
  def correct_style?(node)
93
- style == :prefix && node.modifier_form? || style == :postfix && !node.modifier_form?
93
+ (style == :prefix && node.modifier_form?) || (style == :postfix && !node.modifier_form?)
94
94
  end
95
95
  end
96
96
  end
@@ -80,7 +80,7 @@ module RuboCop
80
80
  end
81
81
 
82
82
  def correct_style?(node)
83
- style == :prefix && node.modifier_form? || style == :postfix && !node.modifier_form?
83
+ (style == :prefix && node.modifier_form?) || (style == :postfix && !node.modifier_form?)
84
84
  end
85
85
  end
86
86
  end
@@ -63,7 +63,7 @@ module RuboCop
63
63
 
64
64
  def on_send(node)
65
65
  return if ignored_node?(node) ||
66
- !include_semantic_changes? && nil_comparison_style == 'comparison'
66
+ (!include_semantic_changes? && nil_comparison_style == 'comparison')
67
67
  return unless register_offense?(node)
68
68
 
69
69
  message = message(node)
@@ -87,7 +87,7 @@ module RuboCop
87
87
 
88
88
  def register_offense?(node)
89
89
  not_equal_to_nil?(node) ||
90
- include_semantic_changes? && (not_and_nil_check?(node) || unless_and_nil_check?(node))
90
+ (include_semantic_changes? && (not_and_nil_check?(node) || unless_and_nil_check?(node)))
91
91
  end
92
92
 
93
93
  def autocorrect(corrector, node)
@@ -53,8 +53,8 @@ module RuboCop
53
53
 
54
54
  def requires_parens?(child)
55
55
  child.and_type? || child.or_type? ||
56
- child.send_type? && child.binary_operation? ||
57
- child.if_type? && child.ternary?
56
+ (child.send_type? && child.binary_operation?) ||
57
+ (child.if_type? && child.ternary?)
58
58
  end
59
59
 
60
60
  def correct_opposite_method(corrector, range, child)