rubocop 1.21.0 → 1.22.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +49 -9
  4. data/lib/rubocop/config.rb +5 -0
  5. data/lib/rubocop/config_loader.rb +3 -1
  6. data/lib/rubocop/config_validator.rb +9 -1
  7. data/lib/rubocop/cop/base.rb +1 -1
  8. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  9. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +34 -11
  10. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  11. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
  12. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  13. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +31 -24
  14. data/lib/rubocop/cop/generator.rb +14 -8
  15. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
  16. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  17. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  18. data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
  19. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  20. data/lib/rubocop/cop/layout/dot_position.rb +34 -5
  21. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  22. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
  23. data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
  24. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
  25. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  26. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  27. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  28. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  29. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  30. data/lib/rubocop/cop/layout/line_length.rb +8 -6
  31. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  32. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -2
  33. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  34. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  35. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  36. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  37. data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -28
  38. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +5 -1
  39. data/lib/rubocop/cop/lint/ambiguous_range.rb +8 -8
  40. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  41. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  42. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  43. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  44. data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
  45. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  46. data/lib/rubocop/cop/lint/else_layout.rb +10 -6
  47. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  48. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  49. data/lib/rubocop/cop/lint/loop.rb +4 -3
  50. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  51. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  52. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  53. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  54. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  55. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  56. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  57. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  58. data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
  59. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  60. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  61. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  62. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  63. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  64. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  65. data/lib/rubocop/cop/lint/useless_times.rb +3 -2
  66. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  67. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  68. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
  69. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +5 -1
  70. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  71. data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
  72. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  73. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  74. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  75. data/lib/rubocop/cop/mixin/percent_array.rb +6 -1
  76. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  77. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  78. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  79. data/lib/rubocop/cop/mixin/string_literals_help.rb +5 -1
  80. data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
  81. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  82. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  83. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  84. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  85. data/lib/rubocop/cop/security/json_load.rb +8 -7
  86. data/lib/rubocop/cop/security/open.rb +4 -0
  87. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  88. data/lib/rubocop/cop/style/and_or.rb +4 -3
  89. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  90. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  91. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  92. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  93. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  94. data/lib/rubocop/cop/style/collection_methods.rb +6 -5
  95. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  96. data/lib/rubocop/cop/style/commented_keyword.rb +9 -4
  97. data/lib/rubocop/cop/style/date_time.rb +5 -0
  98. data/lib/rubocop/cop/style/double_negation.rb +15 -5
  99. data/lib/rubocop/cop/style/float_division.rb +10 -2
  100. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -1
  101. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  102. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  103. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
  104. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  105. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
  106. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +15 -2
  107. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  108. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  109. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -1
  110. data/lib/rubocop/cop/style/module_function.rb +8 -9
  111. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  112. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  113. data/lib/rubocop/cop/style/mutable_constant.rb +12 -7
  114. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  115. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  116. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  117. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  118. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  119. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  120. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  121. data/lib/rubocop/cop/style/quoted_symbols.rb +10 -6
  122. data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
  123. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  124. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  125. data/lib/rubocop/cop/style/redundant_freeze.rb +0 -1
  126. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  127. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  128. data/lib/rubocop/cop/style/redundant_sort.rb +47 -29
  129. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  130. data/lib/rubocop/cop/style/select_by_regexp.rb +139 -0
  131. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  132. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  133. data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
  134. data/lib/rubocop/cop/style/static_class.rb +4 -3
  135. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  136. data/lib/rubocop/cop/style/string_concatenation.rb +4 -0
  137. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  138. data/lib/rubocop/cop/style/struct_inheritance.rb +3 -2
  139. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  140. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  141. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  142. data/lib/rubocop/cop/style/yoda_condition.rb +20 -0
  143. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  144. data/lib/rubocop/cop/util.rb +15 -4
  145. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  146. data/lib/rubocop/options.rb +126 -112
  147. data/lib/rubocop/rake_task.rb +1 -1
  148. data/lib/rubocop/result_cache.rb +2 -2
  149. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  150. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  151. data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
  152. data/lib/rubocop/rspec/support.rb +1 -0
  153. data/lib/rubocop/runner.rb +1 -1
  154. data/lib/rubocop/target_finder.rb +1 -1
  155. data/lib/rubocop/version.rb +1 -1
  156. data/lib/rubocop.rb +5 -0
  157. metadata +12 -5
