rubocop 1.75.0 → 1.76.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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -13
  3. data/config/default.yml +80 -24
  4. data/config/obsoletion.yml +6 -3
  5. data/lib/rubocop/config_validator.rb +6 -6
  6. data/lib/rubocop/cop/autocorrect_logic.rb +18 -10
  7. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  8. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +50 -6
  9. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  10. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  11. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +2 -0
  12. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +6 -1
  13. data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
  14. data/lib/rubocop/cop/layout/class_structure.rb +35 -0
  15. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  16. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  17. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -2
  18. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -2
  19. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  20. data/lib/rubocop/cop/layout/hash_alignment.rb +2 -2
  21. data/lib/rubocop/cop/layout/leading_comment_space.rb +13 -1
  22. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +1 -1
  23. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -4
  24. data/lib/rubocop/cop/layout/space_after_semicolon.rb +10 -0
  25. data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -32
  26. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +5 -1
  27. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
  28. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
  29. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  30. data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -5
  31. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  32. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  33. data/lib/rubocop/cop/lint/duplicate_methods.rb +86 -5
  34. data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
  35. data/lib/rubocop/cop/lint/float_comparison.rb +27 -0
  36. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  37. data/lib/rubocop/cop/lint/literal_as_condition.rb +31 -25
  38. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
  39. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  40. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
  41. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  42. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +7 -4
  43. data/lib/rubocop/cop/lint/return_in_void_context.rb +7 -2
  44. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
  45. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  46. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  47. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  48. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -0
  49. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +87 -0
  50. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  51. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  52. data/lib/rubocop/cop/lint/void.rb +2 -2
  53. data/lib/rubocop/cop/message_annotator.rb +7 -3
  54. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  55. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  56. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
  57. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  58. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  59. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +0 -1
  60. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
  61. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
  62. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  63. data/lib/rubocop/cop/mixin/trailing_comma.rb +9 -5
  64. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  65. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  66. data/lib/rubocop/cop/naming/predicate_method.rb +216 -0
  67. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +2 -2
  68. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
  69. data/lib/rubocop/cop/style/arguments_forwarding.rb +8 -5
  70. data/lib/rubocop/cop/style/class_and_module_children.rb +19 -3
  71. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  72. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  73. data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
  74. data/lib/rubocop/cop/style/comparable_between.rb +5 -2
  75. data/lib/rubocop/cop/style/conditional_assignment.rb +16 -4
  76. data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
  77. data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
  78. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  79. data/lib/rubocop/cop/style/empty_literal.rb +4 -0
  80. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  81. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  82. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  83. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  84. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  85. data/lib/rubocop/cop/style/hash_fetch_chain.rb +0 -1
  86. data/lib/rubocop/cop/style/hash_syntax.rb +3 -0
  87. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  88. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  89. data/lib/rubocop/cop/style/identical_conditional_branches.rb +3 -3
  90. data/lib/rubocop/cop/style/if_unless_modifier.rb +22 -4
  91. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
  92. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  93. data/lib/rubocop/cop/style/it_block_parameter.rb +33 -14
  94. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  95. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  96. data/lib/rubocop/cop/style/map_into_array.rb +3 -1
  97. data/lib/rubocop/cop/style/map_to_hash.rb +11 -0
  98. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -2
  99. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  100. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  101. data/lib/rubocop/cop/style/raise_args.rb +8 -8
  102. data/lib/rubocop/cop/style/redundant_array_flatten.rb +48 -0
  103. data/lib/rubocop/cop/style/redundant_condition.rb +13 -1
  104. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +1 -1
  105. data/lib/rubocop/cop/style/redundant_format.rb +6 -1
  106. data/lib/rubocop/cop/style/redundant_line_continuation.rb +0 -3
  107. data/lib/rubocop/cop/style/redundant_parentheses.rb +31 -3
  108. data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
  109. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  110. data/lib/rubocop/cop/style/safe_navigation.rb +28 -10
  111. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
  112. data/lib/rubocop/cop/style/string_concatenation.rb +1 -2
  113. data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
  114. data/lib/rubocop/cop/style/super_arguments.rb +1 -2
  115. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +7 -1
  116. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
  117. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
  118. data/lib/rubocop/cop/team.rb +1 -1
  119. data/lib/rubocop/cop/util.rb +1 -1
  120. data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
  121. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  122. data/lib/rubocop/cops_documentation_generator.rb +6 -2
  123. data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
  124. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  125. data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
  126. data/lib/rubocop/magic_comment.rb +8 -0
  127. data/lib/rubocop/rspec/cop_helper.rb +2 -2
  128. data/lib/rubocop/rspec/shared_contexts.rb +1 -2
  129. data/lib/rubocop/server/cache.rb +13 -10
  130. data/lib/rubocop/target_finder.rb +6 -2
  131. data/lib/rubocop/version.rb +1 -1
  132. data/lib/rubocop.rb +6 -1
  133. metadata +12 -7
