rubocop 1.36.0 → 1.39.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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +31 -3
  4. data/lib/rubocop/arguments_env.rb +17 -0
  5. data/lib/rubocop/arguments_file.rb +17 -0
  6. data/lib/rubocop/cli/command/execute_runner.rb +7 -7
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +8 -1
  8. data/lib/rubocop/comment_config.rb +36 -1
  9. data/lib/rubocop/cop/commissioner.rb +3 -1
  10. data/lib/rubocop/cop/generator.rb +1 -2
  11. data/lib/rubocop/cop/internal_affairs/create_empty_file.rb +37 -0
  12. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +111 -0
  13. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  14. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
  15. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  16. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  17. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
  18. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  19. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
  20. data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
  21. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +30 -3
  22. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
  23. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +6 -2
  24. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  25. data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
  26. data/lib/rubocop/cop/lint/duplicate_methods.rb +28 -9
  27. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
  28. data/lib/rubocop/cop/lint/empty_class.rb +3 -1
  29. data/lib/rubocop/cop/lint/empty_conditional_body.rb +20 -8
  30. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
  31. data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
  32. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  33. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
  34. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
  35. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -1
  36. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
  37. data/lib/rubocop/cop/lint/redundant_require_statement.rb +38 -10
  38. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  39. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
  40. data/lib/rubocop/cop/lint/shadowed_exception.rb +0 -10
  41. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +3 -0
  42. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  43. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  44. data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
  45. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  46. data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
  47. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
  48. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -3
  49. data/lib/rubocop/cop/mixin/range_help.rb +23 -0
  50. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
  51. data/lib/rubocop/cop/mixin/surrounding_space.rb +10 -8
  52. data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
  53. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
  54. data/lib/rubocop/cop/registry.rb +10 -4
  55. data/lib/rubocop/cop/style/access_modifier_declarations.rb +5 -7
  56. data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
  57. data/lib/rubocop/cop/style/block_delimiters.rb +2 -2
  58. data/lib/rubocop/cop/style/character_literal.rb +1 -1
  59. data/lib/rubocop/cop/style/class_equality_comparison.rb +8 -6
  60. data/lib/rubocop/cop/style/collection_compact.rb +12 -3
  61. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  62. data/lib/rubocop/cop/style/endless_method.rb +1 -1
  63. data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
  64. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  65. data/lib/rubocop/cop/style/guard_clause.rb +62 -21
  66. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
  67. data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
  68. data/lib/rubocop/cop/style/hash_except.rb +4 -0
  69. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  70. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +25 -2
  71. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
  72. data/lib/rubocop/cop/style/module_function.rb +28 -6
  73. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
  74. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  75. data/lib/rubocop/cop/style/object_then.rb +3 -0
  76. data/lib/rubocop/cop/style/operator_method_call.rb +53 -0
  77. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  78. data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
  79. data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
  80. data/lib/rubocop/cop/style/redundant_each.rb +116 -0
  81. data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
  82. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
  83. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -3
  84. data/lib/rubocop/cop/style/redundant_string_escape.rb +181 -0
  85. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  86. data/lib/rubocop/cop/style/static_class.rb +32 -1
  87. data/lib/rubocop/cop/style/symbol_array.rb +2 -0
  88. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  89. data/lib/rubocop/cop/style/word_array.rb +2 -0
  90. data/lib/rubocop/cop/team.rb +3 -4
  91. data/lib/rubocop/cop/util.rb +1 -1
  92. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  93. data/lib/rubocop/cops_documentation_generator.rb +2 -1
  94. data/lib/rubocop/ext/processed_source.rb +2 -0
  95. data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
  96. data/lib/rubocop/formatter/offense_count_formatter.rb +8 -5
  97. data/lib/rubocop/formatter/worst_offenders_formatter.rb +6 -3
  98. data/lib/rubocop/options.rb +19 -15
  99. data/lib/rubocop/rspec/cop_helper.rb +21 -1
  100. data/lib/rubocop/rspec/shared_contexts.rb +14 -1
  101. data/lib/rubocop/runner.rb +15 -11
  102. data/lib/rubocop/server/cache.rb +5 -1
  103. data/lib/rubocop/server/cli.rb +9 -2
  104. data/lib/rubocop/server/client_command/exec.rb +5 -0
  105. data/lib/rubocop/server/core.rb +18 -1
  106. data/lib/rubocop/server/socket_reader.rb +5 -1
  107. data/lib/rubocop/server.rb +1 -1
  108. data/lib/rubocop/version.rb +8 -3
  109. data/lib/rubocop.rb +4 -0
  110. metadata +13 -5
