rubocop 1.41.1 → 1.45.1

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +97 -31
  5. data/lib/rubocop/cli.rb +55 -9
  6. data/lib/rubocop/config.rb +7 -7
  7. data/lib/rubocop/config_loader.rb +12 -15
  8. data/lib/rubocop/config_loader_resolver.rb +8 -5
  9. data/lib/rubocop/cop/base.rb +89 -70
  10. data/lib/rubocop/cop/commissioner.rb +8 -2
  11. data/lib/rubocop/cop/cop.rb +51 -31
  12. data/lib/rubocop/cop/corrector.rb +30 -10
  13. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
  14. data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
  15. data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
  16. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
  17. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  18. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
  19. data/lib/rubocop/cop/layout/class_structure.rb +31 -23
  20. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
  21. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
  22. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  23. data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
  24. data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
  25. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +6 -6
  26. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  27. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  28. data/lib/rubocop/cop/layout/space_around_operators.rb +1 -1
  29. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +11 -13
  30. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +4 -4
  31. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +5 -4
  32. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -2
  33. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
  34. data/lib/rubocop/cop/lint/debugger.rb +8 -27
  35. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
  36. data/lib/rubocop/cop/lint/else_layout.rb +2 -6
  37. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +14 -7
  38. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
  39. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  40. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  41. data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -5
  42. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
  43. data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
  44. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  45. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
  46. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  47. data/lib/rubocop/cop/lint/useless_access_modifier.rb +7 -4
  48. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
  49. data/lib/rubocop/cop/lint/useless_rescue.rb +85 -0
  50. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +14 -4
  51. data/lib/rubocop/cop/lint/void.rb +19 -10
  52. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  53. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  54. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  55. data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
  56. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  57. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +3 -6
  58. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  59. data/lib/rubocop/cop/mixin/allowed_methods.rb +3 -1
  60. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  61. data/lib/rubocop/cop/mixin/comments_help.rb +5 -3
  62. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +57 -23
  63. data/lib/rubocop/cop/mixin/line_length_help.rb +3 -1
  64. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  65. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -0
  66. data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -3
  67. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  68. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -0
  69. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
  70. data/lib/rubocop/cop/registry.rb +34 -29
  71. data/lib/rubocop/cop/security/compound_hash.rb +2 -1
  72. data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -11
  73. data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -0
  74. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  75. data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
  76. data/lib/rubocop/cop/style/class_and_module_children.rb +3 -10
  77. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  78. data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
  79. data/lib/rubocop/cop/style/concat_array_literals.rb +22 -2
  80. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
  81. data/lib/rubocop/cop/style/documentation.rb +1 -1
  82. data/lib/rubocop/cop/style/documentation_method.rb +6 -0
  83. data/lib/rubocop/cop/style/guard_clause.rb +11 -7
  84. data/lib/rubocop/cop/style/hash_each_methods.rb +13 -1
  85. data/lib/rubocop/cop/style/hash_syntax.rb +11 -7
  86. data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
  87. data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
  88. data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -0
  89. data/lib/rubocop/cop/style/map_to_set.rb +61 -0
  90. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +23 -14
  91. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
  92. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
  93. data/lib/rubocop/cop/style/min_max_comparison.rb +83 -0
  94. data/lib/rubocop/cop/style/missing_else.rb +13 -1
  95. data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
  96. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  97. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +18 -3
  98. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
  99. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +11 -3
  100. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
  101. data/lib/rubocop/cop/style/operator_method_call.rb +16 -2
  102. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -1
  103. data/lib/rubocop/cop/style/redundant_condition.rb +16 -1
  104. data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
  105. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -10
  106. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +58 -0
  107. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  108. data/lib/rubocop/cop/style/redundant_string_escape.rb +4 -2
  109. data/lib/rubocop/cop/style/require_order.rb +6 -11
  110. data/lib/rubocop/cop/style/select_by_regexp.rb +6 -2
  111. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  112. data/lib/rubocop/cop/style/semicolon.rb +24 -2
  113. data/lib/rubocop/cop/style/signal_exception.rb +8 -6
  114. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
  115. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  116. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
  117. data/lib/rubocop/cop/style/word_array.rb +42 -1
  118. data/lib/rubocop/cop/style/yoda_condition.rb +12 -5
  119. data/lib/rubocop/cop/style/yoda_expression.rb +90 -0
  120. data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
  121. data/lib/rubocop/cop/team.rb +48 -43
  122. data/lib/rubocop/cop/variable_force/scope.rb +3 -3
  123. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -1
  124. data/lib/rubocop/cop/variable_force.rb +1 -4
  125. data/lib/rubocop/formatter.rb +0 -1
  126. data/lib/rubocop/options.rb +22 -1
  127. data/lib/rubocop/path_util.rb +17 -7
  128. data/lib/rubocop/result_cache.rb +1 -1
  129. data/lib/rubocop/rspec/expect_offense.rb +6 -4
  130. data/lib/rubocop/runner.rb +50 -7
  131. data/lib/rubocop/server/cache.rb +10 -3
  132. data/lib/rubocop/server/cli.rb +37 -18
  133. data/lib/rubocop/server/client_command/exec.rb +1 -1
  134. data/lib/rubocop/server/client_command/start.rb +6 -1
  135. data/lib/rubocop/server/core.rb +23 -8
  136. data/lib/rubocop/target_ruby.rb +0 -1
  137. data/lib/rubocop/version.rb +1 -1
  138. data/lib/rubocop.rb +8 -0
  139. metadata +21 -33
