rubocop 1.50.2 → 1.53.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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +76 -6
  4. data/lib/rubocop/cli/command/lsp.rb +19 -0
  5. data/lib/rubocop/cli.rb +3 -0
  6. data/lib/rubocop/config.rb +4 -0
  7. data/lib/rubocop/config_loader_resolver.rb +4 -3
  8. data/lib/rubocop/config_obsoletion.rb +2 -2
  9. data/lib/rubocop/cop/base.rb +5 -1
  10. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  11. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  12. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  13. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  14. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  15. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  16. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +5 -5
  17. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  18. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  19. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  20. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  21. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  22. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  23. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  24. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  25. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  26. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  27. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  28. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  29. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  30. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  31. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
  32. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  33. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  34. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  35. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  36. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  37. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  38. data/lib/rubocop/cop/lint/mixed_case_range.rb +109 -0
  39. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  40. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  41. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  42. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  43. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +120 -0
  44. data/lib/rubocop/cop/lint/redundant_require_statement.rb +8 -3
  45. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  46. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  47. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  48. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  49. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  50. data/lib/rubocop/cop/lint/useless_assignment.rb +59 -1
  51. data/lib/rubocop/cop/lint/void.rb +63 -7
  52. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  53. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  54. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  55. data/lib/rubocop/cop/mixin/comments_help.rb +7 -3
  56. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  57. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  58. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  59. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  60. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  61. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +25 -10
  62. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  63. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  64. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  65. data/lib/rubocop/cop/style/attr.rb +11 -1
  66. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  67. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  68. data/lib/rubocop/cop/style/block_delimiters.rb +3 -3
  69. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  70. data/lib/rubocop/cop/style/class_equality_comparison.rb +17 -39
  71. data/lib/rubocop/cop/style/collection_compact.rb +16 -6
  72. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  73. data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
  74. data/lib/rubocop/cop/style/conditional_assignment.rb +5 -3
  75. data/lib/rubocop/cop/style/copyright.rb +5 -2
  76. data/lib/rubocop/cop/style/dir.rb +1 -1
  77. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  78. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  79. data/lib/rubocop/cop/style/documentation.rb +1 -1
  80. data/lib/rubocop/cop/style/eval_with_location.rb +5 -5
  81. data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
  82. data/lib/rubocop/cop/style/file_read.rb +2 -2
  83. data/lib/rubocop/cop/style/guard_clause.rb +2 -0
  84. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  85. data/lib/rubocop/cop/style/hash_except.rb +19 -8
  86. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  87. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  88. data/lib/rubocop/cop/style/identical_conditional_branches.rb +6 -2
  89. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  90. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  91. data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -6
  92. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -4
  93. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  94. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  95. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  96. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  97. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  98. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  99. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
  100. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
  101. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  102. data/lib/rubocop/cop/style/redundant_line_continuation.rb +7 -3
  103. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  104. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +86 -0
  105. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  106. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  107. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +3 -1
  108. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  109. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -0
  110. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  111. data/lib/rubocop/cop/style/require_order.rb +11 -5
  112. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  113. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +81 -0
  114. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  115. data/lib/rubocop/cop/style/semicolon.rb +12 -1
  116. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  117. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  118. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  119. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  120. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  121. data/lib/rubocop/cop/team.rb +1 -1
  122. data/lib/rubocop/cop/util.rb +1 -1
  123. data/lib/rubocop/cop/utils/regexp_ranges.rb +100 -0
  124. data/lib/rubocop/cop/variable_force/assignment.rb +33 -1
  125. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  126. data/lib/rubocop/cop/variable_force.rb +1 -0
  127. data/lib/rubocop/cops_documentation_generator.rb +1 -1
  128. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  129. data/lib/rubocop/lsp/logger.rb +22 -0
  130. data/lib/rubocop/lsp/routes.rb +223 -0
  131. data/lib/rubocop/lsp/runtime.rb +79 -0
  132. data/lib/rubocop/lsp/server.rb +62 -0
  133. data/lib/rubocop/lsp/severity.rb +27 -0
  134. data/lib/rubocop/options.rb +11 -1
  135. data/lib/rubocop/result_cache.rb +1 -1
  136. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  137. data/lib/rubocop/server/client_command/exec.rb +2 -1
  138. data/lib/rubocop/target_ruby.rb +3 -2
  139. data/lib/rubocop/version.rb +10 -6
  140. data/lib/rubocop.rb +13 -0
  141. metadata +38 -6