@@ -36,7 +36,12 @@ module RuboCop
36
36
  def check_percent_array(node)
37
37
  array_style_detected(:percent, node.values.size)
38
38
 
39
- return unless style == :brackets || invalid_percent_array_contents?(node)
39
+ brackets_required = invalid_percent_array_contents?(node)
40
+ return unless style == :brackets || brackets_required
41
+
42
+ # If in percent style but brackets are required due to
43
+ # string content, the file should be excluded in auto-gen-config
44
+ no_acceptable_style! if brackets_required
40
45
 
41
46
  bracketed_array = build_bracketed_array(node)
42
47
  message = format(self.class::ARRAY_MSG, prefer: bracketed_array)
@@ -28,7 +28,7 @@ module RuboCop
28
28
  end
29
29
 
30
30
  def space_missing?(token1, token2)
31
- token1.line == token2.line && token2.column == token1.column + offset
31
+ same_line?(token1, token2) && token2.column == token1.column + offset
32
32
  end
33
33
 
34
34
  def space_required_before?(token)
@@ -32,7 +32,7 @@ module RuboCop
32
32
  end
33
33
 
34
34
  def space_missing?(token1, token2)
35
- token1.line == token2.line && token2.begin_pos > token1.end_pos
35
+ same_line?(token1, token2) && token2.begin_pos > token1.end_pos
36
36
  end
37
37
 
38
38
  def space_required_after?(token)
@@ -54,7 +54,7 @@ module RuboCop
54
54
  end
55
55
 
56
56
  def first_line_comment(node)
57
- comment = processed_source.find_comment { |c| c.loc.line == node.loc.line }
57
+ comment = processed_source.find_comment { |c| same_line?(c, node) }
58
58
  return unless comment
59
59
 
60
60
  comment_source = comment.loc.expression.source
@@ -13,7 +13,11 @@ module RuboCop
13
13
  if style == :single_quotes
14
14
  !double_quotes_required?(src)
15
15
  else
16
- !/" | \\[^'\\] | \#[@{$]/x.match?(src)
16
+ # The string needs single quotes if:
17
+ # 1. It contains a double quote
18
+ # 2. It contains text that would become an escape sequence with double quotes
19
+ # 3. It contains text that would become an interpolation with double quotes
20
+ !/" | (?<!\\)\\[aAbcdefkMnprsStuUxzZ0-7] | \#[@{$]/x.match?(src)
17
21
  end
18
22
  end
19
23
  end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  end
11
11
 
12
12
  def body_on_first_line?(node, body)
13
- node.source_range.first_line == body.source_range.first_line
13
+ same_line?(node, body)
14
14
  end
15
15
 
16
16
  def first_part_of(body)
@@ -24,7 +24,7 @@ module RuboCop
24
24
  # # With `AllowNamesEndingInNumbers` set to false
25
25
  # foo { |num1, num2| num1 * num2 }
26
26
  #
27
- # # With `MinParamNameLength` set to number greater than 1
27
+ # # With `MinNameLength` set to number greater than 1
28
28
  # baz { |a, b, c| do_stuff(a, b, c) }
29
29
  #
30
30
  # # good
@@ -14,6 +14,11 @@ module RuboCop
14
14
  # convention that is used to implicitly indicate that an ivar should not
15
15
  # be set or referenced outside of the memoization method.
16
16
  #
17
+ # @safety
18
+ # This cop relies on the pattern `@instance_var ||= ...`,
19
+ # but this is sometimes used for other purposes than memoization
20
+ # so this cop is considered unsafe.
21
+ #
17
22
  # @example EnforcedStyleForLeadingUnderscores: disallowed (default)
