rubocop 1.21.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +43 -6
  4. data/lib/rubocop/config.rb +5 -0
  5. data/lib/rubocop/config_loader.rb +2 -0
  6. data/lib/rubocop/config_validator.rb +9 -1
  7. data/lib/rubocop/cop/base.rb +1 -1
  8. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +34 -11
  9. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  10. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
  11. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  12. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +1 -1
  13. data/lib/rubocop/cop/generator.rb +14 -8
  14. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  15. data/lib/rubocop/cop/layout/dot_position.rb +25 -2
  16. data/lib/rubocop/cop/layout/line_length.rb +7 -5
  17. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  18. data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -24
  19. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +5 -1
  20. data/lib/rubocop/cop/lint/ambiguous_range.rb +7 -7
  21. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  22. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  23. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  24. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  25. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  26. data/lib/rubocop/cop/lint/else_layout.rb +9 -5
  27. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  28. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  29. data/lib/rubocop/cop/lint/loop.rb +4 -3
  30. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  31. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  32. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  33. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  34. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  35. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  36. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  37. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  38. data/lib/rubocop/cop/lint/require_relative_self_path.rb +49 -0
  39. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  40. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  41. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  42. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  43. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  44. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  45. data/lib/rubocop/cop/lint/useless_times.rb +3 -2
  46. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  47. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +5 -1
  48. data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
  49. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  50. data/lib/rubocop/cop/mixin/percent_array.rb +6 -1
  51. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  52. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  53. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  54. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  55. data/lib/rubocop/cop/security/json_load.rb +8 -7
  56. data/lib/rubocop/cop/security/open.rb +4 -0
  57. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  58. data/lib/rubocop/cop/style/and_or.rb +4 -3
  59. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  60. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  61. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  62. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  63. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  64. data/lib/rubocop/cop/style/collection_methods.rb +6 -5
  65. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  66. data/lib/rubocop/cop/style/commented_keyword.rb +4 -1
  67. data/lib/rubocop/cop/style/date_time.rb +5 -0
  68. data/lib/rubocop/cop/style/double_negation.rb +15 -5
  69. data/lib/rubocop/cop/style/float_division.rb +10 -2
  70. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -1
  71. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  72. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  73. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
  74. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  75. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
  76. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +15 -2
  77. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  78. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  79. data/lib/rubocop/cop/style/line_end_concatenation.rb +13 -0
  80. data/lib/rubocop/cop/style/module_function.rb +8 -9
  81. data/lib/rubocop/cop/style/mutable_constant.rb +12 -7
  82. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  83. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  84. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  85. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  86. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  87. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  88. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  89. data/lib/rubocop/cop/style/redundant_argument.rb +14 -7
  90. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  91. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  92. data/lib/rubocop/cop/style/redundant_freeze.rb +0 -1
  93. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  94. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  95. data/lib/rubocop/cop/style/redundant_sort.rb +47 -29
  96. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  97. data/lib/rubocop/cop/style/select_by_regexp.rb +106 -0
  98. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  99. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  100. data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
  101. data/lib/rubocop/cop/style/static_class.rb +4 -3
  102. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  103. data/lib/rubocop/cop/style/string_concatenation.rb +4 -0
  104. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  105. data/lib/rubocop/cop/style/struct_inheritance.rb +3 -2
  106. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  107. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  108. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  109. data/lib/rubocop/cop/style/yoda_condition.rb +20 -0
  110. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  111. data/lib/rubocop/cop/util.rb +2 -2
  112. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  113. data/lib/rubocop/options.rb +126 -112
  114. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  115. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  116. data/lib/rubocop/version.rb +1 -1
  117. data/lib/rubocop.rb +5 -0
  118. metadata +10 -5
@@ -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
@@ -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
@@ -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
@@ -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
@@ -21,8 +21,17 @@ module RuboCop
21
21
  #
22
22
  # NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
23
23
  #
24
- # NOTE: From Ruby 3.0, this cop allows explicit freezing of interpolated
25
- # string literals when `# frozen-string-literal: true` is used.
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.
26
35
  #
27
36
  # @example EnforcedStyle: literals (default)
28
37
  # # bad
@@ -71,10 +80,6 @@ module RuboCop
71
80
  # # shareable_constant_value: literal
72
81
  # CONST = [1, 2, 3]
73
82
  #
