rubocop 1.41.1 → 1.45.1

Sign up to get free protection for your applications and to get access to all the features.
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?