@@ -41,6 +41,7 @@ module RuboCop
41
41
  return unless (receiver = node.receiver)
42
42
  return unless receiver.receiver&.const_type? && receiver.receiver.short_name == :Dir
43
43
  return unless GLOB_METHODS.include?(receiver.method_name)
44
+ return if multiple_argument?(receiver)
44
45
 
45
46
  selector = node.loc.selector
46
47
 
@@ -49,6 +50,12 @@ module RuboCop
49
50
  corrector.remove(node.loc.dot)
50
51
  end
51
52
  end
53
+
54
+ private
55
+
56
+ def multiple_argument?(glob_method)
57
+ glob_method.arguments.count >= 2 || glob_method.first_argument&.splat_type?
58
+ end
52
59
  end
53
60
  end
54
61
  end
@@ -6,13 +6,23 @@ module RuboCop
6
6
  # Checks for unnecessary `require` statement.
7
7
  #
8
8
  # The following features are unnecessary `require` statement because
9
- # they are already loaded.
9
+ # they are already loaded. e.g. Ruby 2.2:
10
10
  #
11
11
  # ruby -ve 'p $LOADED_FEATURES.reject { |feature| %r|/| =~ feature }'
12
12
  # ruby 2.2.8p477 (2017-09-14 revision 59906) [x86_64-darwin13]
13
13
  # ["enumerator.so", "rational.so", "complex.so", "thread.rb"]
14
14
  #
15
- # This cop targets Ruby 2.2 or higher containing these 4 features.
15
+ # Below are the features that each `TargetRubyVersion` targets.
16
+ #
17
+ # * 2.0+ ... `enumerator`
18
+ # * 2.1+ ... `thread`
19
+ # * 2.2+ ... Add `rational` and `complex` above
20
+ # * 2.5+ ... Add `pp` above
21
+ # * 2.7+ ... Add `ruby2_keywords` above
22
+ # * 3.1+ ... Add `fiber` above
23
+ # * 3.2+ ... `set`
24
+ #
25
+ # This cop target those features.
16
26
  #
17
27
  # @example
18
28
  # # bad
@@ -24,28 +34,46 @@ module RuboCop
24
34
  class RedundantRequireStatement < Base
25
35
  include RangeHelp
26
36
  extend AutoCorrector
27
- extend TargetRubyVersion
28
-
29
- minimum_target_ruby_version 2.2
30
37
 
31
38
  MSG = 'Remove unnecessary `require` statement.'
32
39
  RESTRICT_ON_SEND = %i[require].freeze
40
+ RUBY_22_LOADED_FEATURES = %w[rational complex].freeze
33
41
 