74
- # NOTE: This special directive helps to create constants
75
- # that hold only immutable objects, or Ractor-shareable
76
- # constants. - ruby docs
77
- #
78
83
  class MutableConstant < Base
79
84
  # Handles magic comment shareable_constant_value with O(n ^ 2) complexity
80
85
  # n - number of lines in the source
@@ -93,7 +98,7 @@ module RuboCop
93
98
  end
94
99
 
95
100
  # Identifies the most recent magic comment with valid shareable constant values
96
- # thats in scope for this node
101
+ # that's in scope for this node
97
102
  def magic_comment_in_scope(node)
98
103
  processed_source_till_node(node).reverse_each.find do |line|
99
104
  MagicComment.parse(line).valid_shareable_constant_value?
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for numbered parameters.
7
+ #
8
+ # It can either restrict the use of numbered parameters to
9
+ # single-lined blocks, or disallow completely numbered parameters.
10
+ #
11
+ # @example EnforcedStyle: allow_single_line (default)
12
+ # # bad
13
+ # collection.each do
14
+ # puts _1
15
+ # end
16
+ #
17
+ # # good
18
+ # collection.each { puts _1 }
19
+ #
20
+ # @example EnforcedStyle: disallow
21
+ # # bad
22
+ # collection.each { puts _1 }
23
+ #
24
+ # # good
25
+ # collection.each { |item| puts item }
26
+ #
27
+ class NumberedParameters < Base
28
+ include ConfigurableEnforcedStyle
29
+ extend TargetRubyVersion
30
+
31
+ MSG_DISALLOW = 'Avoid using numbered parameters.'
32
+ MSG_MULTI_LINE = 'Avoid using numbered parameters for multi-line blocks.'
33
+
34
+ minimum_target_ruby_version 2.7
35
+
36
+ def on_numblock(node)
37
+ if style == :disallow
38
+ add_offense(node, message: MSG_DISALLOW)
39
+ elsif node.multiline?
40
+ add_offense(node, message: MSG_MULTI_LINE)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop detects use of an excessive amount of numbered parameters in a
7
+ # single block. Having too many numbered parameters can make code too
8
+ # cryptic and hard to read.
9
+ #
10
+ # The cop defaults to registering an offense if there is more than 1 numbered
11
+ # parameter but this maximum can be configured by setting `Max`.
12
+ #
13
+ # @example Max: 1 (default)
14
+ # # bad
15
+ # foo { _1.call(_2, _3, _4) }
16
+ #
17
+ # # good
18
+ # foo { do_something(_1) }
19
+ class NumberedParametersLimit < Base
20
+ extend TargetRubyVersion
21
+ extend ExcludeLimit
22
+
23
+ DEFAULT_MAX_VALUE = 1
24
+
25
+ minimum_target_ruby_version 2.7
26
+ exclude_limit 'Max'
27
+
28
+ MSG = 'Avoid using more than %<max>i numbered %<parameter>s; %<count>i detected.'
29
+
30
+ def on_numblock(node)
31
+ _send_node, param_count, * = *node
32
+ return if param_count <= max_count
33
+
34
+ parameter = max_count > 1 ? 'parameters' : 'parameter'
35
+ message = format(MSG, max: max_count, parameter: parameter, count: param_count)
36
+ add_offense(node, message: message) { self.max = param_count }
37
+ end
38
+
39
+ private
40
+
41
+ def max_count
42
+ max = cop_config.fetch('Max', DEFAULT_MAX_VALUE)
43
+
44
+ # Ruby does not allow more than 9 numbered parameters
45
+ [max, 9].min
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -58,18 +58,17 @@ module RuboCop
58
58
 
59
59
  case int
60
60
  when /^\d+$/
61
- return unless (self.min_digits = int.size + 1)
62
-
63
- register_offense(node)
61
+ register_offense(node) { self.min_digits = int.size + 1 }
64
62
  when /\d{4}/, short_group_regex
65
- return unless (self.config_to_allow_offenses = { 'Enabled' => false })
66
-
67
- register_offense(node)
63
+ register_offense(node) { self.config_to_allow_offenses = { 'Enabled' => false } }
68
64
  end
69
65
  end
70
66
 
71
- def register_offense(node)
72
- add_offense(node) { |corrector| corrector.replace(node, format_number(node)) }
67
+ def register_offense(node, &_block)
68
+ add_offense(node) do |corrector|
69
+ yield
70
+ corrector.replace(node, format_number(node))
71
+ end
73
72
  end