@@ -411,7 +411,7 @@ module RuboCop
411
411
  end
412
412
 
413
413
  def correction_would_break_code?(node)
414
- return unless node.keywords?
414
+ return false unless node.keywords?
415
415
 
416
416
  node.send_node.arguments? && !node.send_node.parenthesized?
417
417
  end
@@ -433,7 +433,7 @@ module RuboCop
433
433
  end
434
434
 
435
435
  def return_value_used?(node)
436
- return unless node.parent
436
+ return false unless node.parent
437
437
 
438
438
  # If there are parentheses around the block, check if that
439
439
  # is being used.
@@ -445,7 +445,7 @@ module RuboCop
445
445
  end
446
446
 
447
447
  def return_value_of_scope?(node)
448
- return unless node.parent
448
+ return false unless node.parent
449
449
 
450
450
  conditional?(node.parent) || array_or_range?(node.parent) ||
451
451
  node.parent.children.last == node
@@ -139,7 +139,7 @@ module RuboCop
139
139
  end
140
140
 
141
141
  def check_style(node, body)
142
- return if node.identifier.children[0]&.cbase_type?
142
+ return if node.identifier.namespace&.cbase_type?
143
143
 
144
144
  if style == :nested
145
145
  check_nested_style(node)
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Style
6
6
  # Enforces the use of `Object#instance_of?` instead of class comparison
7
7
  # for equality.
8
- # `==`, `equal?`, and `eql?` methods are allowed by default.
8
+ # `==`, `equal?`, and `eql?` custom method definitions are allowed by default.
9
9
  # These are customizable with `AllowedMethods` option.
10
10
  #
11
11
  # @example
@@ -18,53 +18,31 @@ module RuboCop
18
18
  # # good
19
19
  # var.instance_of?(Date)
20
20
  #
21
- # @example AllowedMethods: [] (default)
21
+ # @example AllowedMethods: ['==', 'equal?', 'eql?'] (default)
22
22
  # # good
23
- # var.instance_of?(Date)
24
- #
25
- # # bad
26
- # var.class == Date
27
- # var.class.equal?(Date)
28
- # var.class.eql?(Date)
29
- # var.class.name == 'Date'
30
- # var.class.to_s == 'Date'
31
- # var.class.inspect == 'Date'
23
+ # def ==(other)
24
+ # self.class == other.class && name == other.name
25
+ # end
32
26
  #
33
- # @example AllowedMethods: [`==`]
34
- # # good
35
- # var.instance_of?(Date)
36
- # var.class == Date
37
- # var.class.name == 'Date'
38
- # var.class.to_s == 'Date'
39
- # var.class.inspect == 'Date'
27
+ # def equal?(other)
28
+ # self.class.equal?(other.class) && name.equal?(other.name)
29
+ # end
40
30
  #
41
- # # bad
42
- # var.class.equal?(Date)
43
- # var.class.eql?(Date)
31
+ # def eql?(other)
32
+ # self.class.eql?(other.class) && name.eql?(other.name)
33
+ # end
44
34
  #
45
35
  # @example AllowedPatterns: [] (default)
46
- # # good
47
- # var.instance_of?(Date)
48
- #
49
36
  # # bad
50
- # var.class == Date
51
- # var.class.equal?(Date)
52
- # var.class.eql?(Date)
53
- # var.class.name == 'Date'
54
- # var.class.to_s == 'Date'
55
- # var.class.inspect == 'Date'
37
+ # def eq(other)
38
+ # self.class.eq(other.class) && name.eq(other.name)
39
+ # end
56
40
  #
57
41
  # @example AllowedPatterns: ['eq']
58
42
  # # good
