rubocop 1.39.0 → 1.44.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 (188) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +149 -11
  5. data/exe/rubocop +1 -1
  6. data/lib/rubocop/cli.rb +1 -1
  7. data/lib/rubocop/comment_config.rb +5 -0
  8. data/lib/rubocop/config.rb +39 -15
  9. data/lib/rubocop/config_loader.rb +26 -20
  10. data/lib/rubocop/config_loader_resolver.rb +6 -2
  11. data/lib/rubocop/config_validator.rb +1 -1
  12. data/lib/rubocop/cop/badge.rb +9 -4
  13. data/lib/rubocop/cop/base.rb +84 -74
  14. data/lib/rubocop/cop/commissioner.rb +8 -3
  15. data/lib/rubocop/cop/cop.rb +29 -29
  16. data/lib/rubocop/cop/corrector.rb +30 -10
  17. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  18. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
  19. data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
  20. data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
  21. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  22. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  23. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
  24. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  25. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
  26. data/lib/rubocop/cop/layout/class_structure.rb +32 -11
  27. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
  28. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
  29. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  30. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  31. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  32. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  33. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  34. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  35. data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
  36. data/lib/rubocop/cop/layout/indentation_style.rb +7 -2
  37. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  38. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -5
  39. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  40. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  41. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  42. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  43. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  44. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  45. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  46. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  47. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +0 -2
  48. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  49. data/lib/rubocop/cop/layout/trailing_whitespace.rb +11 -4
  50. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  51. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
  52. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  53. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  54. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  55. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
  56. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
  57. data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
  58. data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
  59. data/lib/rubocop/cop/lint/else_layout.rb +2 -6
  60. data/lib/rubocop/cop/lint/empty_block.rb +1 -5
  61. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  62. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -7
  63. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
  64. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  65. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  66. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  67. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
  68. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  69. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +15 -3
  70. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  71. data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
  72. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  73. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
  74. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +10 -12
  75. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  76. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
  77. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  78. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
  79. data/lib/rubocop/cop/lint/useless_rescue.rb +85 -0
  80. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +14 -4
  81. data/lib/rubocop/cop/lint/void.rb +25 -16
  82. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  83. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  84. data/lib/rubocop/cop/metrics/class_length.rb +10 -5
  85. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  86. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  87. data/lib/rubocop/cop/metrics/module_length.rb +10 -5
  88. data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
  89. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  90. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +3 -6
  91. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +6 -3
  92. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  93. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
  94. data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
  95. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
  96. data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
  97. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +59 -6
  98. data/lib/rubocop/cop/mixin/line_length_help.rb +11 -2
  99. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
  100. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
  101. data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
  102. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  103. data/lib/rubocop/cop/mixin/require_library.rb +2 -0
  104. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  105. data/lib/rubocop/cop/mixin/statement_modifier.rb +16 -1
  106. data/lib/rubocop/cop/naming/block_forwarding.rb +5 -1
  107. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  108. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  109. data/lib/rubocop/cop/registry.rb +63 -43
  110. data/lib/rubocop/cop/security/compound_hash.rb +2 -1
  111. data/lib/rubocop/cop/style/access_modifier_declarations.rb +18 -10
  112. data/lib/rubocop/cop/style/alias.rb +9 -1
  113. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  114. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  115. data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
  116. data/lib/rubocop/cop/style/class_and_module_children.rb +2 -9
  117. data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
  118. data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
  119. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
  120. data/lib/rubocop/cop/style/documentation.rb +11 -5
  121. data/lib/rubocop/cop/style/guard_clause.rb +44 -9
  122. data/lib/rubocop/cop/style/hash_each_methods.rb +13 -1
  123. data/lib/rubocop/cop/style/hash_syntax.rb +11 -7
  124. data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
  125. data/lib/rubocop/cop/style/if_with_semicolon.rb +4 -4
  126. data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
  127. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  128. data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -0
  129. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  130. data/lib/rubocop/cop/style/map_to_set.rb +61 -0
  131. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +23 -14
  132. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
  133. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
  134. data/lib/rubocop/cop/style/min_max_comparison.rb +83 -0
  135. data/lib/rubocop/cop/style/missing_else.rb +13 -1
  136. data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
  137. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  138. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
  139. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  140. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
  141. data/lib/rubocop/cop/style/operator_method_call.rb +15 -1
  142. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -1
  143. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  144. data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
  145. data/lib/rubocop/cop/style/redundant_constant_base.rb +85 -0
  146. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +45 -0
  147. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  148. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  149. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  150. data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
  151. data/lib/rubocop/cop/style/require_order.rb +135 -0
  152. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  153. data/lib/rubocop/cop/style/select_by_regexp.rb +13 -5
  154. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  155. data/lib/rubocop/cop/style/semicolon.rb +26 -3
  156. data/lib/rubocop/cop/style/signal_exception.rb +8 -6
  157. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
  158. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  159. data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
  160. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
  161. data/lib/rubocop/cop/style/word_array.rb +41 -0
  162. data/lib/rubocop/cop/style/yoda_expression.rb +81 -0
  163. data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
  164. data/lib/rubocop/cop/team.rb +30 -30
  165. data/lib/rubocop/cop/util.rb +32 -5
  166. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  167. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -1
  168. data/lib/rubocop/cop/variable_force.rb +18 -30
  169. data/lib/rubocop/cops_documentation_generator.rb +33 -11
  170. data/lib/rubocop/directive_comment.rb +1 -1
  171. data/lib/rubocop/file_patterns.rb +43 -0
  172. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  173. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  174. data/lib/rubocop/formatter.rb +4 -1
  175. data/lib/rubocop/options.rb +8 -0
  176. data/lib/rubocop/path_util.rb +50 -22
  177. data/lib/rubocop/result_cache.rb +2 -2
  178. data/lib/rubocop/rspec/cop_helper.rb +4 -1
  179. data/lib/rubocop/rspec/expect_offense.rb +6 -4
  180. data/lib/rubocop/rspec/support.rb +2 -2
  181. data/lib/rubocop/runner.rb +10 -3
  182. data/lib/rubocop/server/cache.rb +3 -1
  183. data/lib/rubocop/server/core.rb +1 -1
  184. data/lib/rubocop/target_finder.rb +1 -1
  185. data/lib/rubocop/target_ruby.rb +1 -2
  186. data/lib/rubocop/version.rb +1 -1
  187. data/lib/rubocop.rb +23 -6
  188. metadata +23 -9