@@ -57,13 +57,9 @@ module RuboCop
57
57
  def on_if(node)
58
58
  cond = condition(node)
59
59
 
60
- if node.unless?
61
- correct_if_node(node, cond, true) if cond.falsey_literal?
62
- correct_if_node(node, cond, false) if cond.truthy_literal?
63
- else
64
- correct_if_node(node, cond, true) if cond.truthy_literal?
65
- correct_if_node(node, cond, false) if cond.falsey_literal?
66
- end
60
+ return unless cond.falsey_literal? || cond.truthy_literal?
61
+
62
+ correct_if_node(node, cond)
67
63
  end
68
64
 
69
65
  def on_while(node)
@@ -232,27 +228,37 @@ module RuboCop
232
228
  )
233
229
  end
234
230
 
235
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
236
- def correct_if_node(node, cond, result)
237
- if result
238
- add_offense(cond) do |corrector|
239
- corrector.replace(node, node.if_branch.source)
240
- end
241
- elsif node.elsif_conditional?
242
- add_offense(cond) do |corrector|
243
- corrector.replace(node, "#{node.else_branch.source.sub('elsif', 'if')}\nend")
244
- end
245
- elsif node.else? || node.ternary?
246
- add_offense(cond) do |corrector|
247
- corrector.replace(node, node.else_branch.source)
248
- end
231
+ def condition_evaluation(node, cond)
232
+ if node.unless?
233
+ cond.falsey_literal?
249
234
  else
250
- add_offense(cond) do |corrector|
251
- corrector.remove(node)
252
- end
235
+ cond.truthy_literal?
236
+ end
237
+ end
238
+
239
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
240
+ def correct_if_node(node, cond)
241
+ result = condition_evaluation(node, cond)
242
+
243
+ new_node = if node.elsif? && result
244
+ "else\n #{range_with_comments(node.if_branch).source}"
245
+ elsif node.elsif? && !result
246
+ "else\n #{node.else_branch.source}"
247
+ elsif node.if_branch && result
248
+ node.if_branch.source
249
+ elsif node.elsif_conditional?
250
+ "#{node.else_branch.source.sub('elsif', 'if')}\nend"
251
+ elsif node.else? || node.ternary?
252
+ node.else_branch.source
253
+ else
254
+ '' # Equivalent to removing the node
255
+ end
256
+
257
+ add_offense(cond) do |corrector|
258
+ corrector.replace(node, new_node)
253
259
  end
254
260
  end
255
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
261
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
256
262
  end
257
263
  end
258
264
  end
@@ -52,7 +52,7 @@ module RuboCop
52
52
  each_missing_enable do |cop, line_range|
53
53
  next if acceptable_range?(cop, line_range)
54
54
 
55
- range = source_range(processed_source.buffer, line_range.min, (0..0))
55
+ range = source_range(processed_source.buffer, line_range.min, 0..0)
56
56
  comment = processed_source.comment_at_line(line_range.begin)
57
57
 
58
58
  add_offense(range, message: message(cop, comment))
@@ -98,7 +98,7 @@ module RuboCop
98
98
  subject, = *node # rubocop:disable InternalAffairs/NodeDestructuring
99
99
  return if node.defs_type? && allowed_subject_type?(subject)
100
100
 
101
- def_ancestor = node.each_ancestor(:def, :defs).first
101
+ def_ancestor = node.each_ancestor(:any_def).first
102
102
  return unless def_ancestor
103
103
 
104
104
  within_scoping_def =
@@ -46,7 +46,7 @@ module RuboCop
46
46
  def on_return(return_node)
47
47
  return if return_value?(return_node)
48
48
 