74
73
 
75
74
  def short_group_regex
@@ -16,6 +16,11 @@ module RuboCop
16
16
  # populated with objects which can be compared with integers, but are
17
17
  # not themselves `Integer` polymorphic.
18
18
  #
19
+ # @safety
20
+ # This cop is unsafe because it cannot be guaranteed that the receiver
21
+ # defines the predicates or can be compared to a number, which may lead
22
+ # to a false positive for non-standard classes.
23
+ #
19
24
  # @example EnforcedStyle: predicate (default)
20
25
  # # bad
21
26
  #
@@ -6,6 +6,10 @@ module RuboCop
6
6
  # This cop checks for optional arguments to methods
7
7
  # that do not come at the end of the argument list.
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe because changing a method signature will
11
+ # implicitly change behaviour.
12
+ #
9
13
  # @example
10
14
  # # bad
11
15
  # def foo(a = 1, b, c)
@@ -7,6 +7,10 @@ module RuboCop
7
7
  # boolean arguments when defining methods. `respond_to_missing?` method is allowed by default.
8
8
  # These are customizable with `AllowedMethods` option.
9
9
  #
10
+ # @safety
11
+ # This cop is unsafe because changing a method signature will
12
+ # implicitly change behaviour.
13
+ #
10
14
  # @example
11
15
  # # bad
12
16
  # def some_method(bar = false)
@@ -33,8 +37,8 @@ module RuboCop
33
37
  class OptionalBooleanParameter < Base
34
38
  include AllowedMethods
35
39
 
36
- MSG = 'Use keyword arguments when defining method with boolean argument.'
37
- BOOLEAN_TYPES = %i[true false].freeze
40
+ MSG = 'Prefer keyword arguments for arguments with a boolean default value; ' \
41
+ 'use `%<replacement>s` instead of `%<original>s`.'
38
42
 
39
43
  def on_def(node)
40
44
  return if allowed_method?(node.method_name)
@@ -42,11 +46,17 @@ module RuboCop
42
46
  node.arguments.each do |arg|
43
47
  next unless arg.optarg_type?
44
48
 
45
- _name, value = *arg
46
- add_offense(arg) if BOOLEAN_TYPES.include?(value.type)
49
+ add_offense(arg, message: format_message(arg)) if arg.default_value.boolean_type?
47
50
  end
48
51
  end
49
52
  alias on_defs on_def
53
+
54
+ private
55
+
56
+ def format_message(argument)
57
+ source = argument.source
58
+ format(MSG, original: source, replacement: source.sub(/\s+=/, ':'))
59
+ end
50
60
  end
51
61
  end
52
62
  end
@@ -3,10 +3,15 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # This cop (by default) checks for uses of methods Hash#has_key? and
7
- # Hash#has_value? where it enforces Hash#key? and Hash#value?
8
- # It is configurable to enforce the inverse, using `verbose` method
9
- # names also.
6
+ # This cop checks for uses of methods `Hash#has_key?` and
7
+ # `Hash#has_value?`, and suggests using `Hash#key?` and `Hash#value?` instead.
8
+ #
9
+ # It is configurable to enforce the verbose method names, by using the
10
+ # `EnforcedStyle: verbose` configuration.
11
+ #
12
+ # @safety
13
+ # This cop is unsafe because it cannot be guaranteed that the receiver
14
+ # is a `Hash` or responds to the replacement methods.
10
15
  #
11
16
  # @example EnforcedStyle: short (default)
12
17
  # # bad
@@ -5,22 +5,29 @@ module RuboCop
5
5
  module Style
6
6
  # This cop checks for a redundant argument passed to certain methods.
7
7
  #
8
- # Limitations:
9
- #
10
- # 1. This cop matches for method names only and hence cannot tell apart
11
- # methods with same name in different classes.
12
- # 2. This cop is limited to methods with single parameter.
13
- # 3. This cop is unsafe if certain special global variables (e.g. `$;`, `$/`) are set.
14
- # That depends on the nature of the target methods, of course.
8
+ # NOTE: This cop is limited to methods with single parameter.
15
9
  #
16
10
  # Method names and their redundant arguments can be configured like this:
17
11
  #
12
+ # [source,yaml]
13
+ # ----
18
14
  # Methods:
19
15
  # join: ''
20
16
  # split: ' '