59
- # var.instance_of?(Date)
60
- # var.class.equal?(Date)
61
- # var.class.eql?(Date)
62
- #
63
- # # bad
64
- # var.class == Date
65
- # var.class.name == 'Date'
66
- # var.class.to_s == 'Date'
67
- # var.class.inspect == 'Date'
43
+ # def eq(other)
44
+ # self.class.eq(other.class) && name.eq(other.name)
45
+ # end
68
46
  #
69
47
  class ClassEqualityComparison < Base
70
48
  include RangeHelp
@@ -9,8 +9,8 @@ module RuboCop
9
9
  # @safety
10
10
  # It is unsafe by default because false positives may occur in the
11
11
  # `nil` check of block arguments to the receiver object. Additionally,
12
- # we can't know the type of the receiver object for sure, which may
13
- # result in false positives as well.
12
+ # we can't know the type of the receiver object for sure, which may
13
+ # result in false positives as well.
14
14
  #
15
15
  # For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
16
16
  # and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
@@ -19,7 +19,9 @@ module RuboCop
19
19
  # @example
20
20
  # # bad
21
21
  # array.reject(&:nil?)
22
+ # array.delete_if(&:nil?)
22
23
  # array.reject { |e| e.nil? }
24
+ # array.delete_if { |e| e.nil? }
23
25
  # array.select { |e| !e.nil? }
24
26
  #
25
27
  # # good
@@ -33,20 +35,25 @@ module RuboCop
33
35
  # # good
34
36
  # hash.compact!
35
37
  #
38
+ # @example AllowedReceivers: ['params']
39
+ # # good
40
+ # params.reject(&:nil?)
41
+ #
36
42
  class CollectionCompact < Base
43
+ include AllowedReceivers
37
44
  include RangeHelp
38
45
  extend AutoCorrector
39
46
  extend TargetRubyVersion
40
47
 
41
48
  MSG = 'Use `%<good>s` instead of `%<bad>s`.'
42
- RESTRICT_ON_SEND = %i[reject reject! select select!].freeze
49
+ RESTRICT_ON_SEND = %i[reject delete_if reject! select select!].freeze
43
50
  TO_ENUM_METHODS = %i[to_enum lazy].freeze
44
51
 
45
52
  minimum_target_ruby_version 2.4
46
53
 
47
54
  # @!method reject_method_with_block_pass?(node)
48
55
  def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
49
- (send !nil? {:reject :reject!}
56
+ (send !nil? {:reject :delete_if :reject!}
50
57
  (block_pass
51
58
  (sym :nil?)))
52
59
  PATTERN
@@ -55,7 +62,7 @@ module RuboCop
55
62
  def_node_matcher :reject_method?, <<~PATTERN
56
63
  (block
57
64
  (send
58
- !nil? {:reject :reject!})
65
+ !nil? {:reject :delete_if :reject!})
59
66
  $(args ...)
60
67
  (send
61
68
  $(lvar _) :nil?))
@@ -74,7 +81,10 @@ module RuboCop
74
81
 
75
82
  def on_send(node)
76
83
  return unless (range = offense_range(node))
77
- return if target_ruby_version <= 3.0 && to_enum_method?(node)
84
+ return if allowed_receiver?(node.receiver)
85
+ if (target_ruby_version <= 3.0 || node.method?(:delete_if)) && to_enum_method?(node)
86
+ return
87
+ end
78
88
 
79
89
  good = good_method_name(node)
80
90
  message = format(MSG, good: good, bad: range.source)
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for methods invoked via the :: operator instead
7
- # of the . operator (like FileUtils::rmdir instead of FileUtils.rmdir).
6
+ # Checks for methods invoked via the `::` operator instead
7
+ # of the `.` operator (like `FileUtils::rmdir` instead of `FileUtils.rmdir`).
8
8
  #
9
9
  # @example
10
10
  # # bad
@@ -57,38 +57,58 @@ module RuboCop
57
57
  # end
58
58
  #
59
59
  class CombinableLoops < Base
60
+ extend AutoCorrector
61
+
62
+ include RangeHelp
63
+
60
64
  MSG = 'Combine this loop with the previous loop.'
61
65
 
62
66
  def on_block(node)
63
67
  return unless node.parent&.begin_type?
64
68
  return unless collection_looping_method?(node)