@@ -38,6 +38,10 @@ module RuboCop
38
38
  'a whitespace to the right of the `%<operator>s` if it ' \
39
39
  'should be %<possible>s.'
40
40
 
41
+ def self.autocorrect_incompatible_with
42
+ [Naming::BlockForwarding]
43
+ end
44
+
41
45
  def on_new_investigation
42
46
  processed_source.diagnostics.each do |diagnostic|
43
47
  next unless diagnostic.reason == :ambiguous_prefix
@@ -11,6 +11,10 @@ module RuboCop
11
11
  # an assignment to indicate "I know I'm using an assignment
12
12
  # as a condition. It's not a mistake."
13
13
  #
14
+ # @safety
15
+ # This cop's autocorrection is unsafe because it assumes that
16
+ # the author meant to use an assignment result as a condition.
17
+ #
14
18
  # @example
15
19
  # # bad
16
20
  # if some_var = true
@@ -35,6 +39,8 @@ module RuboCop
35
39
  # end
36
40
  #
37
41
  class AssignmentInCondition < Base
42
+ extend AutoCorrector
43
+
38
44
  include SafeAssignment
39
45
 
40
46
  MSG_WITH_SAFE_ASSIGNMENT_ALLOWED =
@@ -53,7 +59,11 @@ module RuboCop
53
59
  next :skip_children if skip_children?(asgn_node)
54
60
  next if allowed_construct?(asgn_node)
55
61
 