18
23
  # # bad
19
24
  # # Method foo is memoized using an instance variable that is
@@ -139,10 +144,6 @@ module RuboCop
139
144
  # define_method(:foo) do
140
145
  # @_foo ||= calculate_expensive_thing
141
146
  # end
142
- #
143
- # This cop relies on the pattern `@instance_var ||= ...`,
144
- # but this is sometimes used for other purposes than memoization
145
- # so this cop is considered unsafe.
146
147
  class MemoizedInstanceVariableName < Base
147
148
  include ConfigurableEnforcedStyle
148
149
 
@@ -75,6 +75,9 @@ module RuboCop
75
75
  preferred_name = preferred_name(offending_name)
76
76
  return if preferred_name.to_sym == offending_name
77
77
 
78
+ # check variable shadowing for exception variable
79
+ return if shadowed_variable_name?(node)
80
+
78
81
  range = offense_range(node)
79
82
  message = message(node)
80
83
 
@@ -150,6 +153,10 @@ module RuboCop
150
153
  preferred_name = preferred_name(offending_name)
151
154
  format(MSG, preferred: preferred_name, bad: offending_name)
152
155
  end
156
+
157
+ def shadowed_variable_name?(node)
158
+ node.each_descendant(:lvar).any? { |n| n.children.first.to_s == preferred_name(n) }
159
+ end
153
160
  end
154
161
  end
155
162
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Security
6
+ # Checks for the first argument to `IO.read`, `IO.binread`, `IO.write`, `IO.binwrite`,
7
+ # `IO.foreach`, and `IO.readlines`.
8
+ #
9
+ # If argument starts with a pipe character (`'|'`) and the receiver is the `IO` class,
10
+ # a subprocess is created in the same way as `Kernel#open`, and its output is returned.
11
+ # `Kernel#open` may allow unintentional command injection, which is the reason these
12
+ # `IO` methods are a security risk.
13
+ # Consider to use `File.read` to disable the behavior of subprocess invocation.
14
+ #
15
+ # @safety
16
+ # This cop is unsafe because false positive will occur if the variable passed as
17
+ # the first argument is a command that is not a file path.
18
+ #
19
+ # @example
20
+ #
21
+ # # bad
22
+ # IO.read(path)
23
+ # IO.read('path')
24
+ #
25
+ # # good
26
+ # File.read(path)
27
+ # File.read('path')
28
+ # IO.read('| command') # Allow intentional command invocation.
29
+ #
30
+ class IoMethods < Base
31
+ extend AutoCorrector
32
+
33
+ MSG = '`File.%<method_name>s` is safer than `IO.%<method_name>s`.'
34
+ RESTRICT_ON_SEND = %i[read binread write binwrite foreach readlines].freeze
35
+
36
+ def on_send(node)
37
+ return unless (receiver = node.receiver) && receiver.source == 'IO'
38
+
39
+ argument = node.first_argument
40
+ return if argument.respond_to?(:value) && argument.value.strip.start_with?('|')
41
+
42
+ add_offense(node, message: format(MSG, method_name: node.method_name)) do |corrector|
43
+ corrector.replace(receiver, 'File')
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -6,13 +6,14 @@ module RuboCop
6
6
  # This cop checks for the use of JSON class methods which have potential
7
7
  # security issues.
8
8
  #
9
- # Autocorrect is disabled by default because it's potentially dangerous.
10
- # If using a stream, like `JSON.load(open('file'))`, it will need to call
11
- # `#read` manually, like `JSON.parse(open('file').read)`.
12
- # If reading single values (rather than proper JSON objects), like
13
- # `JSON.load('false')`, it will need to pass the `quirks_mode: true`
14
- # option, like `JSON.parse('false', quirks_mode: true)`.
15
- # Other similar issues may apply.
9
+ # @safety
10
+ # This cop's autocorrection is unsafe because it's potentially dangerous.
11
+ # If using a stream, like `JSON.load(open('file'))`, it will need to call
12
+ # `#read` manually, like `JSON.parse(open('file').read)`.
13
+ # If reading single values (rather than proper JSON objects), like
14
+ # `JSON.load('false')`, it will need to pass the `quirks_mode: true`
15
+ # option, like `JSON.parse('false', quirks_mode: true)`.
16
+ # Other similar issues may apply.
16
17
  #