@@ -11,6 +11,8 @@ module RuboCop
11
11
  # File.exists?(some_path)
12
12
  # Dir.exists?(some_path)
13
13
  # iterator?
14
+ # attr :name, true
15
+ # attr :name, false
14
16
  # ENV.freeze # Calling `Env.freeze` raises `TypeError` since Ruby 2.7.
15
17
  # ENV.clone
16
18
  # ENV.dup # Calling `Env.dup` raises `TypeError` since Ruby 3.1.
@@ -21,6 +23,8 @@ module RuboCop
21
23
  # File.exist?(some_path)
22
24
  # Dir.exist?(some_path)
23
25
  # block_given?
26
+ # attr_accessor :name
27
+ # attr_reader :name
24
28
  # ENV # `ENV.freeze` cannot prohibit changes to environment variables.
25
29
  # ENV.to_h
26
30
  # ENV.to_h # `ENV.dup` cannot dup `ENV`, use `ENV.to_h` to get a copy of `ENV` as a hash.
@@ -29,138 +33,84 @@ module RuboCop
29
33
  class DeprecatedClassMethods < Base
30
34
  extend AutoCorrector
31
35
 
32
- # Inner class to DeprecatedClassMethods.
33
- # This class exists to add abstraction and clean naming
34
- # to the deprecated objects
35
- class DeprecatedClassMethod
36
- include RuboCop::AST::Sexp
36
+ MSG = '`%<current>s` is deprecated in favor of `%<prefer>s`.'
37
+ RESTRICT_ON_SEND = %i[
38
+ attr clone dup exists? freeze gethostbyaddr gethostbyname iterator?
39
+ ].freeze
40
+
41
+ PREFERRED_METHDOS = {
42
+ clone: 'to_h',
43
+ dup: 'to_h',
44
+ exists?: 'exist?',
45
+ gethostbyaddr: 'Addrinfo#getnameinfo',
46
+ gethostbyname: 'Addrinfo#getaddrinfo',
47
+ iterator?: 'block_given?'
48
+ }.freeze
37
49
 
38
- attr_reader :method, :class_constant
50
+ DIR_ENV_FILE_CONSTANTS = %i[Dir ENV File].freeze
39
51
 