34
- # @!method unnecessary_require_statement?(node)
35
- def_node_matcher :unnecessary_require_statement?, <<~PATTERN
42
+ # @!method redundant_require_statement?(node)
43
+ def_node_matcher :redundant_require_statement?, <<~PATTERN
36
44
  (send nil? :require
37
- (str {"enumerator" "rational" "complex" "thread"}))
45
+ (str #redundant_feature?))
38
46
  PATTERN
39
47
 
40
48
  def on_send(node)
41
- return unless unnecessary_require_statement?(node)
49
+ return unless redundant_require_statement?(node)
42
50
 
43
51
  add_offense(node) do |corrector|
44
- range = range_with_surrounding_space(node.loc.expression, side: :right)
52
+ if node.parent.respond_to?(:modifier_form?) && node.parent.modifier_form?
53
+ corrector.insert_after(node.parent, "\nend")
54
+
55
+ range = range_with_surrounding_space(node.loc.expression, side: :right)
56
+ else
57
+ range = range_by_whole_lines(node.source_range, include_final_newline: true)
58
+ end
45
59
 
46
60
  corrector.remove(range)
47
61
  end
48
62
  end
63
+
64
+ private
65
+
66
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
67
+ def redundant_feature?(feature_name)
68
+ feature_name == 'enumerator' ||
69
+ (target_ruby_version >= 2.1 && feature_name == 'thread') ||
70
+ (target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
71
+ (target_ruby_version >= 2.5 && feature_name == 'pp') ||
72
+ (target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
73
+ (target_ruby_version >= 3.1 && feature_name == 'fiber') ||
74
+ (target_ruby_version >= 3.2 && feature_name == 'set')
75
+ end
76
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
49
77
  end
50
78
  end
51
79
  end
@@ -46,7 +46,7 @@ module RuboCop
46
46
  private
47
47
 
48
48
  def check_ternary(ternary, node)
49
- return unless ternary.condition.operator_keyword?
49
+ return if node.method?(:[]) || !ternary.condition.operator_keyword?
50
50
 
51
51
  range = range_between(node.source_range.begin_pos, ternary.condition.source_range.end_pos)
52
52
 
@@ -31,6 +31,7 @@ module RuboCop
31
31
  minimum_target_ruby_version 2.3
32
32
 
33
33
  MSG = 'Do not chain ordinary method call after safe navigation operator.'
34
+ PLUS_MINUS_METHODS = %i[+@ -@].freeze
34
35
 
35
36
  # @!method bad_method?(node)
36
37
  def_node_matcher :bad_method?, <<~PATTERN
@@ -42,7 +43,7 @@ module RuboCop
42
43
 
43
44
  def on_send(node)
44
45
  bad_method?(node) do |safe_nav, method|
45
- return if nil_methods.include?(method)
46
+ return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
46
47
 
47
48
  method_chain = method_chain(node)
48
49
  location =
@@ -71,7 +72,7 @@ module RuboCop
71
72
  else
72
73
  offense_range.source.dup
73
74
  end
74
- source.prepend('.') unless send_node.dot?
75
+ source.prepend('.') unless source.start_with?('.')
75
76
  source.prepend('&')
76
77
  end
77
78
 
@@ -155,16 +155,6 @@ module RuboCop
155
155
  end
156
156
  end
157
157
 
158
- # @param [RuboCop::AST::Node] rescue_group is a node of array_type
159
- def rescued_exceptions(rescue_group)
160
- klasses = *rescue_group
161
- klasses.map do |klass|
162
- next unless klass.const_type?
163
-
164
- klass.source
165
- end.compact
166
- end
167
-
168
158
  def find_shadowing_rescue(rescues)
169
159
  rescued_groups = rescued_groups_for(rescues)
170
160
  rescued_groups.zip(rescues).each do |group, res|
@@ -12,9 +12,12 @@ module RuboCop
12
12
  # because `Ractor` should not access outer variables.
13
13
  # eg. following style is encouraged:
14
14
  #
15
+ # [source,ruby]
16
+ # ----
15
17
  # worker_id, pipe = env
16
18
  # Ractor.new(worker_id, pipe) do |worker_id, pipe|
17
19
  # end
20
+ # ----
18
21
  #
19
22
  # @example
20
23
  #
@@ -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, :block).first
119
+ ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block, :numblock).first
120
120
  return unless ancestor
121
121
 
122
122
  end_line = ancestor.loc.end.line
@@ -79,7 +79,7 @@ module RuboCop
79
79
  # # bad
80
80
  # 2.times { raise ArgumentError }
81
81
  #
82
- # @example AllowedPatterns: [/(exactly|at_least|at_most)\(\d+\)\.times/] (default)
82
+ # @example AllowedPatterns: ['(exactly|at_least|at_most)\(\d+\)\.times'] (default)
83
83
  #
84
84
  # # good
85
85
  # exactly(2).times { raise StandardError }
@@ -68,6 +68,10 @@ module RuboCop
68
68
  (send nil? :fail ...)}
69
69
  PATTERN
70
70
 
71
+ def self.autocorrect_incompatible_with
72
+ [Style::ExplicitBlockArgument]
73
+ end
74
+
71
75
  def self.joining_forces
72
76
  VariableForce
73
77
  end
@@ -20,7 +20,7 @@ module RuboCop
20
20
  #
21
21
  # @example CountRepeatedAttributes: false (default is true)
22
22
  #
23
- # # `model` and `current_user`, refenced 3 times each,
23
+ # # `model` and `current_user`, referenced 3 times each,
24
24
  # # are each counted as only 1 branch each if
25
25
  # # `CountRepeatedAttributes` is set to 'false'
26
26
  #
@@ -22,6 +22,18 @@ module RuboCop
22
22
  processed_source.each_comment_in_lines(start_line...end_line)