17
18
  # @example
18
19
  # # bad
@@ -11,6 +11,10 @@ module RuboCop
11
11
  # the argument of `Kernel#open` and `URI.open`. It would be better to use
12
12
  # `File.open`, `IO.popen` or `URI.parse#open` explicitly.
13
13
  #
14
+ # @safety
15
+ # This cop could register false positives if `open` is redefined
16
+ # in a class and then used without a receiver in that class.
17
+ #
14
18
  # @example
15
19
  # # bad
16
20
  # open(something)
@@ -7,6 +7,10 @@ module RuboCop
7
7
  # potential security issues leading to remote code execution when
8
8
  # loading from an untrusted source.
9
9
  #
10
+ # @safety
11
+ # The behaviour of the code might change depending on what was
12
+ # in the YAML payload, since `YAML.safe_load` is more restrictive.
13
+ #
10
14
  # @example
11
15
  # # bad
12
16
  # YAML.load("--- foo")
@@ -7,9 +7,10 @@ module RuboCop
7
7
  # `||` instead. It can be configured to check only in conditions or in
8
8
  # all contexts.
9
9
  #
10
- # It is marked as unsafe auto-correction because it may change the
11
- # operator precedence between logical operators (`&&` and `||`) and
12
- # semantic operators (`and` and `or`).
10
+ # @safety
11
+ # Auto-correction is unsafe because there is a different operator precedence
12
+ # between logical operators (`&&` and `||`) and semantic operators (`and` and `or`),
13
+ # and that might change the behaviour.
13
14
  #
14
15
  # @example EnforcedStyle: always
15
16
  # # bad
@@ -30,6 +30,10 @@ module RuboCop
30
30
  # bar(*args)
31
31
  # end
32
32
  #
33
+ # def foo(**kwargs)
34
+ # bar(**kwargs)
35
+ # end
36
+ #
33
37
  # @example AllowOnlyRestArgument: false
34
38
  # # bad
35
39
  # # The following code can replace the arguments with `...`,
@@ -38,6 +42,10 @@ module RuboCop
38
42
  # bar(*args)
39
43
  # end
40
44
  #
45
+ # def foo(**kwargs)
46
+ # bar(**kwargs)
47
+ # end
48
+ #
41
49
  class ArgumentsForwarding < Base
42
50
  include RangeHelp
43
51
  extend AutoCorrector
@@ -49,12 +57,15 @@ module RuboCop
49
57
 
50
58
  # @!method use_rest_arguments?(node)
51
59
  def_node_matcher :use_rest_arguments?, <<~PATTERN
52
- (args (restarg $_) $...)
60
+ (args ({restarg kwrestarg} $_) $...)
53
61
  PATTERN
54
62
 
55
63
  # @!method only_rest_arguments?(node, name)
56
64
  def_node_matcher :only_rest_arguments?, <<~PATTERN
57
- (send _ _ (splat (lvar %1)))
65
+ {
66
+ (send _ _ (splat (lvar %1)))
67
+ (send _ _ (hash (kwsplat (lvar %1))))
68
+ }
58
69
  PATTERN
59
70
 
60
71
  # @!method forwarding_method_arguments?(node, rest_name, block_name, kwargs_name)
@@ -5,9 +5,27 @@ module RuboCop
5
5
  module Style
6
6
  # This cop enforces the use of `Array()` instead of explicit `Array` check or `[*var]`.
7
7
  #