56
- add_offense(asgn_node.loc.operator)
62
+ add_offense(asgn_node.loc.operator) do |corrector|
63
+ next unless safe_assignment_allowed?
64
+
65
+ corrector.wrap(asgn_node, '(', ')')
66
+ end
57
67
  end
58
68
  end
59
69
  alias on_while on_if
@@ -16,6 +16,10 @@ module RuboCop
16
16
  # using the same name a namespace and a class. To avoid too many unnecessary
17
17
  # offenses, Enable this cop with `Only: [The, Constant, Names, Causing, Issues]`
18
18
  #
19
+ # NOTE: `Style/RedundantConstantBase` cop is disabled if this cop is enabled to prevent
20
+ # conflicting rules. Because it respects user configurations that want to enable
21
+ # this cop which is disabled by default.
22
+ #
19
23
  # @example
20
24
  # # By default checks every constant
21
25
  #
@@ -96,8 +96,10 @@ module RuboCop
96
96
  end
97
97
 
98
98
  def debugger_method?(send_node)
99
+ method_name = send_node.method_name
100
+
99
101
  debugger_methods.any? do |method|
100
- next unless method[:method_name] == send_node.method_name
102
+ next unless method[:method_name] == method_name
101
103
 
102
104
  if method[:receiver].nil?
103
105
  send_node.receiver.nil?
@@ -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
@@ -14,7 +14,8 @@ module RuboCop
14
14
  # Alternative: 'alternative_value'
15
15
  # DeprecatedVersion: 'deprecated_version'
16
16
  #
17
- # By default, `NIL`, `TRUE`, `FALSE` and `Random::DEFAULT` are configured.
17
+ # By default, `NIL`, `TRUE`, `FALSE`, `Net::HTTPServerException, `Random::DEFAULT`,
18
+ # `Struct::Group`, and `Struct::Passwd` are configured.
18
19
  #
19
20
  # @example
20
21
  #
@@ -22,13 +23,19 @@ module RuboCop
22
23
  # NIL
23
24
  # TRUE
24
25
  # FALSE
26
+ # Net::HTTPServerException
25
27
  # Random::DEFAULT # Return value of Ruby 2 is `Random` instance, Ruby 3.0 is `Random` class.
28
+ # Struct::Group
29
+ # Struct::Passwd
26
30
  #
27
31
  # # good
28
32
  # nil
29
33
  # true
30
34
  # false
35
+ # Net::HTTPClientException
31
36
  # Random.new # `::DEFAULT` has been deprecated in Ruby 3, `.new` is compatible with Ruby 2.
37
+ # Etc::Group
38
+ # Etc::Passwd
32
39
  #
33
40
  class DeprecatedConstants < Base
34
41
  extend AutoCorrector
@@ -84,8 +84,6 @@ module RuboCop
84
84
  # end
85
85
  #
86
86
  class DuplicateBranch < Base
87
- include RescueNode
88
-
89
87
  MSG = 'Duplicate branch body detected.'
90
88
 
91
89
  def on_branching_statement(node)
@@ -57,19 +57,20 @@ module RuboCop
57
57
  def initialize(config = nil, options = nil)
58
58
  super
59
59
  @definitions = {}
60
+ @scopes = Hash.new { |hash, key| hash[key] = [] }
60
61
  end
61
62
 
62
63
  def on_def(node)
63
64
  # if a method definition is inside an if, it is very likely
64
65
  # that a different definition is used depending on platform, etc.
65
- return if node.ancestors.any?(&:if_type?)
66
+ return if node.each_ancestor.any?(&:if_type?)
66
67
  return if possible_dsl?(node)
67
68
 
68
69
  found_instance_method(node, node.method_name)
69
70
  end
70
71
 
71
72
  def on_defs(node)
72
- return if node.ancestors.any?(&:if_type?)
73
+ return if node.each_ancestor.any?(&:if_type?)
73
74
  return if possible_dsl?(node)
74
75
 
75
76
  if node.receiver.const_type?
@@ -157,16 +158,18 @@ module RuboCop
157
158
 
158
159
  def found_method(node, method_name)
159
160
  key = method_key(node, method_name)