49
- return_node.each_ancestor(:any_block, :def, :defs) do |node|
49
+ return_node.each_ancestor(:any_block, :any_def) do |node|
50
50
  break if scoped_node?(node)
51
51
 
52
52
  # if a proc is passed to `Module#define_method` or
@@ -66,7 +66,7 @@ module RuboCop
66
66
  private
67
67
 
68
68
  def scoped_node?(node)
69
- node.type?(:def, :defs) || node.lambda?
69
+ node.any_def_type? || node.lambda?
70
70
  end
71
71
 
72
72
  def return_value?(return_node)
@@ -30,7 +30,7 @@ module RuboCop
30
30
  return unless node.lhs&.casgn_type?
31
31
 
32
32
  add_offense(node.loc.operator) do |corrector|
33
- next if node.each_ancestor(:def, :defs).any?
33
+ next if node.each_ancestor(:any_def).any?
34
34
 
35
35
  corrector.replace(node.loc.operator, '=')
36
36
  end
@@ -27,7 +27,8 @@ module RuboCop
27
27
  # In all cases, chaining one same `to_*` conversion methods listed above is redundant.
28
28
  #
29
29
  # The cop can also register an offense for chaining conversion methods on methods that are
30
- # expected to return a specific type regardless of receiver (eg. `foo.inspect.to_s`).
30
+ # expected to return a specific type regardless of receiver (eg. `foo.inspect.to_s` and
31
+ # `foo.to_json.to_s`).
31
32
  #
32
33
  # @example
33
34
  # # bad
@@ -69,10 +70,12 @@ module RuboCop
69
70
  # foo.to_s
70
71
  #
71
72
  # # bad - chaining a conversion to a method that is expected to return the same type
72
- # inspect.to_s
73
+ # foo.inspect.to_s
74
+ # foo.to_json.to_s
73
75
  #
74
76
  # # good
75
- # inspect
77
+ # foo.inspect
78
+ # foo.to_json
76
79
  #
77
80
  class RedundantTypeConversion < Base
78
81
  extend AutoCorrector
@@ -108,7 +111,7 @@ module RuboCop
108
111
 
109
112
  # Methods that already are expected to return a given type, which makes a further
110
113
  # conversion redundant.
111
- TYPED_METHODS = { to_s: %i[inspect] }.freeze
114
+ TYPED_METHODS = { to_s: %i[inspect to_json] }.freeze
112
115
 
113
116
  CONVERSION_METHODS = Set[*LITERAL_NODE_TYPES.keys].freeze
114
117
  RESTRICT_ON_SEND = CONVERSION_METHODS + [:to_d]
@@ -32,12 +32,17 @@ module RuboCop
32
32
  class ReturnInVoidContext < Base
33
33
  MSG = 'Do not return a value in `%<method>s`.'
34
34
 
35
+ # Returning out of these methods only exits the block itself.
36
+ SCOPE_CHANGING_METHODS = %i[lambda define_method define_singleton_method].freeze
37
+
35
38
  def on_return(return_node)
36
39
  return unless return_node.descendants.any?
37
40
 
38
- def_node = return_node.each_ancestor(:def).first
41
+ def_node = return_node.each_ancestor(:any_def).first
39
42
  return unless def_node&.void_context?
40
- return if return_node.each_ancestor(:any_block).any?(&:lambda?)
43
+ return if return_node.each_ancestor(:any_block).any? do |block_node|
44
+ SCOPE_CHANGING_METHODS.include?(block_node.method_name)
45
+ end
41
46
 