23
23
  end
24
24
 
25
+ def comments_contain_disables?(node, cop_name)
26
+ disabled_ranges = processed_source.disabled_line_ranges[cop_name]
27
+
28
+ return unless disabled_ranges
29
+
30
+ node_range = node.source_range.line...find_end_line(node)
31
+
32
+ disabled_ranges.any? do |disable_range|
33
+ disable_range.cover?(node_range) || node_range.cover?(disable_range)
34
+ end
35
+ end
36
+
25
37
  private
26
38
 
27
39
  def end_position_for(node)
@@ -69,6 +69,10 @@ module RuboCop
69
69
  end
70
70
  end
71
71
 
72
+ def leading_magic_comments
73
+ leading_comment_lines.map { |line| MagicComment.parse(line) }
74
+ end
75
+
72
76
  def leading_comment_lines
73
77
  first_non_comment_token = processed_source.tokens.find { |token| !token.comment? }
74
78
 
@@ -96,11 +96,14 @@ module RuboCop
96
96
  end
97
97
 
98
98
  def without_parentheses_call_expr_follows?(ancestor)
99
+ return false unless ancestor.respond_to?(:parenthesized?) && !ancestor.parenthesized?
100
+
99
101
  right_sibling = ancestor.right_sibling
100
- right_sibling ||= ancestor.each_ancestor.find(&:assignment?)&.right_sibling
101
- return false unless right_sibling
102
+ right_sibling ||= ancestor.each_ancestor.find do |node|
103
+ node.assignment? || node.send_type?
104
+ end&.right_sibling
102
105
 
103
- ancestor.respond_to?(:parenthesized?) && !ancestor.parenthesized? && !!right_sibling
106
+ !!right_sibling
104
107
  end
105
108
 
106
109
  def breakdown_value_types_of_hash(hash_node)
@@ -126,6 +126,29 @@ module RuboCop
126
126
  pos += size * step while condition && src[pos + offset, size] == needle
127
127
  pos.negative? ? 0 : pos
128
128
  end
129
+
130
+ def range_with_comments_and_lines(node)
131
+ range_by_whole_lines(range_with_comments(node), include_final_newline: true)
132
+ end
133
+
134
+ def range_with_comments(node)
135
+ ranges = [
136
+ node,
137
+ *@processed_source.ast_with_comments[node]
138
+ ].map do |element|
139
+ element.location.expression
140
+ end
141
+ ranges.reduce do |result, range|
142
+ add_range(result, range)
143
+ end
144
+ end
145
+
146
+ def add_range(range1, range2)
147
+ range1.with(
148
+ begin_pos: [range1.begin_pos, range2.begin_pos].min,
149
+ end_pos: [range1.end_pos, range2.end_pos].max
150
+ )
151
+ end
129
152
  end
130
153
  end
131
154
  end
@@ -11,7 +11,9 @@ module RuboCop
11
11
  private
12
12
 
13
13
  def rescue_modifier?(node)
14
- node&.resbody_type? && @modifier_locations.include?(node.loc.keyword)
14
+ return false unless node.respond_to?(:resbody_type?)
15
+
16
+ node.resbody_type? && @modifier_locations.include?(node.loc.keyword)
15
17
  end
16
18
 
17
19
  # @deprecated Use ResbodyNode#exceptions instead
@@ -13,7 +13,7 @@ module RuboCop
13
13
 
14
14
  private
15
15
 
16
- def side_space_range(range:, side:)
16
+ def side_space_range(range:, side:, include_newlines: false)
17
17
  buffer = processed_source.buffer
18
18
  src = buffer.source
19
19
 
@@ -21,11 +21,11 @@ module RuboCop
21
21
  end_pos = range.end_pos
22
22
  if side == :left
23
23
  end_pos = begin_pos
24
- begin_pos = reposition(src, begin_pos, -1)
24
+ begin_pos = reposition(src, begin_pos, -1, include_newlines: include_newlines)
25
25
  end
26
26
  if side == :right
27
27
  begin_pos = end_pos
28
- end_pos = reposition(src, end_pos, 1)
28
+ end_pos = reposition(src, end_pos, 1, include_newlines: include_newlines)
29
29
  end
30
30
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
31
31
  end
@@ -75,9 +75,10 @@ module RuboCop
75
75
  end
76
76
  end
77
77
 