40
- def initialize(method, class_constant: nil, correctable: true)
41
- @method = method
42
- @class_constant = class_constant
43
- @correctable = correctable
44
- end
45
-
46
- def class_nodes
47
- @class_nodes ||=
48
- if class_constant
49
- [
50
- s(:const, nil, class_constant),
51
- s(:const, s(:cbase), class_constant)
52
- ]
53
- else
54
- [nil]
55
- end
56
- end
52
+ # @!method deprecated_class_method?(node)
53
+ def_node_matcher :deprecated_class_method?, <<~PATTERN
54
+ {
55
+ (send (const {cbase nil?} {:ENV}) {:clone :dup :freeze})
56
+ (send (const {cbase nil?} {:File :Dir}) :exists? _)
57
+ (send (const {cbase nil?} :Socket) {:gethostbyaddr :gethostbyname} ...)
58
+ (send nil? :attr _ boolean)
59
+ (send nil? :iterator?)
60
+ }
61
+ PATTERN
57
62
 
58
- def correctable?
59
- @correctable
60
- end
63
+ def on_send(node)
64
+ return unless deprecated_class_method?(node)
61
65
 
62
- def to_s
63
- [class_constant, method].compact.join(delimiter)
64
- end
66
+ offense_range = offense_range(node)
67
+ prefer = preferred_method(node)
68
+ message = format(MSG, current: offense_range.source, prefer: prefer)
65
69
 
66
- private
70
+ add_offense(offense_range, message: message) do |corrector|
71
+ next if socket_const?(node.receiver)
67
72
 
68
- def delimiter
69
- CLASS_METHOD_DELIMITER
73
+ if node.method?(:freeze)
74
+ corrector.replace(node, 'ENV')
75
+ else
76
+ corrector.replace(offense_range, prefer)
77
+ end
70
78
  end
71
79
  end
72
80
 
73
- # Inner class to DeprecatedClassMethods.
74
- # This class exists to add abstraction and clean naming
75
- # to the replacements for deprecated objects
76
- class Replacement
77
- attr_reader :method, :class_constant
78
-
79
- def initialize(method, class_constant: nil, instance_method: false)
80
- @method = method
81
- @class_constant = class_constant
82
- @instance_method = instance_method
83
- end
84
-
85
- def to_s
86
- [class_constant, method].compact.join(delimiter)
87
- end
88
-
89
- private
90
-
91
- def delimiter
92
- instance_method? ? INSTANCE_METHOD_DELIMITER : CLASS_METHOD_DELIMITER
93
- end
81
+ private
94
82
 
95
- def instance_method?
96
- @instance_method
83
+ def offense_range(node)
84
+ if socket_const?(node.receiver) || dir_env_file_const?(node.receiver)
85
+ node.loc.expression.begin.join(node.loc.selector.end)
86
+ elsif node.method?(:attr)
87
+ node
88
+ else
89
+ node.loc.selector
97
90
  end
98
91
  end
99
92
 
100
- MSG = '`%<current>s` is deprecated in favor of `%<prefer>s`.'
101
-
102
- DEPRECATED_METHODS_OBJECT = {
103
- DeprecatedClassMethod.new(:exists?, class_constant: :File) =>
104
- Replacement.new(:exist?, class_constant: :File),
105
-
106
- DeprecatedClassMethod.new(:exists?, class_constant: :Dir) =>
107
- Replacement.new(:exist?, class_constant: :Dir),
108
-
109
- DeprecatedClassMethod.new(:iterator?) => Replacement.new(:block_given?),
110
-
111
- DeprecatedClassMethod.new(:freeze, class_constant: :ENV) =>
112
- Replacement.new(nil, class_constant: :ENV),
93
+ def preferred_method(node)
94
+ if node.method?(:attr)
95
+ boolean_argument = node.arguments[1].source
96
+ preferred_attr_method = boolean_argument == 'true' ? 'attr_accessor' : 'attr_reader'
113
97
 
114
- DeprecatedClassMethod.new(:clone, class_constant: :ENV) =>
115
- Replacement.new(:to_h, class_constant: :ENV),
116
-
117
- DeprecatedClassMethod.new(:dup, class_constant: :ENV) =>
118
- Replacement.new(:to_h, class_constant: :ENV),
119
-
120
- DeprecatedClassMethod.new(:gethostbyaddr, class_constant: :Socket, correctable: false) =>
121
- Replacement.new(:getnameinfo, class_constant: :Addrinfo, instance_method: true),
122
-
123
- DeprecatedClassMethod.new(:gethostbyname, class_constant: :Socket, correctable: false) =>
124
- Replacement.new(:getaddrinfo, class_constant: :Addrinfo, instance_method: true)
125
- }.freeze
98
+ "#{preferred_attr_method} #{node.first_argument.source}"
99
+ elsif dir_env_file_const?(node.receiver)
100
+ prefer = PREFERRED_METHDOS[node.method_name]
126
101
 