69
+ return unless same_collection_looping_block?(node, node.left_sibling)
65
70
 
66
- add_offense(node) if same_collection_looping?(node, node.left_sibling)
71
+ add_offense(node) do |corrector|
72
+ combine_with_left_sibling(corrector, node)
73
+ end
67
74
  end
68
75
 
69
76
  alias on_numblock on_block
70
77
 
71
78
  def on_for(node)
72
79
  return unless node.parent&.begin_type?
80
+ return unless same_collection_looping_for?(node, node.left_sibling)
73
81
 
74
- sibling = node.left_sibling
75
- add_offense(node) if sibling&.for_type? && node.collection == sibling.collection
82
+ add_offense(node) do |corrector|
83
+ combine_with_left_sibling(corrector, node)
84
+ end
76
85
  end
77
86
 
78
87
  private
79
88
 
80
89
  def collection_looping_method?(node)
81
- # TODO: Remove `Symbol#to_s` after supporting only Ruby >= 2.7.
82
- method_name = node.method_name.to_s
90
+ method_name = node.method_name
83
91
  method_name.start_with?('each') || method_name.end_with?('_each')
84
92
  end
85
93
 
86
- def same_collection_looping?(node, sibling)
94
+ def same_collection_looping_block?(node, sibling)
87
95
  (sibling&.block_type? || sibling&.numblock_type?) &&
88
96
  sibling.send_node.method?(node.method_name) &&
89
97
  sibling.receiver == node.receiver &&
90
98
  sibling.send_node.arguments == node.send_node.arguments
91
99
  end
100
+
101
+ def same_collection_looping_for?(node, sibling)
102
+ sibling&.for_type? && node.collection == sibling.collection
103
+ end
104
+
105
+ def combine_with_left_sibling(corrector, node)
106
+ corrector.replace(
107
+ node.left_sibling.body,
108
+ "#{node.left_sibling.body.source}\n#{node.body.source}"
109
+ )
110
+ corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
111
+ end
92
112
  end
93
113
  end
94
114
  end
@@ -350,7 +350,7 @@ module RuboCop
350
350
  end
351
351
 
352
352
  def ternary_condition?(node)
353
- [node, node.children.first].any? { |n| n.if_type? && n.ternary? }
353
+ [node, node.children.first].compact.any? { |n| n.if_type? && n.ternary? }
354
354
  end
355
355
 
356
356
  def lhs_all_match?(branches)
@@ -361,7 +361,7 @@ module RuboCop
361
361
  end
362
362
 
363
363
  def assignment_types_match?(*nodes)
364
- return unless assignment_type?(nodes.first)
364
+ return false unless assignment_type?(nodes.first)
365
365
 
366
366
  nodes.map(&:type).uniq.one?
367
367
  end
@@ -386,7 +386,7 @@ module RuboCop
386
386
  def allowed_statements?(branches)
387
387
  return false unless branches.all?
388
388
 
389
- statements = branches.map { |branch| tail(branch) }.compact
389
+ statements = branches.filter_map { |branch| tail(branch) }
390
390
 
391
391
  lhs_all_match?(statements) && statements.none?(&:masgn_type?) &&
392
392
  assignment_types_match?(*statements)
@@ -440,6 +440,8 @@ module RuboCop
440
440
  module ConditionalCorrectorHelper
441
441
  def remove_whitespace_in_branches(corrector, branch, condition, column)
442
442
  branch.each_node do |child|
443
+ next if child.source_range.nil?
444
+
443
445
  white_space = white_space_range(child, column)
444
446
  corrector.remove(white_space) if white_space.source.strip.empty?
445
447
  end
@@ -8,8 +8,11 @@ module RuboCop
8
8
  # The default regexp for an acceptable copyright notice can be found in
9
9
  # config/default.yml. The default can be changed as follows:
10
10
  #
11
- # Style/Copyright:
12
- # Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
11
+ # [source,yaml]
12
+ # ----
13
+ # Style/Copyright:
14
+ # Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
15
+ # ----
13
16
  #
14
17
  # This regex string is treated as an unanchored regex. For each file