42
47
  add_offense(
43
48
  return_node.loc.keyword,
@@ -8,6 +8,11 @@ module RuboCop
8
8
  # given by `ruby -cw` prior to Ruby 2.6:
9
9
  # "shadowing outer local variable - foo".
10
10
  #
11
+ # The cop is now disabled by default to match the upstream Ruby behavior.
12
+ # It's useful, however, if you'd like to avoid shadowing variables from outer
13
+ # scopes, which some people consider an anti-pattern that makes it harder
14
+ # to keep track of what's going on in a program.
15
+ #
11
16
  # NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
12
17
  # because `Ractor` should not access outer variables.
13
18
  # eg. following style is encouraged:
@@ -116,7 +116,7 @@ module RuboCop
116
116
  private
117
117
 
118
118
  def comment_between_rescue_and_end?(node)
119
- ancestor = node.each_ancestor(:kwbegin, :def, :defs, :any_block).first
119
+ ancestor = node.each_ancestor(:kwbegin, :any_def, :any_block).first
120
120
  return false unless ancestor
121
121
 
122
122
  end_line = ancestor.loc.end&.line || ancestor.loc.last_line
@@ -45,7 +45,7 @@ module RuboCop
45
45
  PATTERN
46
46
 
47
47
  def on_send(node)
48
- def_node = node.each_ancestor(:def, :defs).first
48
+ def_node = node.each_ancestor(:any_def).first
49
49
  return unless def_node
50
50
 
51
51
  enum_conversion_call?(node) do |method_node, arguments|
@@ -40,7 +40,7 @@ module RuboCop
40
40
  # top-level return node's ancestors should not be of block, def, or
41
41
  # defs type.
42
42
  def top_level_return?(return_node)
43
- return_node.each_ancestor(:block, :def, :defs).none?
43
+ return_node.each_ancestor(:block, :any_def).none?
44
44
  end
45
45
  end
46
46
  end
@@ -104,6 +104,8 @@ module RuboCop
104
104
  end
105
105
 
106
106
  def chained_assignment?(node)
107
+ return true if node.lvasgn_type? && node.expression&.send_type?
108
+
107
109
  node.respond_to?(:expression) && node.expression&.lvasgn_type?
108
110
  end
109
111
 
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for usage of method `fetch` or `Array.new` with default value argument
7
+ # and block. In such cases, block will always be used as default value.
8
+ #
9
+ # This cop emulates Ruby warning "block supersedes default value argument" which
10
+ # applies to `Array.new`, `Array#fetch`, `Hash#fetch`, `ENV.fetch` and
11
+ # `Thread#fetch`.
12
+ #
13
+ # @safety
14
+ # This cop is unsafe because the receiver could have nonstandard implementation
15
+ # of `fetch`, or be a class other than the one listed above.
16
+ #
17
+ # It is also unsafe because default value argument could have side effects:
18
+ #
19
+ # [source,ruby]
20
+ # ----
21
+ # def x(a) = puts "side effect"
22
+ # Array.new(5, x(1)) { 2 }
23
+ # ----
24
+ #
25
+ # so removing it would change behavior.
26
+ #
27
+ # @example
28
+ # # bad
29
+ # x.fetch(key, default_value) { block_value }
30
+ # Array.new(size, default_value) { block_value }
31
+ #
32
+ # # good
33
+ # x.fetch(key) { block_value }
34
+ # Array.new(size) { block_value }
35
+ #
36
+ # # also good - in case default value argument is desired instead
37
+ # x.fetch(key, default_value)
38
+ # Array.new(size, default_value)
39
+ #
40
+ # # good - keyword arguments aren't registered as offenses
41
+ # x.fetch(key, keyword: :arg) { block_value }
42
+ #
43
+ # @example AllowedReceivers: ['Rails.cache']
44
+ # # good
45
+ # Rails.cache.fetch(name, options) { block }
46
+ #
47
+ class UselessDefaultValueArgument < Base
48
+ include AllowedReceivers
49
+ extend AutoCorrector
50
+
51
+ MSG = 'Block supersedes default value argument.'
52
+
53
+ RESTRICT_ON_SEND = %i[fetch new].freeze
54
+
55
+ # @!method default_value_argument_and_block(node)
56
+ def_node_matcher :default_value_argument_and_block, <<~PATTERN
57
+ (any_block
58
+ {
59
+ (call _receiver :fetch $_key $_default_value)
60
+ (send (const _ :Array) :new $_size $_default_value)
61
+ }
62
+ _args
63
+ _block_body)
64
+ PATTERN
65
+
66
+ def on_send(node)
67
+ unless (prev_arg_node, default_value_node = default_value_argument_and_block(node.parent))
68
+ return
69
+ end
70
+ return if allowed_receiver?(node.receiver)
71
+ return if hash_without_braces?(default_value_node)
72
+
73
+ add_offense(default_value_node) do |corrector|
74
+ corrector.remove(prev_arg_node.source_range.end.join(default_value_node.source_range))
75
+ end
76
+ end
77
+ alias on_csend on_send
78
+
79
+ private
80
+
81
+ def hash_without_braces?(node)
82
+ node.hash_type? && !node.braces?
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for useless OR (`||` and `or`) expressions.
7
+ #
8
+ # Some methods always return a truthy value, even when called
9
+ # on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
10
+ # appended after these methods will never evaluate.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # x.to_a || fallback
16
+ # x.to_c || fallback
17
+ # x.to_d || fallback
18
+ # x.to_i || fallback
19
+ # x.to_f || fallback
20
+ # x.to_h || fallback
21
+ # x.to_r || fallback
22
+ # x.to_s || fallback
23
+ # x.to_sym || fallback
24
+ # x.intern || fallback
25
+ # x.inspect || fallback
26
+ # x.hash || fallback
27
+ # x.object_id || fallback
28
+ # x.__id__ || fallback
29
+ #
30
+ # x.to_s or fallback
31
+ #
32
+ # # good - if fallback is same as return value of method called on nil
33
+ # x.to_a # nil.to_a returns []
34
+ # x.to_c # nil.to_c returns (0+0i)
35
+ # x.to_d # nil.to_d returns 0.0
36
+ # x.to_i # nil.to_i returns 0
37
+ # x.to_f # nil.to_f returns 0.0
38
+ # x.to_h # nil.to_h returns {}
39
+ # x.to_r # nil.to_r returns (0/1)
40
+ # x.to_s # nil.to_s returns ''
41
+ # x.to_sym # nil.to_sym raises an error
42
+ # x.intern # nil.intern raises an error
43
+ # x.inspect # nil.inspect returns "nil"
44
+ # x.hash # nil.hash returns an Integer
45
+ # x.object_id # nil.object_id returns an Integer
46
+ # x.__id__ # nil.object_id returns an Integer
47
+ #
48
+ # # good - if the intention is not to call the method on nil
49
+ # x&.to_a || fallback
50
+ # x&.to_c || fallback
51
+ # x&.to_d || fallback
52
+ # x&.to_i || fallback
53
+ # x&.to_f || fallback
54
+ # x&.to_h || fallback
55
+ # x&.to_r || fallback
56
+ # x&.to_s || fallback
57
+ # x&.to_sym || fallback
58
+ # x&.intern || fallback
59
+ # x&.inspect || fallback
60
+ # x&.hash || fallback
61
+ # x&.object_id || fallback
62
+ # x&.__id__ || fallback
63
+ #
64
+ # x&.to_s or fallback
65
+ #
66
+ class UselessOr < Base
67
+ MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
68
+
69
+ TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
70
+ :to_s, :to_sym, :intern, :inspect, :hash, :object_id,
71
+ :__id__].freeze
72
+
73
+ # @!method truthy_return_value_method?(node)
74
+ def_node_matcher :truthy_return_value_method?, <<~PATTERN
75
+ (send _ %TRUTHY_RETURN_VALUE_METHODS)
76
+ PATTERN
77
+
78
+ def on_or(node)
79
+ if truthy_return_value_method?(node.lhs)
80
+ report_offense(node, node.lhs)
81
+ elsif truthy_return_value_method?(node.rhs)
82
+ parent = node.parent
83
+ parent = parent.parent if parent&.begin_type?
84
+
85
+ report_offense(parent, node.rhs) if parent&.or_type?
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def report_offense(or_node, truthy_node)
92
+ add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
93
+ message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for useless `rescue`s, which only reraise rescued exceptions.
6
+ # Checks for useless ``rescue``s, which only reraise rescued exceptions.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -128,8 +128,8 @@ module RuboCop
128
128
 