127
- RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.keys.map(&:method).freeze
128
-
129
- CLASS_METHOD_DELIMITER = '.'
130
- INSTANCE_METHOD_DELIMITER = '#'
131
-
132
- def on_send(node)
133
- check(node) do |deprecated|
134
- prefer = replacement(deprecated)
135
- message = format(MSG, current: deprecated, prefer: prefer)
136
- current_method = node.loc.selector
137
-
138
- add_offense(current_method, message: message) do |corrector|
139
- next unless deprecated.correctable?
140
-
141
- if (preferred_method = prefer.method)
142
- corrector.replace(current_method, preferred_method)
143
- else
144
- corrector.remove(node.loc.dot)
145
- corrector.remove(current_method)
146
- end
147
- end
102
+ prefer ? "#{node.receiver.source}.#{prefer}" : 'ENV'
103
+ else
104
+ PREFERRED_METHDOS[node.method_name]
148
105
  end
149
106
  end
150
107
 
151
- private
152
-
153
- def check(node)
154
- DEPRECATED_METHODS_OBJECT.each_key do |deprecated|
155
- next unless deprecated.class_nodes.include?(node.receiver)
156
- next unless node.method?(deprecated.method)
157
-
158
- yield deprecated
159
- end
108
+ def socket_const?(node)
109
+ node&.short_name == :Socket
160
110
  end
161
111
 
162
- def replacement(deprecated)
163
- DEPRECATED_METHODS_OBJECT[deprecated]
112
+ def dir_env_file_const?(node)
113
+ DIR_ENV_FILE_CONSTANTS.include?(node&.short_name)
164
114
  end
165
115
  end
166
116
  end
@@ -41,6 +41,7 @@ module RuboCop
41
41
  # do_that
42
42
  # end
43
43
  class ElseLayout < Base
44
+ include Alignment
44
45
  include RangeHelp
45
46
  extend AutoCorrector
46
47
 
@@ -81,12 +82,7 @@ module RuboCop
81
82
  corrector.insert_after(node.loc.else, "\n")
82
83
 
83
84
  blank_range = range_between(node.loc.else.end_pos, first_else.loc.expression.begin_pos)
84
- indentation = indent(node, offset: indentation_width)
85
- corrector.replace(blank_range, indentation)
86
- end
87
-
88
- def indentation_width
89
- @config.for_cop('Layout/IndentationWidth')['Width'] || 2
85
+ corrector.replace(blank_range, indentation(node))
90
86
  end
91
87
  end
92
88
  end
@@ -81,6 +81,10 @@ module RuboCop
81
81
 
82
82
  return false if num_of_format_args == :unknown
83
83
 
84
+ first_arg = node.first_argument
85
+ return false if num_of_expected_fields.zero? &&
86
+ (first_arg.dstr_type? || first_arg.array_type?)
87
+
84
88
  matched_arguments_count?(num_of_expected_fields, num_of_format_args)
85
89
  end