8
- # This cop is disabled by default because false positive will occur if
9
- # the argument of `Array()` is not an array (e.g. Hash, Set),
10
- # an array will be returned as an incompatibility result.
8
+ # The cop is disabled by default due to safety concerns.
9
+ #
10
+ # @safety
11
+ # This cop is unsafe because a false positive may occur if
12
+ # the argument of `Array()` is (or could be) nil or depending
13
+ # on how the argument is handled by `Array()` (which can be
14
+ # different than just wrapping the argument in an array).
15
+ #
16
+ # For example:
17
+ #
18
+ # [source,ruby]
19
+ # ----
20
+ # [nil] #=> [nil]
21
+ # Array(nil) #=> []
22
+ #
23
+ # [{a: 'b'}] #= [{a: 'b'}]
24
+ # Array({a: 'b'}) #=> [[:a, 'b']]
25
+ #
26
+ # [Time.now] #=> [#<Time ...>]
27
+ # Array(Time.now) #=> [14, 16, 14, 16, 9, 2021, 4, 259, true, "EDT"]
28
+ # ----
11
29
  #
12
30
  # @example
13
31
  # # bad
@@ -6,6 +6,11 @@ module RuboCop
6
6
  # This cop identifies places where `if-elsif` constructions
7
7
  # can be replaced with `case-when`.
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe. `case` statements use `===` for equality,
11
+ # so if the original conditional used a different equality operator, the
12
+ # behaviour may be different.
13
+ #
9
14
  # @example
10
15
  # # bad
11
16
  # if status == :active
@@ -6,6 +6,15 @@ module RuboCop
6
6
  # This cop checks the style of children definitions at classes and
7
7
  # modules. Basically there are two different styles:
8
8
  #
9
+ # @safety
10
+ # Autocorrection is unsafe.
11
+ #
12
+ # Moving from compact to nested children requires knowledge of whether the
13
+ # outer parent is a module or a class. Moving from nested to compact requires
14
+ # verification that the outer parent is defined elsewhere. Rubocop does not
15
+ # have the knowledge to perform either operation safely and thus requires
16
+ # manual oversight.
17
+ #
9
18
  # @example EnforcedStyle: nested (default)
10
19
  # # good
11
20
  # # have each child on its own line
@@ -6,11 +6,13 @@ module RuboCop
6
6
  # This cop checks for places where custom logic on rejection nils from arrays
7
7
  # and hashes can be replaced with `{Array,Hash}#{compact,compact!}`.
8
8
  #
9
- # It is marked as unsafe by default because false positives may occur in the
10
- # nil check of block arguments to the receiver object.
11
- # For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
12
- # and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
13
- # when the receiver is a hash object.
9
+ # @safety
10
+ # It is unsafe by default because false positives may occur in the
11
+ # `nil` check of block arguments to the receiver object.
12
+ #
13
+ # For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
14
+ # and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
15
+ # when the receiver is a hash object.
14
16
  #
15
17
  # @example
16
18
  # # bad
@@ -6,10 +6,6 @@ module RuboCop
6
6
  # This cop enforces the use of consistent method names
7
7
  # from the Enumerable module.
8
8
  #
9
- # Unfortunately we cannot actually know if a method is from
10
- # Enumerable or not (static analysis limitation), so this cop
11
- # can yield some false positives.
12
- #
13
9
  # You can customize the mapping from undesired method to desired method.
14
10
  #
15
11
  # e.g. to use `detect` over `find`:
@@ -18,9 +14,14 @@ module RuboCop
18
14
  # PreferredMethods:
19
15
  # find: detect
20
16
  #
21
- # The default mapping for `PreferredMethods` behaves as follows.
17
+ # @safety
18
+ # This cop is unsafe because it finds methods by name, without actually
19
+ # being able to determine if the receiver is an Enumerable or not, so
20
+ # this cop may register false positives.
22
21
  #
23
22
  # @example
23
+ # # These examples are based on the default mapping for `PreferredMethods`.
24
+ #
24
25
  # # bad
25
26
  # items.collect
26
27
  # items.collect!