161
+ scope = node.each_ancestor(:rescue, :ensure).first&.type
160
162
 
161
163
  if @definitions.key?(key)
162
- loc = if DEF_TYPES.include?(node.type)
163
- node.loc.keyword.join(node.loc.name)
164
- else
165
- node.loc.expression
166
- end
164
+ if scope && !@scopes[scope].include?(key)
165
+ @definitions[key] = node
166
+ @scopes[scope] << key
167
+ return
168
+ end
169
+
167
170
  message = message_for_dup(node, method_name, key)
168
171
 
169
- add_offense(loc, message: message)
172
+ add_offense(location(node), message: message)
170
173
  else
171
174
  @definitions[key] = node
172
175
  end
@@ -180,6 +183,14 @@ module RuboCop
180
183
  end
181
184
  end
182
185
 
186
+ def location(node)
187
+ if DEF_TYPES.include?(node.type)
188
+ node.loc.keyword.join(node.loc.name)
189
+ else
190
+ node.loc.expression
191
+ end
192
+ end
193
+
183
194
  def on_attr(node, attr_name, args)
184
195
  case attr_name
185
196
  when :attr
@@ -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
@@ -65,7 +65,7 @@ module RuboCop
65
65
 
66
66
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
67
67
  return if node.body
68
- return if allow_empty_lambdas? && lambda_or_proc?(node)
68
+ return if allow_empty_lambdas? && node.lambda_or_proc?
69
69
  return if cop_config['AllowComments'] && allow_comment?(node)
70
70
 
71
71
  add_offense(node)
@@ -88,10 +88,6 @@ module RuboCop
88
88
  regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
89
89
  Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
90
90
  end
91
-
92
- def lambda_or_proc?(node)
93
- node.lambda? || node.proc?
94
- end
95
91
  end
96
92
  end
97
93
  end
@@ -68,7 +68,7 @@ module RuboCop
68
68
  MSG = 'Avoid `%<keyword>s` branches without a body.'
69
69
 
70
70
  def on_if(node)
71
- return if node.body
71
+ return if node.body || same_line?(node.loc.begin, node.loc.end)
72
72
  return if cop_config['AllowComments'] && contains_comments?(node)
73
73
 
74
74
  add_offense(node, message: format(MSG, keyword: node.keyword)) do |corrector|
@@ -80,6 +80,7 @@ module RuboCop
80
80
  num_of_format_args, num_of_expected_fields = count_matches(node)
81
81
 
82
82
  return false if num_of_format_args == :unknown
83
+ return false if num_of_expected_fields.zero? && node.child_nodes.first.dstr_type?
83
84
 
84
85
  matched_arguments_count?(num_of_expected_fields, num_of_format_args)
85
86
  end
@@ -94,8 +95,8 @@ module RuboCop
94
95
 
95
96
  # @!method called_on_string?(node)
96
97
  def_node_matcher :called_on_string?, <<~PATTERN
97
- {(send {nil? const_type?} _ (str _) ...)
98
- (send (str ...) ...)}
98
+ {(send {nil? const_type?} _ {str dstr} ...)
99
+ (send {str dstr} ...)}
99
100
  PATTERN
100
101
 
101
102
  def method_with_format_args?(node)
@@ -143,11 +144,11 @@ module RuboCop
143
144
  return false if node.const_receiver? && !node.receiver.loc.name.is?(KERNEL)
144
145
  return false unless node.method?(name)
145
146
 
146
- node.arguments.size > 1 && node.first_argument.str_type?
147
+ node.arguments.size > 1 && string_type?(node.first_argument)
147
148
  end
148
149
 
149
150
  def expected_fields_count(node)
150
- return :unknown unless node.str_type?
151
+ return :unknown unless string_type?(node)
151
152
 
152
153
  format_string = RuboCop::Cop::Utils::FormatString.new(node.source)
153
154
  return 1 if format_string.named_interpolation?
@@ -172,10 +173,9 @@ module RuboCop
172
173
  def percent?(node)