78
- def reposition(src, pos, step)
78
+ def reposition(src, pos, step, include_newlines: false)
79
79
  offset = step == -1 ? -1 : 0
80
- pos += step while SINGLE_SPACE_REGEXP.match?(src[pos + offset])
80
+ pos += step while SINGLE_SPACE_REGEXP.match?(src[pos + offset]) ||
81
+ (include_newlines && src[pos + offset] == "\n")
81
82
  pos.negative? ? 0 : pos
82
83
  end
83
84
 
@@ -117,14 +118,15 @@ module RuboCop
117
118
  end
118
119
 
119
120
  def offending_empty_no_space?(config, left_token, right_token)
120
- config == 'no_space' && !no_space_between?(left_token, right_token)
121
+ config == 'no_space' && !no_character_between?(left_token, right_token)
121
122
  end
122
123
 
123
124
  def space_between?(left_bracket_token, right_bracket_token)
124
- left_bracket_token.end_pos + 1 == right_bracket_token.begin_pos
125
+ left_bracket_token.end_pos + 1 == right_bracket_token.begin_pos &&
126
+ processed_source.buffer.source[left_bracket_token.end_pos] == ' '
125
127
  end
126
128
 
127
- def no_space_between?(left_bracket_token, right_bracket_token)
129
+ def no_character_between?(left_bracket_token, right_bracket_token)
128
130
  left_bracket_token.end_pos == right_bracket_token.begin_pos
129
131
  end
130
132
  end
@@ -1,18 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'set'
4
+
3
5
  module RuboCop
4
6
  module Cop
5
7
  # Help methods for determining node visibility.
6
8
  module VisibilityHelp
7
9
  extend NodePattern::Macros
8
10
 
9
- VISIBILITY_SCOPES = %i[private protected public].freeze
11
+ VISIBILITY_SCOPES = ::Set[:private, :protected, :public].freeze
10
12
 
11
13
  private
12
14
 
13
15
  def node_visibility(node)
14
- scope = find_visibility_start(node)
15
- scope&.method_name || :public
16
+ node_visibility_from_visibility_inline(node) ||
17
+ node_visibility_from_visibility_block(node) ||
18
+ :public
19
+ end
20
+
21
+ def node_visibility_from_visibility_inline(node)
22
+ return unless node.def_type?
23
+
24
+ node_visibility_from_visibility_inline_on_def(node) ||
25
+ node_visibility_from_visibility_inline_on_method_name(node)
26
+ end
27
+
28
+ def node_visibility_from_visibility_inline_on_def(node)
29
+ parent = node.parent
30
+ parent.method_name if visibility_inline_on_def?(parent)
31
+ end
32
+
33
+ def node_visibility_from_visibility_inline_on_method_name(node)
34
+ node.right_siblings.reverse.find do |sibling|
35
+ visibility_inline_on_method_name?(sibling, method_name: node.method_name)
36
+ end&.method_name
37
+ end
38
+
39
+ def node_visibility_from_visibility_block(node)
40
+ find_visibility_start(node)&.method_name
16
41
  end
17
42
 
18
43
  def find_visibility_start(node)
@@ -21,7 +46,7 @@ module RuboCop
21
46
 
22
47
  # Navigate to find the last protected method
23
48
  def find_visibility_end(node)
24
- possible_visibilities = VISIBILITY_SCOPES - [node_visibility(node)]
49
+ possible_visibilities = VISIBILITY_SCOPES - ::Set[node_visibility(node)]
25
50
  right = node.right_siblings
26
51
  right.find do |child_node|
27
52
  possible_visibilities.include?(node_visibility(child_node))
@@ -30,7 +55,17 @@ module RuboCop
30
55
 
31
56
  # @!method visibility_block?(node)
32
57
  def_node_matcher :visibility_block?, <<~PATTERN
33
- (send nil? { :private :protected :public })
58
+ (send nil? VISIBILITY_SCOPES)
59
+ PATTERN
60
+
61
+ # @!method visibility_inline_on_def?(node)
62
+ def_node_matcher :visibility_inline_on_def?, <<~PATTERN
63
+ (send nil? VISIBILITY_SCOPES def)
64
+ PATTERN
65
+
66
+ # @!method visibility_inline_on_method_name?(node, method_name:)
67
+ def_node_matcher :visibility_inline_on_method_name?, <<~PATTERN
68
+ (send nil? VISIBILITY_SCOPES (sym %method_name))
34
69
  PATTERN