129
129
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
130
130
  def check_void_op(node, &block)
131
- node = node.children.first while node.begin_type?
132
- return unless node.call_type? && OPERATORS.include?(node.method_name)
131
+ node = node.children.first while node&.begin_type?
132
+ return unless node&.call_type? && OPERATORS.include?(node.method_name)
133
133
  if !UNARY_OPERATORS.include?(node.method_name) && node.loc.dot && node.arguments.none?
134
134
  return
135
135
  end
@@ -32,7 +32,7 @@ module RuboCop
32
32
  # @param [String] cop_name for specific cop name
33
33
  # @param [Hash] cop_config configs for specific cop, from config#for_cop
34
34
  # @option cop_config [String] :StyleGuide Extension of base styleguide URL
35
- # @option cop_config [String] :Reference Full reference URL
35
+ # @option cop_config [String] :References Full reference URLs
36
36
  # @option cop_config [String] :Details
37
37
  #
38
38
  # @param [Hash, nil] options optional
@@ -100,8 +100,12 @@ module RuboCop
100
100
  end
101
101
 
102
102
  def reference_urls
103
- urls = Array(cop_config['Reference'])
104
- urls.nil? || urls.empty? ? nil : urls.reject(&:empty?)
103
+ urls = cop_config
104
+ .values_at('References', 'Reference') # Support legacy Reference key
105
+ .flat_map { Array(_1) }
106
+ .reject(&:empty?)
107
+
108
+ urls unless urls.empty?
105
109
  end