86
90
 
@@ -94,8 +98,8 @@ module RuboCop
94
98
 
95
99
  # @!method called_on_string?(node)
96
100
  def_node_matcher :called_on_string?, <<~PATTERN
97
- {(send {nil? const_type?} _ (str _) ...)
98
- (send (str ...) ...)}
101
+ {(send {nil? const_type?} _ {str dstr} ...)
102
+ (send {str dstr} ...)}
99
103
  PATTERN
100
104
 
101
105
  def method_with_format_args?(node)
@@ -143,11 +147,11 @@ module RuboCop
143
147
  return false if node.const_receiver? && !node.receiver.loc.name.is?(KERNEL)
144
148
  return false unless node.method?(name)
145
149
 
146
- node.arguments.size > 1 && node.first_argument.str_type?
150
+ node.arguments.size > 1 && string_type?(node.first_argument)
147
151
  end
148
152
 
149
153
  def expected_fields_count(node)
150
- return :unknown unless node.str_type?
154
+ return :unknown unless string_type?(node)
151
155
 
152
156
  format_string = RuboCop::Cop::Utils::FormatString.new(node.source)
153
157
  return 1 if format_string.named_interpolation?
@@ -172,10 +176,9 @@ module RuboCop
172
176
  def percent?(node)
173
177
  receiver = node.receiver
174
178
 
175
- percent = node.method?(:%) &&
176
- (STRING_TYPES.include?(receiver.type) || node.first_argument.array_type?)
179
+ percent = node.method?(:%) && (string_type?(receiver) || node.first_argument.array_type?)
177
180
 
178
- return false if percent && STRING_TYPES.include?(receiver.type) && heredoc?(node)
181
+ return false if percent && string_type?(receiver) && heredoc?(node)
179
182
 
180
183
  percent
181
184
  end
@@ -188,6 +191,10 @@ module RuboCop
188
191
  format(MSG, arg_num: num_args_for_format, method: method_name,
189
192
  field_num: num_expected_fields)
190
193
  end
194
+
195
+ def string_type?(node)
196
+ STRING_TYPES.include?(node.type)
197
+ end
191
198
  end
192
199
  end
193
200
  end
@@ -8,27 +8,25 @@ module RuboCop
8
8
  #
9
9
  # @example
10
10
  # # bad
11
+ # <<-SQL
12
+ # bar
13
+ # SQL
14
+ # .strip_indent
11
15
  #
12
- # <<-SQL
13
- # bar
14
- # SQL
15
- # .strip_indent
16
- #
17
- # <<-SQL
18
- # bar
19
- # SQL
20
- # .strip_indent
21
- # .trim
16
+ # <<-SQL
17
+ # bar
18
+ # SQL
19
+ # .strip_indent
20
+ # .trim
22
21
  #
23
22
  # # good
23
+ # <<~SQL
24
+ # bar
25
+ # SQL
24
26
  #
25
- # <<~SQL
26
- # bar
27
- # SQL
28
- #
29
- # <<~SQL.trim
30
- # bar
31
- # SQL
27
+ # <<~SQL.trim
28
+ # bar
29
+ # SQL
32
30
  #
33
31
  class HeredocMethodCallPosition < Base
34
32
  include RangeHelp
@@ -81,7 +81,7 @@ module RuboCop
81
81
  end
82
82
 
83
83
  def display_str(node)
84
- if /\n/.match?(node.source)
84
+ if node.source.include?("\n")
85
85
  str_content(node).inspect
86
86
  else
87
87
  node.source
@@ -8,6 +8,7 @@ module RuboCop
8
8
  # Replace numbered captures with non-capturing groupings or
9
9
  # named captures.
10
10
  #
11
+ # @example
11
12
  # # bad
12
13
  # /(?<foo>FOO)(BAR)/
13
14
  #
@@ -108,7 +108,7 @@ module RuboCop
108
108
  return unless def_ancestor
109
109
 