35
70
  end
36
71
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # This cops recommends the use of inclusive language instead of problematic terms.
6
+ # Recommends the use of inclusive language instead of problematic terms.
7
7
  # The cop can check the following locations for offenses:
8
8
  # - identifiers
9
9
  # - constants
@@ -149,16 +149,22 @@ module RuboCop
149
149
  @registry.size
150
150
  end
151
151
 
152
- def enabled(config, only = [], only_safe: false)
153
- select { |cop| only.include?(cop.cop_name) || enabled?(cop, config, only_safe) }
152
+ def enabled(config)
153
+ select { |cop| enabled?(cop, config) }
154
154
  end
155
155
 
156
- def enabled?(cop, config, only_safe)
156
+ def disabled(config)
157
+ reject { |cop| enabled?(cop, config) }
158
+ end
159
+
160
+ def enabled?(cop, config)
161
+ return true if options.fetch(:only, []).include?(cop.cop_name)
162
+
157
163
  cfg = config.for_cop(cop)
158
164
 
159
165
  cop_enabled = cfg.fetch('Enabled') == true || enabled_pending_cop?(cfg, config)
160
166
 
161
- if only_safe
167
+ if options.fetch(:safe, false)
162
168
  cop_enabled && cfg.fetch('Safe', true)
163
169
  else
164
170
  cop_enabled
@@ -85,6 +85,8 @@ module RuboCop
85
85
 
86
86
  RESTRICT_ON_SEND = %i[private protected public module_function].freeze
87
87
 
88
+ ALLOWED_NODE_TYPES = %i[pair block].freeze
89
+
88
90
  # @!method access_modifier_with_symbol?(node)
89
91
  def_node_matcher :access_modifier_with_symbol?, <<~PATTERN
90
92
  (send nil? {:private :protected :public :module_function} (sym _))
@@ -92,7 +94,7 @@ module RuboCop
92
94
 
93
95
  def on_send(node)
94
96
  return unless node.access_modifier?
95
- return if node.parent&.pair_type?
97
+ return if ALLOWED_NODE_TYPES.include?(node.parent&.type)
96
98
  return if allow_modifiers_on_symbols?(node)
97
99
 
98
100
  if offense?(node)
@@ -183,6 +185,7 @@ module RuboCop
183
185
  end
184
186
 
185
187
  def insert_def(corrector, node, source)
188
+ source = [*processed_source.ast_with_comments[node].map(&:text), source].join("\n")
186
189
  argument_less_modifier_node = find_argument_less_modifier_node(node)
187
190
  if argument_less_modifier_node
188
191
  corrector.insert_after(argument_less_modifier_node, "\n\n#{source}")
@@ -199,12 +202,7 @@ module RuboCop
199
202
  end
200
203
 
201
204
  def remove_node(corrector, node)
202
- corrector.remove(
203
- range_by_whole_lines(
204
- node.location.expression,
205
- include_final_newline: true
206
- )
207
- )
205
+ corrector.remove(range_with_comments_and_lines(node))
208
206
  end
209
207
  end
210
208
  end
@@ -135,12 +135,16 @@ module RuboCop
135
135
  end
136
136
 
137
137
  def separate_accessors(node)
138
- node.arguments.map do |arg|
139
- if arg == node.arguments.first
138
+ node.arguments.flat_map do |arg|
139
+ lines = [
140
+ *processed_source.ast_with_comments[arg].map(&:text),
140
141
  "#{node.method_name} #{arg.source}"
142
+ ]
143
+ if arg == node.arguments.first
144
+ lines
141
145
  else
142
146
  indent = ' ' * node.loc.column
143
- "#{indent}#{node.method_name} #{arg.source}"
147
+ lines.map { |line| "#{indent}#{line}" }
144
148
  end
145
149
  end.join("\n")
146
150
  end
@@ -157,7 +157,7 @@ module RuboCop
157
157
  # process(something)
158
158
  # }
159
159
  #
160
- # @example AllowedPatterns: [/map/]
160
+ # @example AllowedPatterns: ['map']
161
161
  #
162
162
  # # good
163
163
  # things.map { |thing|
@@ -425,7 +425,7 @@ module RuboCop
425
425
  if node.parent.begin_type?
426
426
  return_value_used?(node.parent)
427
427
  else