21
17
  # chomp: "\n"
22
18
  # chomp!: "\n"
23
19
  # foo: 2
20
+ # ----
21
+ #
22
+ # @safety
23
+ # This cop is unsafe because of the following limitations:
24
+ #
25
+ # 1. This cop matches by method names only and hence cannot tell apart
26
+ # methods with same name in different classes.
27
+ # 2. This cop may be unsafe if certain special global variables (e.g. `$;`, `$/`) are set.
28
+ # That depends on the nature of the target methods, of course. For example, the default
29
+ # argument to join is `$OUTPUT_FIELD_SEPARATOR` (or `$,`) rather than `''`, and if that
30
+ # global is changed, `''` is no longer a redundant argument.
24
31
  #
25
32
  # @example
26
33
  # # bad
@@ -9,6 +9,10 @@ module RuboCop
9
9
  # In such cases `fetch(key, value)` method is faster
10
10
  # than `fetch(key) { value }`.
11
11
  #
12
+ # @safety
13
+ # This cop is unsafe because it cannot be guaranteed that the receiver
14
+ # does not have a different implementation of `fetch`.
15
+ #
12
16
  # @example SafeForConstants: false (default)
13
17
  # # bad
14
18
  # hash.fetch(:key) { 5 }
@@ -25,6 +25,7 @@ module RuboCop
25
25
  # require_relative '../foo.so'
26
26
  #
27
27
  class RedundantFileExtensionInRequire < Base
28
+ include RangeHelp
28
29
  extend AutoCorrector
29
30
 
30
31
  MSG = 'Redundant `.rb` file extension detected.'
@@ -39,13 +40,21 @@ module RuboCop
39
40
  require_call?(node) do |name_node|
40
41
  return unless name_node.value.end_with?('.rb')
41
42
 
42
- add_offense(name_node) do |corrector|
43
- correction = name_node.value.delete_suffix('.rb')
43
+ extension_range = extension_range(name_node)
44
44
 
45
- corrector.replace(name_node, "'#{correction}'")
45
+ add_offense(extension_range) do |corrector|
46
+ corrector.remove(extension_range)
46
47
  end
47
48
  end
48
49
  end
50
+
51
+ private
52
+
53
+ def extension_range(name_node)
54
+ end_of_path_string = name_node.source_range.end_pos
55
+
56
+ range_between(end_of_path_string - 4, end_of_path_string - 1)
57
+ end
49
58
  end
50
59
  end
51
60
  end
@@ -59,7 +59,6 @@ module RuboCop
59
59
  (begin (send {float int} {:+ :- :* :** :/ :% :<<} _))
60
60
  (begin (send !{(str _) array} {:+ :- :* :** :/ :%} {float int}))
61
61
  (begin (send _ {:== :=== :!= :<= :>= :< :>} _))
62
- (send (const {nil? cbase} :ENV) :[] _)
63
62
  (send _ {:count :length :size} ...)
64
63
  (block (send _ {:count :length :size} ...) ...)
65
64
  }
@@ -100,6 +100,10 @@ module RuboCop
100
100
  add_lhs_to_local_variables_scopes(rhs, lhs)
101
101
  end
102
102
 
103
+ def on_in_pattern(node)
104
+ add_match_var_scopes(node)
105
+ end
106
+
103
107
  def on_send(node)
104
108
  return unless node.self_receiver? && regular_method_call?(node)
105
109
  return if node.parent&.mlhs_type?
@@ -185,6 +189,12 @@ module RuboCop
185
189
  add_lhs_to_local_variables_scopes(rhs, child.to_a.first)
186
190
  end
187
191
  end
192
+
193
+ def add_match_var_scopes(in_pattern_node)
194
+ in_pattern_node.each_descendant(:match_var) do |match_var_node|
195
+ @local_variables_scopes[in_pattern_node] << match_var_node.children.first
196
+ end
197
+ end
188
198
  end
189
199
  end
190
200
  end
@@ -6,9 +6,10 @@ module RuboCop
6
6
  # This cop checks for places where redundant assignments are made for in place
7
7
  # modification methods.
8
8
  #
9
- # This cop is marked as unsafe, because it can produce false positives for
10
- # user defined methods having one of the expected names, but not modifying
11
- # its receiver in place.
9
+ # @safety
10
+ # This cop is unsafe, because it can produce false positives for
11
+ # user defined methods having one of the expected names, but not modifying
12
+ # its receiver in place.
12
13
  #