15
18
  # that RuboCop scans, a comment that matches this regex must be found or
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for places where the `#__dir__` method can replace more
6
+ # Checks for places where the `#\_\_dir\_\_` method can replace more
7
7
  # complex constructs to retrieve a canonicalized absolute path to the
8
8
  # current file.
9
9
  #
@@ -19,18 +19,16 @@ module RuboCop
19
19
  extend AutoCorrector
20
20
  extend TargetRubyVersion
21
21
 
22
- MSG = 'Use `Dir.empty?(%<arg>s)` instead.'
23
- RESTRICT_ON_SEND = %i[== > empty? none?].freeze
22
+ MSG = 'Use `%<replacement>s` instead.'
23
+ RESTRICT_ON_SEND = %i[== != > empty? none?].freeze
24
24
 
25
25
  minimum_target_ruby_version 2.4
26
26
 
27
27
  # @!method offensive?(node)
28
28
  def_node_matcher :offensive?, <<~PATTERN
29
29
  {
30
- (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) {:== :>} (int 2))
31
- (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) {:== :>} (int 0))
32
- (send (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) :!) {:== :>} (int 2))
33
- (send (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) :!) {:== :>} (int 0))
30
+ (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) {:== :!= :>} (int 2))
31
+ (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) {:== :!= :>} (int 0))
34
32
  (send (send $(const {nil? cbase} :Dir) :children $_) :empty?)
35
33
  (send (send $(const {nil? cbase} :Dir) :each_child $_) :none?)
36
34
  }
@@ -38,10 +36,9 @@ module RuboCop
38
36
 
39
37
  def on_send(node)
40
38
  offensive?(node) do |const_node, arg_node|
41
- add_offense(node, message: format(MSG, arg: arg_node.source)) do |corrector|
42
- bang(node)
43
- corrector.replace(node,
44
- "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})")
39
+ replacement = "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})"
40
+ add_offense(node, message: format(MSG, replacement: replacement)) do |corrector|
41
+ corrector.replace(node, replacement)
45
42
  end
46
43
  end
47
44
  end
@@ -49,10 +46,7 @@ module RuboCop
49
46
  private
50
47
 
51
48
  def bang(node)
52
- if (node.method?(:==) && node.child_nodes.first.method?(:!)) ||
53
- (node.method?(:>) && !node.child_nodes.first.method?(:!))
54
- '!'
55
- end
49
+ '!' if %i[!= >].include? node.method_name
56
50
  end
57
51
  end
58
52
  end
@@ -108,7 +108,7 @@ module RuboCop
108
108
  comments = heredoc_comment_blocks(arg_node.loc.heredoc_body.line_span)
109
109
  .concat(preceding_comment_blocks(arg_node.parent))
110
110
 
111
- return if comments.none?
111
+ return false if comments.none?
112
112
 
113
113
  regexp = comment_regexp(arg_node)
114
114
  comments.any?(regexp) || regexp.match?(comments.join)
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # declarations.
11
11
  #
12
12
  # The documentation requirement is annulled if the class or module has
13
- # a "#:nodoc:" comment next to it. Likewise, "#:nodoc: all" does the
13
+ # a `#:nodoc:` comment next to it. Likewise, `#:nodoc: all` does the
14
14
  # same for all its children.
15
15
  #
16
16
  # @example