@@ -7,8 +7,9 @@ module RuboCop
7
7
  # can be combined into a single loop. It is very likely that combining them
8
8
  # will make the code more efficient and more concise.
9
9
  #
10
- # It is marked as unsafe, because the first loop might modify
11
- # a state that the second loop depends on; these two aren't combinable.
10
+ # @safety
11
+ # The cop is unsafe, because the first loop might modify state that the
12
+ # second loop depends on; these two aren't combinable.
12
13
  #
13
14
  # @example
14
15
  # # bad
@@ -12,7 +12,10 @@ module RuboCop
12
12
  #
13
13
  # Auto-correction removes comments from `end` keyword and keeps comments
14
14
  # for `class`, `module`, `def` and `begin` above the keyword.
15
- # It is marked as unsafe auto-correction as it may remove meaningful comments.
15
+ #
16
+ # @safety
17
+ # Auto-correction is unsafe because it may remove a comment that is
18
+ # meaningful.
16
19
  #
17
20
  # @example
18
21
  # # bad
@@ -49,9 +52,11 @@ module RuboCop
49
52
  ALLOWED_COMMENTS = %w[:nodoc: :yields: rubocop:disable rubocop:todo].freeze
50
53
  ALLOWED_COMMENT_REGEXES = ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ }.freeze
51
54
 
55
+ REGEXP = /(?<keyword>\S+).*#/.freeze
56
+
52
57
  def on_new_investigation
53
58
  processed_source.comments.each do |comment|
54
- next unless offensive?(comment) && (match = line(comment).match(/(?<keyword>\S+).*#/))
59
+ next unless offensive?(comment) && (match = source_line(comment).match(REGEXP))
55
60
 
56
61
  register_offense(comment, match[:keyword])
57
62
  end
@@ -73,12 +78,12 @@ module RuboCop
73
78
  end
74
79
 
75
80
  def offensive?(comment)
76
- line = line(comment)
81
+ line = source_line(comment)
77
82
  KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
78
83
  ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
79
84
  end
80
85
 
81
- def line(comment)
86
+ def source_line(comment)
82
87
  comment.location.expression.source_line
83
88
  end
84
89
  end
@@ -9,6 +9,11 @@ module RuboCop
9
9
  # replaceable in certain situations when dealing with multiple timezones
10
10
  # and/or DST.
11
11
  #
12
+ # @safety
13
+ # Autocorrection is not safe, because `DateTime` and `Time` do not have
14
+ # exactly the same behaviour, although in most cases the autocorrection
15
+ # will be fine.
16
+ #
12
17
  # @example
13
18
  #
14
19
  # # bad - uses `DateTime` for current time
@@ -9,6 +9,21 @@ module RuboCop
9
9
  # that use boolean as a return value. When using `EnforcedStyle: forbidden`, double negation
10
10
  # should be forbidden always.
11
11
  #
12
+ # NOTE: when `something` is a boolean value
13
+ # `!!something` and `!something.nil?` are not the same thing.
14
+ # As you're unlikely to write code that can accept values of any type
15
+ # this is rarely a problem in practice.
16
+ #
17
+ # @safety
18
+ # Autocorrection is unsafe when the value is `false`, because the result
19
+ # of the expression will change.
20
+ #
21
+ # [source,ruby]
22
+ # ----
23
+ # !!false #=> false
24
+ # !false.nil? #=> true
25
+ # ----
26
+ #
12
27
  # @example
13
28
  # # bad
14
29
  # !!something
@@ -27,11 +42,6 @@ module RuboCop
27
42
  # def foo?
28
43
  # !!return_value
29
44
  # end
30
- #
31
- # Please, note that when something is a boolean value
32
- # !!something and !something.nil? are not the same thing.
33
- # As you're unlikely to write code that can accept values of any type
34
- # this is rarely a problem in practice.
35
45
  class DoubleNegation < Base
36
46
  include ConfigurableEnforcedStyle
37
47
  extend AutoCorrector
@@ -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
@@ -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')
@@ -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 }
@@ -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