106
110
 
107
111
  def extra_details?
@@ -39,7 +39,7 @@ module RuboCop
39
39
  class AbcSize < Base
40
40
  include MethodComplexity
41
41
 
42
- MSG = 'Assignment Branch Condition size for %<method>s is too high. ' \
42
+ MSG = 'Assignment Branch Condition size for `%<method>s` is too high. ' \
43
43
  '[%<abc_vector>s %<complexity>.4g/%<max>.4g]'
44
44
 
45
45
  private
@@ -48,7 +48,7 @@ module RuboCop
48
48
 
49
49
  args = process_args(node.arguments)
50
50
  return extract_breakable_node_from_elements(node, args, max)
51
- elsif node.type?(:def, :defs)
51
+ elsif node.any_def_type?
52
52
  return extract_breakable_node_from_elements(node, node.arguments, max)
53
53
  elsif node.type?(:array, :hash)
54
54
  return extract_breakable_node_from_elements(node, node.children, max)
@@ -220,7 +220,7 @@ module RuboCop
220
220
 
221
221
  # @api private
222
222
  def already_on_multiple_lines?(node)
223
- return node.first_line != node.last_argument.last_line if node.type?(:def, :defs)
223
+ return node.first_line != node.last_argument.last_line if node.any_def_type?
224
224
 
225
225
  !node.single_line?
226
226
  end
@@ -40,7 +40,7 @@ module RuboCop
40
40
  end
41
41
 
42
42
  def safe_to_split?(node)
43
- node.each_descendant(:if, :case, :kwbegin, :def, :defs).none? &&
43
+ node.each_descendant(:if, :case, :kwbegin, :any_def).none? &&
44
44
  node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
45
45
  node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
46
46
  end
@@ -19,7 +19,7 @@ module RuboCop
19
19
 
20
20
  # @!method non_public_modifier?(node)
21
21
  def_node_matcher :non_public_modifier?, <<~PATTERN
22
- (send nil? {:private :protected :private_class_method} ({def defs} ...))
22
+ (send nil? {:private :protected :private_class_method} (any_def ...))
23
23
  PATTERN
24
24
  end
25
25
  end
@@ -21,7 +21,7 @@ module RuboCop
21
21
 
22
22
  # @!method empty_line_required?(node)
23
23
  def_node_matcher :empty_line_required?,
24
- '{def defs class module (send nil? {:private :protected :public})}'
24
+ '{any_def class module (send nil? {:private :protected :public})}'
25
25
 
26
26
  def check(node, body, adjusted_first_line: nil)
27
27
  return if valid_body_style?(body)
@@ -6,7 +6,6 @@ module RuboCop
6
6
  module FrozenStringLiteral
7
7
  module_function
8
8
 
9
- FROZEN_STRING_LITERAL_REGEXP = /#\s*frozen[-_]?string[-_]?literal:/i.freeze
10
9
  FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
11
10
  FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
12
11
 
@@ -10,7 +10,7 @@ module RuboCop
10
10
  true
11
11
  end
12
12
 