173
174
  receiver = node.receiver
174
175
 
175
- percent = node.method?(:%) &&
176
- (STRING_TYPES.include?(receiver.type) || node.first_argument.array_type?)
176
+ percent = node.method?(:%) && (string_type?(receiver) || node.first_argument.array_type?)
177
177
 
178
- return false if percent && STRING_TYPES.include?(receiver.type) && heredoc?(node)
178
+ return false if percent && string_type?(receiver) && heredoc?(node)
179
179
 
180
180
  percent
181
181
  end
@@ -188,6 +188,10 @@ module RuboCop
188
188
  format(MSG, arg_num: num_args_for_format, method: method_name,
189
189
  field_num: num_expected_fields)
190
190
  end
191
+
192
+ def string_type?(node)
193
+ STRING_TYPES.include?(node.type)
194
+ end
191
195
  end
192
196
  end
193
197
  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
@@ -6,9 +6,10 @@ module RuboCop
6
6
  # Checks for interpolation in a single quoted string.
7
7
  #
8
8
  # @safety
9
- # This cop is generally safe, but is marked as unsafe because
10
- # it is possible to actually intentionally have text inside
11
- # `#{...}` in a single quoted string.
9
+ # This cop's autocorrection is unsafe because although it always replaces single quotes as
10
+ # if it were miswritten double quotes, it is not always the case. For example,
11
+ # `'#{foo} bar'` would be replaced by `"#{foo} bar"`, so the replaced code would evaluate
12
+ # the expression `foo`.
12
13
  #
13
14
  # @example
14
15
  #
@@ -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
  #
@@ -44,7 +44,6 @@ module RuboCop
44
44
  class NonAtomicFileOperation < Base
45
45
  extend AutoCorrector
46
46
  include Alignment
47
- include RangeHelp
48
47
 
49
48
  MSG_REMOVE_FILE_EXIST_CHECK = 'Remove unnecessary existence check ' \
50
49
  '`%<receiver>s.%<method_name>s`.'
@@ -101,10 +100,11 @@ module RuboCop
101
100
  def register_offense(node, exist_node)
102
101
  add_offense(node, message: message_change_force_method(node)) unless force_method?(node)
103
102
 
104
- range = range_between(node.parent.loc.keyword.begin_pos,
105
- exist_node.loc.expression.end_pos)
103
+ parent = node.parent
104
+ range = parent.loc.keyword.begin.join(parent.condition.source_range.end)
105
+
106
106
  add_offense(range, message: message_remove_file_exist_check(exist_node)) do |corrector|
107
- autocorrect(corrector, node, range) unless node.parent.elsif?
107
+ autocorrect(corrector, node, range) unless parent.elsif?
108
108
  end
109
109
  end
110
110
 
@@ -120,7 +120,12 @@ module RuboCop
120
120
  def autocorrect(corrector, node, range)
121
121
  corrector.remove(range)
122
122
  autocorrect_replace_method(corrector, node)
123
- corrector.remove(node.parent.loc.end) if node.parent.multiline?
123
+
124
+ if node.parent.modifier_form?
125
+ corrector.remove(node.source_range.end.join(node.parent.loc.keyword.begin))
126
+ else
127
+ corrector.remove(node.parent.loc.end)
128
+ end
124
129
  end
125
130
 
126
131
  def autocorrect_replace_method(corrector, node)
@@ -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
 
@@ -40,11 +40,16 @@ module RuboCop
40
40
  unless node.arguments.one? && first_argument_starts_with_left_parenthesis?(node)
41
41
  return true
42
42
  end
43
+ return true if first_argument_block_type?(node.first_argument)
43
44
 
44
45
  node.operator_method? || node.setter_method? || chained_calls?(node) ||
45
46
  valid_first_argument?(node.first_argument)
46
47
  end
47
48
 
49
+ def first_argument_block_type?(first_arg)
50
+ first_arg.block_type? || first_arg.numblock_type?
51
+ end
52
+
48
53
  def valid_first_argument?(first_arg)
49
54
  first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg)
50
55
  end