13
14
  # @example
14
15
  # # bad
@@ -12,6 +12,33 @@ module RuboCop
12
12
  # `Enumerable#max_by` can replace `Enumerable#sort_by` calls
13
13
  # after which only the first or last element is used.
14
14
  #
15
+ # @safety
16
+ # This cop is unsafe, because `sort...last` and `max` may not return the
17
+ # same element in all cases.
18
+ #
19
+ # In an enumerable where there are multiple elements where `a <=> b == 0`,
20
+ # or where the transformation done by the `sort_by` block has the
21
+ # same result, `sort.last` and `max` (or `sort_by.last` and `max_by`)
22
+ # will return different elements. `sort.last` will return the last
23
+ # element but `max` will return the first element.
24
+ #
25
+ # For example:
26
+ #
27
+ # [source,ruby]
28
+ # ----
29
+ # class MyString < String; end
30
+ # strings = [MyString.new('test'), 'test']
31
+ # strings.sort.last.class #=> String
32
+ # strings.max.class #=> MyString
33
+ # ----
34
+ #
35
+ # [source,ruby]
36
+ # ----
37
+ # words = %w(dog horse mouse)
38
+ # words.sort_by { |word| word.length }.last #=> 'mouse'
39
+ # words.max_by { |word| word.length } #=> 'horse'
40
+ # ----
41
+ #
15
42
  # @example
16
43
  # # bad
17
44
  # [2, 1, 3].sort.first
@@ -75,48 +102,39 @@ module RuboCop
75
102
  MATCHER
76
103
 
77
104
  def on_send(node)
78
- if (sort_node, sorter, accessor = redundant_sort?(node.parent))
79
- return if use_size_method_in_block?(sort_node)
80
-
81
- ancestor = node.parent
82
- elsif (sort_node, sorter, accessor = redundant_sort?(node.parent&.parent))
83
- return if use_size_method_in_block?(sort_node)
84
-
85
- ancestor = node.parent.parent
86
- else
87
- return
88
- end
105
+ ancestor, sort_node, sorter, accessor =
106
+ find_redundant_sort(node.parent, node.parent&.parent)
107
+ return unless ancestor
89
108
 
90
109
  register_offense(ancestor, sort_node, sorter, accessor)
91
110
  end
92
111
 
93
112
  private
94
113
 
95
- def use_size_method_in_block?(sort_node)
96
- return true if sort_node.send_type? && sort_node.block_node&.body&.method?(:size)
97
- return false unless sort_node.block_argument?
114
+ def find_redundant_sort(*nodes)
115
+ nodes.each do |node|
116
+ if (sort_node, sorter, accessor = redundant_sort?(node))
117
+ return [node, sort_node, sorter, accessor]
118
+ end
119
+ end
98
120
 
99
- sort_node.last_argument.children.first.value == :size
121
+ nil
100
122
  end
101
123
 
102
- def register_offense(ancestor, sort_node, sorter, accessor)
103
- message = message(ancestor, sorter, accessor)
124
+ def register_offense(node, sort_node, sorter, accessor)
125
+ message = message(node, sorter, accessor)
104
126
 
105
- add_offense(offense_range(sort_node, ancestor), message: message) do |corrector|
106
- autocorrect(corrector, ancestor, sort_node, sorter, accessor)
107
- end
108
- end
109
-
110
- def autocorrect(corrector, node, sort_node, sorter, accessor)
111
- # Remove accessor, e.g. `first` or `[-1]`.
112
- corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
127
+ add_offense(offense_range(sort_node, node), message: message) do |corrector|
128
+ # Remove accessor, e.g. `first` or `[-1]`.
129
+ corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
113
130
 
114
- # Replace "sort" or "sort_by" with the appropriate min/max method.
115
- corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
131
+ # Replace "sort" or "sort_by" with the appropriate min/max method.
132
+ corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
133
+ end
116
134
  end
117
135
 
118
- def offense_range(sort_node, ancestor)
119
- range_between(sort_node.loc.selector.begin_pos, ancestor.loc.expression.end_pos)
136
+ def offense_range(sort_node, node)
137
+ range_between(sort_node.loc.selector.begin_pos, node.loc.expression.end_pos)
120
138
  end
121
139
 
122
140
  def message(node, sorter, accessor)