110
110
  within_scoping_def =
111
- node.each_ancestor(:block, :sclass).any? do |ancestor|
111
+ node.each_ancestor(:block, :numblock, :sclass).any? do |ancestor|
112
112
  scoping_method_call?(ancestor)
113
113
  end
114
114
 
@@ -120,7 +120,7 @@ module RuboCop
120
120
 
121
121
  def scoping_method_call?(child)
122
122
  child.sclass_type? || eval_call?(child) || exec_call?(child) ||
123
- class_or_module_or_struct_new_call?(child) || allowed_method_name?(child)
123
+ class_constructor?(child) || allowed_method_name?(child)
124
124
  end
125
125
 
126
126
  def allowed_method_name?(node)
@@ -139,9 +139,12 @@ module RuboCop
139
139
  (block (send _ {:instance_exec :class_exec :module_exec} ...) ...)
140
140
  PATTERN
141
141
 
142
- # @!method class_or_module_or_struct_new_call?(node)
143
- def_node_matcher :class_or_module_or_struct_new_call?, <<~PATTERN
144
- (block (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...)
142
+ # @!method class_constructor?(node)
143
+ def_node_matcher :class_constructor?, <<~PATTERN
144
+ ({block numblock} {
145
+ (send (const {nil? cbase} {:Class :Module :Struct}) :new ...)
146
+ (send (const {nil? cbase} :Data) :define ...)
147
+ } ...)
145
148
  PATTERN
146
149
  end
147
150
  end
@@ -68,6 +68,12 @@ module RuboCop
68
68
  @valid_ref = regexp_conditions.map { |condition| check_regexp(condition) }.compact.max
69
69
  end
70
70
 
71
+ def on_in_pattern(node)
72
+ regexp_patterns = patterns(node).select(&:regexp_type?)
73
+
74
+ @valid_ref = regexp_patterns.map { |pattern| check_regexp(pattern) }.compact.max
75
+ end
76
+
71
77
  def on_nth_ref(node)
72
78
  backref, = *node
73
79
  return if @valid_ref.nil? || backref <= @valid_ref
@@ -84,6 +90,19 @@ module RuboCop
84
90
 
85
91
  private
86
92
 
93
+ def patterns(pattern_node)
94
+ pattern = pattern_node.node_parts[0]
95
+
96
+ case pattern.type
97
+ when :array_pattern, :match_alt
98
+ pattern.children
99
+ when :match_as
100
+ patterns(pattern)
101
+ else
102
+ [pattern]
103
+ end
104
+ end
105
+
87
106
  def check_regexp(node)
88
107
  return if node.interpolation?
89
108
 
@@ -38,6 +38,10 @@ module RuboCop
38
38
  MSG = 'Remove unnecessary `require` statement.'
39
39
  RESTRICT_ON_SEND = %i[require].freeze
40
40
  RUBY_22_LOADED_FEATURES = %w[rational complex].freeze
41
+ PRETTY_PRINT_METHODS = %i[
42
+ pretty_inspect pretty_print pretty_print_cycle
43
+ pretty_print_inspect pretty_print_instance_variables
44
+ ].freeze
41
45
 
42
46
  # @!method redundant_require_statement?(node)
43
47
  def_node_matcher :redundant_require_statement?, <<~PATTERN
@@ -68,12 +72,18 @@ module RuboCop
68
72
  feature_name == 'enumerator' ||
69
73
  (target_ruby_version >= 2.1 && feature_name == 'thread') ||
70
74
  (target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
71
- (target_ruby_version >= 2.5 && feature_name == 'pp') ||
75
+ (target_ruby_version >= 2.5 && feature_name == 'pp' && !use_pretty_print_method?) ||
72
76
  (target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
73
77
  (target_ruby_version >= 3.1 && feature_name == 'fiber') ||
74
78
  (target_ruby_version >= 3.2 && feature_name == 'set')
75
79
  end
76
80
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
81
+
82
+ def use_pretty_print_method?
83
+ processed_source.ast.each_descendant(:send).any? do |node|
84
+ PRETTY_PRINT_METHODS.include?(node.method_name)
85
+ end
86
+ end
77
87
  end
78
88
  end
79
89
  end
@@ -17,13 +17,19 @@ module RuboCop
17
17
  # do_something
18
18
  # end
19
19
  class RegexpAsCondition < Base
20
+ include IgnoredNode
20
21
  extend AutoCorrector
21
22
 
22
23
  MSG = 'Do not use regexp literal as a condition. ' \
23
24
  'The regexp literal matches `$_` implicitly.'
24
25
 
25
26
  def on_match_current_line(node)
27
+ return if node.ancestors.none?(&:conditional?)
28
+ return if part_of_ignored_node?(node)
29
+
26
30
  add_offense(node) { |corrector| corrector.replace(node, "#{node.source} =~ $_") }
31
+
32
+ ignore_node(node)
27
33
  end
28
34
  end
29
35
  end
@@ -46,7 +46,9 @@ module RuboCop
46
46
  private
47
47
 
48
48
  def check_ternary(ternary, node)
49
- return if node.method?(:[]) || !ternary.condition.operator_keyword?
49
+ if node.method?(:[]) || node.assignment_method? || !ternary.condition.operator_keyword?
50
+ return
51
+ end
50
52
 
51
53
  range = range_between(node.source_range.begin_pos, ternary.condition.source_range.end_pos)
52
54
 
@@ -100,7 +100,8 @@ module RuboCop
100
100
 
101
101
  unless variable.keyword_argument?
102
102
  message << " If it's necessary, use `_` or `_#{variable.name}` " \
103
- "as an argument name to indicate that it won't be used."
103
+ "as an argument name to indicate that it won't be used. " \
104
+ "If it's unnecessary, remove it."
104
105
  end
105
106
 
106
107
  scope = variable.scope
@@ -167,9 +167,12 @@ module RuboCop
167
167
  ({block numblock} (send _ {:class_eval :instance_eval}) ...)
168
168
  PATTERN
169
169
 
170
- # @!method class_or_module_or_struct_new_call?(node)
171
- def_node_matcher :class_or_module_or_struct_new_call?, <<~PATTERN
172
- ({block numblock} (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...)
170
+ # @!method class_constructor?(node)
171
+ def_node_matcher :class_constructor?, <<~PATTERN
172
+ ({block numblock} {
173
+ (send (const {nil? cbase} {:Class :Module :Struct}) :new ...)
174
+ (send (const {nil? cbase} :Data) :define ...)
175
+ } ...)
173
176
  PATTERN
174
177
 
175
178
  def check_node(node)
@@ -270,7 +273,7 @@ module RuboCop
270
273
 
271
274
  def eval_call?(child)
272
275
  class_or_instance_eval?(child) ||
273
- class_or_module_or_struct_new_call?(child) ||
276
+ class_constructor?(child) ||
274
277
  any_context_creating_methods?(child)
275
278
  end
276
279
 
@@ -41,7 +41,7 @@ module RuboCop
41
41
  MSG = 'Useless method definition detected.'
42
42
 
43
43
  def on_def(node)
44
- return if optional_args?(node)
44
+ return if use_rest_or_optional_args?(node)
45
45
  return unless delegating?(node.body, node)
46
46
 
47
47
  add_offense(node) { |corrector| corrector.remove(node) }
@@ -50,8 +50,8 @@ module RuboCop
50
50
 
51
51
  private
52
52
 
53
- def optional_args?(node)
54
- node.arguments.any? { |arg| arg.optarg_type? || arg.kwoptarg_type? }
53
+ def use_rest_or_optional_args?(node)
54
+ node.arguments.any? { |arg| arg.restarg_type? || arg.optarg_type? || arg.kwoptarg_type? }
55
55
  end
56
56
 
57
57
  def delegating?(node, def_node)
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for useless `rescue`s, which only reraise rescued exceptions.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # def foo
11
+ # do_something
12
+ # rescue
13
+ # raise
14
+ # end
15
+ #
16
+ # # bad
17
+ # def foo
18
+ # do_something
19
+ # rescue => e
20
+ # raise # or 'raise e', or 'raise $!', or 'raise $ERROR_INFO'
21
+ # end
22
+ #
23
+ # # good
24
+ # def foo
25
+ # do_something
26
+ # rescue
27
+ # do_cleanup
28
+ # raise
29
+ # end
30
+ #
31
+ # # bad (latest rescue)
32
+ # def foo
33
+ # do_something
34
+ # rescue ArgumentError
35
+ # # noop
36
+ # rescue
37
+ # raise
38
+ # end
39
+ #
40
+ # # good (not the latest rescue)
41
+ # def foo
42
+ # do_something
43
+ # rescue ArgumentError
44
+ # raise
45
+ # rescue
46
+ # # noop
47
+ # end
48
+ #
49
+ class UselessRescue < Base
50
+ MSG = 'Useless `rescue` detected.'
51
+
52
+ def on_rescue(node)
53
+ resbody_node = node.resbody_branches.last
54
+ add_offense(resbody_node) if only_reraising?(resbody_node)
55
+ end
56
+
57
+ private
58
+
59
+ def only_reraising?(resbody_node)
60
+ return false if use_exception_variable_in_ensure?(resbody_node)
61
+
62
+ body = resbody_node.body
63
+ return false if body.nil? || !body.send_type? || !body.method?(:raise)
64
+ return true unless body.arguments?
65
+ return false if body.arguments.size > 1
66
+
67
+ exception_name = body.first_argument.source
68
+
69
+ exception_objects(resbody_node).include?(exception_name)
70
+ end
71
+
72
+ def use_exception_variable_in_ensure?(resbody_node)
73
+ return false unless (exception_variable = resbody_node.exception_variable)
74
+ return false unless (ensure_node = resbody_node.each_ancestor(:ensure).first)
75
+
76
+ ensure_node.body.each_descendant(:lvar).map(&:source).include?(exception_variable.source)
77
+ end
78
+
79
+ def exception_objects(resbody_node)
80
+ [resbody_node.exception_variable&.source, '$!', '$ERROR_INFO']
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -77,10 +77,12 @@ module RuboCop
77
77
  PATTERN
78
78
 
79
79
  def on_send(node)
80
- if node.first_argument.def_type?
81
- inspect_def(node, node.first_argument)
80
+ return unless (first_argument = node.first_argument)
81
+
82
+ if first_argument.def_type?
83
+ inspect_def(node, first_argument)
82
84
  elsif node.first_argument.sym_type?
83
- inspect_sym(node, node.first_argument)
85
+ inspect_sym(node, first_argument)
84
86
  end
85
87
  end
86
88
 
@@ -96,7 +98,7 @@ module RuboCop
96
98
  return unless node.parent
97
99
 
98
100
  method_name = sym_node.value
99
- definition = node.parent.each_child_node.detect { |n| method_definition(n, method_name) }
101
+ definition = find_method_definition(node, method_name)
100
102
 
101
103
  return unless definition
102
104
  return if allowed_arguments(definition.arguments)
@@ -104,6 +106,14 @@ module RuboCop
104
106
  add_offense(node, message: format(MSG, method_name: method_name))
105
107
  end
106
108
 
109
+ def find_method_definition(node, method_name)
110
+ node.each_ancestor.lazy.map do |ancestor|
111
+ ancestor.each_child_node(:def, :block, :numblock).find do |child|
112
+ method_definition(child, method_name)
113
+ end
114
+ end.find(&:itself)
115
+ end
116
+
107
117
  # `ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
108
118
  def allowed_arguments(arguments)
109
119
  return false if arguments.empty?