428
- node.parent.assignment? || node.parent.send_type?
428
+ node.parent.assignment? || node.parent.call_type?
429
429
  end
430
430
  end
431
431
 
@@ -29,7 +29,7 @@ module RuboCop
29
29
 
30
30
  def offense?(node)
31
31
  # we don't register an offense for things like ?\C-\M-d
32
- node.loc.begin.is?('?') && node.source.size.between?(2, 3)
32
+ node.character_literal? && node.source.size.between?(2, 3)
33
33
  end
34
34
 
35
35
  def autocorrect(corrector, node)
@@ -48,7 +48,7 @@ module RuboCop
48
48
  # var.class.eql?(Date)
49
49
  # var.class.name == 'Date'
50
50
  #
51
- # @example AllowedPatterns: [`/eq/`]
51
+ # @example AllowedPatterns: ['eq']
52
52
  # # good
53
53
  # var.instance_of?(Date)
54
54
  # var.class.equal?(Date)
@@ -97,12 +97,14 @@ module RuboCop
97
97
  if node.children.first.method?(:name)
98
98
  return class_node.receiver.source if class_node.receiver
99
99
 
100
- value = class_node.source.delete('"').delete("'")
101
- value.prepend('::') if class_node.each_ancestor(:class, :module).any?
102
- value
103
- else
104
- class_node.source
100
+ if class_node.str_type?
101
+ value = class_node.source.delete('"').delete("'")
102
+ value.prepend('::') if class_node.each_ancestor(:class, :module).any?
103
+ return value
104
+ end
105
105
  end
106
+
107
+ class_node.source
106
108
  end
107
109
 
108
110
  def offense_range(receiver_node, node)
@@ -8,7 +8,9 @@ module RuboCop
8
8
  #
9
9
  # @safety
10
10
  # It is unsafe by default because false positives may occur in the
11
- # `nil` check of block arguments to the receiver object.
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
14
  #
13
15
  # For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
14
16
  # and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
@@ -36,8 +38,8 @@ module RuboCop
36
38
  extend AutoCorrector
37
39
 
38
40
  MSG = 'Use `%<good>s` instead of `%<bad>s`.'
39
-
40
41
  RESTRICT_ON_SEND = %i[reject reject! select select!].freeze
42
+ TO_ENUM_METHODS = %i[to_enum lazy].freeze
41
43
 
42
44
  # @!method reject_method_with_block_pass?(node)
43
45
  def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
@@ -69,6 +71,7 @@ module RuboCop
69
71
 
70
72
  def on_send(node)
71
73
  return unless (range = offense_range(node))
74
+ return if target_ruby_version <= 3.0 && to_enum_method?(node)
72
75
 
73
76
  good = good_method_name(node)
74
77
  message = format(MSG, good: good, bad: range.source)
@@ -94,6 +97,12 @@ module RuboCop
94
97
  end
95
98
  end
96
99
 
100
+ def to_enum_method?(node)
101
+ return false unless node.receiver.send_type?
102
+
103
+ TO_ENUM_METHODS.include?(node.receiver.method_name)
104
+ end
105
+
97
106
  def good_method_name(node)
98
107
  if node.bang_method?
99
108
  'compact!'
@@ -103,7 +112,7 @@ module RuboCop
103
112
  end
104
113
 
105
114
  def range(begin_pos_node, end_pos_node)
106
- range_between(begin_pos_node.loc.selector.begin_pos, end_pos_node.loc.end.end_pos)
115
+ range_between(begin_pos_node.loc.selector.begin_pos, end_pos_node.loc.expression.end_pos)
107
116
  end
108
117
  end
109
118
  end
@@ -52,7 +52,7 @@ module RuboCop
52
52
  MSG_EXPANDED = 'Put the `end` of empty method definitions on the next line.'
53
53
 
54
54
  def on_def(node)
55
- return if node.body || comment_lines?(node)
55
+ return if node.body || processed_source.contains_comment?(node.source_range)
56
56
  return if correct_style?(node)
57
57
 
58
58
  add_offense(node) do |corrector|
@@ -39,7 +39,7 @@ module RuboCop
39
39
  #
40
40
  # @example EnforcedStyle: disallow
41
41
  # # bad
42
- # def my_method; x end
42
+ # def my_method() = x
43
43
  #
44
44
  # # bad
45
45
  # def my_method() = x.foo