13
- def deltas_for_first_pair(first_pair, _node)
13
+ def deltas_for_first_pair(first_pair)
14
14
  {
15
15
  separator: separator_delta(first_pair),
16
16
  value: value_delta(first_pair)
@@ -81,13 +81,7 @@ module RuboCop
81
81
  class TableAlignment
82
82
  include ValueAlignment
83
83
 
84
- def initialize
85
- self.max_key_width = 0
86
- end
87
-
88
- def deltas_for_first_pair(first_pair, node)
89
- self.max_key_width = node.keys.map { |key| key.source.length }.max
90
-
84
+ def deltas_for_first_pair(first_pair)
91
85
  separator_delta = separator_delta(first_pair, first_pair, 0)
92
86
  {
93
87
  separator: separator_delta,
@@ -97,30 +91,37 @@ module RuboCop
97
91
 
98
92
  private
99
93
 
100
- attr_accessor :max_key_width
101
-
102
94
  def key_delta(first_pair, current_pair)
103
95
  first_pair.key_delta(current_pair)
104
96
  end
105
97
 
106
98
  def hash_rocket_delta(first_pair, current_pair)
107
- first_pair.loc.column + max_key_width + 1 - current_pair.loc.operator.column
99
+ first_pair.loc.column + max_key_width(first_pair.parent) + 1 -
100
+ current_pair.loc.operator.column
108
101
  end
109
102
 
110
103
  def value_delta(first_pair, current_pair)
111
104
  correct_value_column = first_pair.key.loc.column +
112
- current_pair.delimiter(true).length +
113
- max_key_width
105
+ max_key_width(first_pair.parent) +
106
+ max_delimiter_width(first_pair.parent)
114
107
 
115
108
  current_pair.value_omission? ? 0 : correct_value_column - current_pair.value.loc.column
116
109
  end
110
+
111
+ def max_key_width(hash_node)
112
+ hash_node.keys.map { |key| key.source.length }.max
113
+ end
114
+
115
+ def max_delimiter_width(hash_node)
116
+ hash_node.pairs.map { |pair| pair.delimiter(true).length }.max
117
+ end
117
118
  end
118
119
 
119
120
  # Handles calculation of deltas when the enforced style is 'separator'.
120
121
  class SeparatorAlignment
121
122
  include ValueAlignment
122
123
 
123
- def deltas_for_first_pair(*_nodes)
124
+ def deltas_for_first_pair(_first_pair)
124
125
  {}
125
126
  end
126
127
 
@@ -17,6 +17,8 @@ module RuboCop
17
17
 
18
18
  lhs = left_hand_side(node.receiver)
19
19
  rhs = right_hand_side(node)
20
+ return unless rhs
21
+
20
22
  range = offending_range(node, lhs, rhs, style)
21
23
  check(range, node, lhs, rhs)
22
24
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
  gem_canonical_name(string_a) < gem_canonical_name(string_b)
25
25
  end
26
26
 
27
- def consecutive_lines(previous, current)
27
+ def consecutive_lines?(previous, current)
28
28
  first_line = get_source_range(current, treat_comments_as_separators).first_line
29
29
  previous.source_range.last_line == first_line - 1
30
30
  end
@@ -107,7 +107,7 @@ module RuboCop
107
107
  # of the argument is not considered multiline, even if the argument
108
108
  # itself might span multiple lines.
109
109
  def allowed_multiline_argument?(node)
110
- elements(node).one? && !Util.begins_its_line?(node.loc.end)
110
+ elements(node).one? && !Util.begins_its_line?(node_end_location(node))
111
111
  end
112
112
 
113
113
  def elements(node)
@@ -127,18 +127,22 @@ module RuboCop
127
127
 
128
128
  def no_elements_on_same_line?(node)
129
129
  items = elements(node).map(&:source_range)
130
- items << node.loc.end
130
+ items << node_end_location(node)
131
131
  items.each_cons(2).none? { |a, b| on_same_line?(a, b) }
132
132
  end
133
133
 
134
+ def node_end_location(node)
135
+ node.loc.end || node.source_range.end.adjust(begin_pos: -1)
136
+ end
137
+
134
138
  def on_same_line?(range1, range2)
135
139
  range1.last_line == range2.line
136
140
  end
137
141
 
138
142
  def last_item_precedes_newline?(node)
139
- after_last_item =
140
- range_between(node.children.last.source_range.end_pos, node.loc.end.begin_pos)
141
- after_last_item.source =~ /\A,?\s*\n/
143
+ after_last_item = node.children.last.source_range.end.join(node.loc.end.begin)
144
+
145
+ after_last_item.source.start_with?(/,?\s*(#.*)?\n/)
142
146
  end
143
147
 
144
148
  def avoid_comma(kind, comma_begin_pos, extra_info)