@@ -4,12 +4,12 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Ensures that eval methods (`eval`, `instance_eval`, `class_eval`
7
- # and `module_eval`) are given filename and line number values (`__FILE__`
8
- # and `__LINE__`). This data is used to ensure that any errors raised
7
+ # and `module_eval`) are given filename and line number values (`\_\_FILE\_\_`
8
+ # and `\_\_LINE\_\_`). This data is used to ensure that any errors raised
9
9
  # within the evaluated code will be given the correct identification
10
10
  # in a backtrace.
11
11
  #
12
- # The cop also checks that the line number given relative to `__LINE__` is
12
+ # The cop also checks that the line number given relative to `\_\_LINE\_\_` is
13
13
  # correct.
14
14
  #
15
15
  # This cop will autocorrect incorrect or missing filename and line number
@@ -57,7 +57,7 @@ module RuboCop
57
57
  extend AutoCorrector
58
58
 
59
59
  MSG = 'Pass `__FILE__` and `__LINE__` to `%<method_name>s`.'
60
- MSG_EVAL = 'Pass a binding, `__FILE__` and `__LINE__` to `eval`.'
60
+ MSG_EVAL = 'Pass a binding, `__FILE__`, and `__LINE__` to `eval`.'
61
61
  MSG_INCORRECT_FILE = 'Incorrect file for `%<method_name>s`; ' \
62
62
  'use `%<expected>s` instead of `%<actual>s`.'
63
63
  MSG_INCORRECT_LINE = 'Incorrect line number for `%<method_name>s`; ' \
@@ -210,7 +210,7 @@ module RuboCop
210
210
  def add_offense_for_missing_line(node, code)
211
211
  register_offense(node) do |corrector|
212
212
  line_str = missing_line(node, code)
213
- corrector.insert_after(node.source_range.end, ", #{line_str}")
213
+ corrector.insert_after(node.last_argument.source_range.end, ", #{line_str}")
214
214
  end
215
215
  end
216
216
 
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for exact regexp match inside Regexp literals.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # string =~ /\Astring\z/
12
+ # string === /\Astring\z/
13
+ # string.match(/\Astring\z/)
14
+ # string.match?(/\Astring\z/)
15
+ #
16
+ # # good
17
+ # string == 'string'
18
+ #
19
+ # # bad
20
+ # string !~ /\Astring\z/
21
+ #
22
+ # # good
23
+ # string != 'string'
24
+ #
25
+ class ExactRegexpMatch < Base
26
+ extend AutoCorrector
27
+
28
+ MSG = 'Use `%<prefer>s`.'
29
+ RESTRICT_ON_SEND = %i[=~ === !~ match match?].freeze
30
+
31
+ # @!method exact_regexp_match(node)
32
+ def_node_matcher :exact_regexp_match, <<~PATTERN
33
+ (send
34
+ _ {:=~ :=== :!~ :match :match?}
35
+ (regexp
36
+ (str $_)
37
+ (regopt)))
38
+ PATTERN
39
+
40
+ def on_send(node)
41
+ return unless (regexp = exact_regexp_match(node))
42
+
43
+ parsed_regexp = Regexp::Parser.parse(regexp)
44
+ return unless exact_match_pattern?(parsed_regexp)
45
+
46
+ prefer = "#{node.receiver.source} #{new_method(node)} '#{parsed_regexp[1].text}'"
47
+
48
+ add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
49
+ corrector.replace(node, prefer)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def exact_match_pattern?(parsed_regexp)
56
+ tokens = parsed_regexp.map(&:token)
57
+ return false unless tokens[0] == :bos && tokens[1] == :literal && tokens[2] == :eos
58
+
59
+ !parsed_regexp[1].quantifier
60
+ end
61
+
62
+ def new_method(node)
63
+ node.method?(:!~) ? '!=' : '=='
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -63,7 +63,7 @@ module RuboCop
63
63
 
64
64
  # @!method block_read?(node)
65
65
  def_node_matcher :block_read?, <<~PATTERN
66
- (block _ (args (arg $_)) (send (lvar $_) :read))
66
+ (block _ (args (arg _name)) (send (lvar _name) :read))
67
67
  PATTERN
68
68
 
69
69
  def on_send(node)
@@ -100,7 +100,7 @@ module RuboCop
100
100
  def file_open_read?(node)
101
101
  return true if send_read?(node)
102
102
 
103
- block_read?(node) { |block_arg, read_lvar| block_arg == read_lvar }
103
+ block_read?(node)
104
104
  end
105
105
 
106
106
  def read_method(mode)
@@ -187,6 +187,8 @@ module RuboCop
187
187
  if_branch = node.if_branch
188
188
  else_branch = node.else_branch
189
189
 
190
+ corrector.replace(node.loc.begin, "\n") if node.loc.begin&.is?('then')
191
+
190
192
  if if_branch&.send_type? && heredoc?(if_branch.last_argument)
191
193
  autocorrect_heredoc_argument(corrector, node, if_branch, else_branch, guard)
192
194
  elsif else_branch&.send_type? && heredoc?(else_branch.last_argument)
@@ -28,6 +28,7 @@ module RuboCop
28
28
  # execute(sql).keys.each { |v| p v }
29
29
  # execute(sql).values.each { |v| p v }
30
30
  class HashEachMethods < Base
31
+ include AllowedReceivers
31
32
  include Lint::UnusedArgument
32
33
  extend AutoCorrector
33
34
 
@@ -116,28 +117,6 @@ module RuboCop
116
117
  def kv_range(outer_node)
117
118
  outer_node.receiver.loc.selector.join(outer_node.loc.selector)
118
119
  end
119
-
120
- def allowed_receiver?(receiver)
121
- receiver_name = receiver_name(receiver)
122
-
123
- allowed_receivers.include?(receiver_name)
124
- end
125
-
126
- def receiver_name(receiver)
127
- if receiver.send_type?
128
- if receiver.receiver
129
- "#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
130
- else
131
- receiver.method_name.to_s
132
- end
133
- else
134
- receiver.source
135
- end
136
- end
137
-
138
- def allowed_receivers
139
- cop_config.fetch('AllowedReceivers', [])
140
- end
141
120
  end
142
121
  end
143
122
  end
@@ -45,13 +45,13 @@ module RuboCop
45
45
  (block
46
46
  (send _ _)
47
47
  (args
48
- (arg _)
48
+ $(arg _)
49
49
  (arg _))
50
50
  {
51
- (send
51
+ $(send
52
52
  _ {:== :!= :eql? :include?} _)
53
53
  (send
54
- (send
54
+ $(send
55
55
  _ {:== :!= :eql? :include?} _) :!)
56
56
  })
57
57
  PATTERN
@@ -61,13 +61,13 @@ module RuboCop
61
61
  (block
62
62
  (send _ _)
63
63
  (args
64
- (arg _)
64
+ $(arg _)
65
65
  (arg _))
66
66
  {
67
- (send
67
+ $(send
68
68
  _ {:== :!= :eql? :in? :include? :exclude?} _)
69
69
  (send
70
- (send
70
+ $(send
71
71
  _ {:== :!= :eql? :in? :include? :exclude?} _) :!)
72
72
  })
73
73
  PATTERN
@@ -89,13 +89,24 @@ module RuboCop
89
89
 
90
90
  private
91
91
 
92
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
92
93
  def bad_method?(block)
93
94
  if active_support_extensions_enabled?
94
- bad_method_with_active_support?(block)
95
+ bad_method_with_active_support?(block) do |key_arg, send_node|
96
+ if send_node.method?(:in?) && send_node.receiver&.source != key_arg.source
97
+ return false
98
+ end
99
+ return true if !send_node.method?(:include?) && !send_node.method?(:exclude?)
100
+
101
+ send_node.first_argument&.source == key_arg.source
102
+ end
95
103
  else
96
- bad_method_with_poro?(block)
104
+ bad_method_with_poro?(block) do |key_arg, send_node|
105
+ !send_node.method?(:include?) || send_node.first_argument&.source == key_arg.source
106
+ end
97
107
  end
98
108
  end
109
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
99
110
 
100
111
  def semantically_except_method?(send, block)
101
112
  body = block.body
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Looks for uses of `_.each_with_object({}) {...}`,
7
- # `_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just
6
+ # Looks for uses of `\_.each_with_object({}) {...}`,
7
+ # `\_.map {...}.to_h`, and `Hash[\_.map {...}]` that are actually just
8
8
  # transforming the keys of a hash, and tries to use a simpler & faster
9
9
  # call to `transform_keys` instead.
10
10
  # It should only be enabled on Ruby version 2.5 or newer.
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Looks for uses of `_.each_with_object({}) {...}`,
7
- # `_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just
6
+ # Looks for uses of `\_.each_with_object({}) {...}`,
7
+ # `\_.map {...}.to_h`, and `Hash[\_.map {...}]` that are actually just
8
8
  # transforming the values of a hash, and tries to use a simpler & faster
9
9
  # call to `transform_values` instead.
10
10
  #