rubocop 0.90.0 → 0.93.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 (201) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +79 -3
  4. data/lib/rubocop.rb +20 -5
  5. data/lib/rubocop/cached_data.rb +2 -1
  6. data/lib/rubocop/cli/command/execute_runner.rb +8 -0
  7. data/lib/rubocop/comment_config.rb +9 -5
  8. data/lib/rubocop/config_loader.rb +3 -3
  9. data/lib/rubocop/config_regeneration.rb +33 -0
  10. data/lib/rubocop/config_store.rb +3 -3
  11. data/lib/rubocop/cop/bundler/duplicated_gem.rb +5 -1
  12. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -0
  13. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +2 -0
  14. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  15. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
  16. data/lib/rubocop/cop/generator.rb +1 -1
  17. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +1 -0
  18. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +1 -0
  19. data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +1 -0
  20. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -0
  21. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +1 -0
  22. data/lib/rubocop/cop/layout/array_alignment.rb +1 -0
  23. data/lib/rubocop/cop/layout/begin_end_alignment.rb +77 -0
  24. data/lib/rubocop/cop/layout/case_indentation.rb +4 -7
  25. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  26. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  27. data/lib/rubocop/cop/layout/dot_position.rb +6 -9
  28. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
  29. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +4 -12
  30. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +13 -8
  31. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -2
  32. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -2
  33. data/lib/rubocop/cop/layout/end_alignment.rb +5 -10
  34. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +26 -4
  35. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +4 -13
  36. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -7
  37. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
  38. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +6 -21
  39. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +3 -8
  40. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +2 -2
  41. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
  42. data/lib/rubocop/cop/lint/ambiguous_operator.rb +2 -0
  43. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +18 -1
  44. data/lib/rubocop/cop/lint/big_decimal_new.rb +1 -2
  45. data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
  46. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +74 -0
  47. data/lib/rubocop/cop/lint/debugger.rb +2 -3
  48. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -3
  49. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -4
  50. data/lib/rubocop/cop/lint/duplicate_require.rb +7 -2
  51. data/lib/rubocop/cop/lint/duplicate_rescue_exception.rb +2 -4
  52. data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -0
  53. data/lib/rubocop/cop/lint/empty_file.rb +1 -4
  54. data/lib/rubocop/cop/lint/erb_new_arguments.rb +2 -0
  55. data/lib/rubocop/cop/lint/float_comparison.rb +2 -2
  56. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  57. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
  58. data/lib/rubocop/cop/lint/identity_comparison.rb +51 -0
  59. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +2 -5
  60. data/lib/rubocop/cop/lint/inherit_exception.rb +2 -2
  61. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  62. data/lib/rubocop/cop/lint/multiple_comparison.rb +3 -1
  63. data/lib/rubocop/cop/lint/number_conversion.rb +1 -0
  64. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -2
  65. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  66. data/lib/rubocop/cop/lint/raise_exception.rb +1 -0
  67. data/lib/rubocop/cop/lint/rand_one.rb +2 -1
  68. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +22 -12
  69. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +14 -4
  70. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -0
  71. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
  72. data/lib/rubocop/cop/lint/rescue_type.rb +0 -1
  73. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +3 -1
  74. data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -6
  75. data/lib/rubocop/cop/lint/struct_new_override.rb +1 -0
  76. data/lib/rubocop/cop/lint/to_json.rb +16 -5
  77. data/lib/rubocop/cop/lint/unreachable_loop.rb +3 -6
  78. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +3 -1
  79. data/lib/rubocop/cop/lint/uri_regexp.rb +2 -1
  80. data/lib/rubocop/cop/lint/useless_access_modifier.rb +3 -9
  81. data/lib/rubocop/cop/lint/useless_method_definition.rb +20 -27
  82. data/lib/rubocop/cop/lint/useless_times.rb +106 -0
  83. data/lib/rubocop/cop/metrics/block_length.rb +3 -1
  84. data/lib/rubocop/cop/metrics/class_length.rb +14 -6
  85. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +25 -16
  86. data/lib/rubocop/cop/mixin/comments_help.rb +3 -9
  87. data/lib/rubocop/cop/mixin/configurable_naming.rb +2 -2
  88. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
  89. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +9 -0
  90. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -2
  91. data/lib/rubocop/cop/mixin/rescue_node.rb +1 -0
  92. data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -3
  93. data/lib/rubocop/cop/mixin/visibility_help.rb +4 -16
  94. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  95. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  96. data/lib/rubocop/cop/offense.rb +15 -2
  97. data/lib/rubocop/cop/security/eval.rb +1 -0
  98. data/lib/rubocop/cop/security/json_load.rb +1 -0
  99. data/lib/rubocop/cop/security/marshal_load.rb +1 -0
  100. data/lib/rubocop/cop/security/open.rb +1 -0
  101. data/lib/rubocop/cop/security/yaml_load.rb +1 -0
  102. data/lib/rubocop/cop/style/access_modifier_declarations.rb +7 -11
  103. data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
  104. data/lib/rubocop/cop/style/alias.rb +2 -0
  105. data/lib/rubocop/cop/style/array_coercion.rb +4 -0
  106. data/lib/rubocop/cop/style/array_join.rb +1 -0
  107. data/lib/rubocop/cop/style/attr.rb +1 -0
  108. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +2 -0
  109. data/lib/rubocop/cop/style/case_equality.rb +3 -0
  110. data/lib/rubocop/cop/style/case_like_if.rb +20 -4
  111. data/lib/rubocop/cop/style/class_and_module_children.rb +2 -0
  112. data/lib/rubocop/cop/style/class_check.rb +6 -9
  113. data/lib/rubocop/cop/style/class_equality_comparison.rb +64 -0
  114. data/lib/rubocop/cop/style/class_methods_definitions.rb +42 -16
  115. data/lib/rubocop/cop/style/class_vars.rb +1 -2
  116. data/lib/rubocop/cop/style/combinable_loops.rb +13 -11
  117. data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
  118. data/lib/rubocop/cop/style/commented_keyword.rb +7 -8
  119. data/lib/rubocop/cop/style/conditional_assignment.rb +49 -60
  120. data/lib/rubocop/cop/style/date_time.rb +12 -1
  121. data/lib/rubocop/cop/style/dir.rb +1 -0
  122. data/lib/rubocop/cop/style/double_negation.rb +1 -0
  123. data/lib/rubocop/cop/style/empty_literal.rb +3 -1
  124. data/lib/rubocop/cop/style/eval_with_location.rb +1 -3
  125. data/lib/rubocop/cop/style/even_odd.rb +1 -0
  126. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -2
  127. data/lib/rubocop/cop/style/explicit_block_argument.rb +7 -3
  128. data/lib/rubocop/cop/style/float_division.rb +2 -0
  129. data/lib/rubocop/cop/style/for.rb +0 -4
  130. data/lib/rubocop/cop/style/format_string.rb +1 -4
  131. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  132. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +24 -5
  133. data/lib/rubocop/cop/style/hash_transform_keys.rb +5 -11
  134. data/lib/rubocop/cop/style/hash_transform_values.rb +5 -11
  135. data/lib/rubocop/cop/style/if_unless_modifier.rb +0 -4
  136. data/lib/rubocop/cop/style/implicit_runtime_error.rb +1 -0
  137. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -6
  138. data/lib/rubocop/cop/style/lambda_call.rb +3 -1
  139. data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
  140. data/lib/rubocop/cop/style/mixin_usage.rb +8 -27
  141. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -2
  142. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +14 -1
  143. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -0
  144. data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
  145. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  146. data/lib/rubocop/cop/style/non_nil_check.rb +2 -0
  147. data/lib/rubocop/cop/style/not.rb +1 -0
  148. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -3
  149. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -1
  150. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +12 -1
  151. data/lib/rubocop/cop/style/preferred_hash_methods.rb +2 -0
  152. data/lib/rubocop/cop/style/raise_args.rb +2 -3
  153. data/lib/rubocop/cop/style/random_with_offset.rb +4 -3
  154. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -9
  155. data/lib/rubocop/cop/style/redundant_begin.rb +36 -8
  156. data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
  157. data/lib/rubocop/cop/style/redundant_conditional.rb +4 -5
  158. data/lib/rubocop/cop/style/redundant_exception.rb +1 -3
  159. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -0
  160. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -1
  161. data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
  162. data/lib/rubocop/cop/style/redundant_parentheses.rb +14 -6
  163. data/lib/rubocop/cop/style/redundant_percent_q.rb +9 -11
  164. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +39 -24
  165. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
  166. data/lib/rubocop/cop/style/redundant_return.rb +17 -17
  167. data/lib/rubocop/cop/style/redundant_self.rb +7 -9
  168. data/lib/rubocop/cop/style/redundant_self_assignment.rb +2 -2
  169. data/lib/rubocop/cop/style/redundant_sort.rb +12 -29
  170. data/lib/rubocop/cop/style/redundant_sort_by.rb +5 -9
  171. data/lib/rubocop/cop/style/rescue_standard_error.rb +20 -16
  172. data/lib/rubocop/cop/style/safe_navigation.rb +5 -0
  173. data/lib/rubocop/cop/style/sample.rb +2 -1
  174. data/lib/rubocop/cop/style/send.rb +2 -3
  175. data/lib/rubocop/cop/style/signal_exception.rb +2 -0
  176. data/lib/rubocop/cop/style/single_argument_dig.rb +1 -0
  177. data/lib/rubocop/cop/style/slicing_with_range.rb +2 -1
  178. data/lib/rubocop/cop/style/stderr_puts.rb +1 -0
  179. data/lib/rubocop/cop/style/string_concatenation.rb +17 -3
  180. data/lib/rubocop/cop/style/strip.rb +1 -0
  181. data/lib/rubocop/cop/style/ternary_parentheses.rb +2 -3
  182. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +4 -3
  183. data/lib/rubocop/cop/style/unpack_first.rb +1 -0
  184. data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -5
  185. data/lib/rubocop/cop/util.rb +0 -1
  186. data/lib/rubocop/cop/variable_force/branch.rb +0 -4
  187. data/lib/rubocop/core_ext/string.rb +1 -1
  188. data/lib/rubocop/directive_comment.rb +32 -0
  189. data/lib/rubocop/ext/regexp_node.rb +23 -7
  190. data/lib/rubocop/formatter/disabled_config_formatter.rb +12 -5
  191. data/lib/rubocop/options.rb +37 -17
  192. data/lib/rubocop/result_cache.rb +38 -15
  193. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  194. data/lib/rubocop/rspec/expect_offense.rb +5 -5
  195. data/lib/rubocop/runner.rb +37 -18
  196. data/lib/rubocop/target_finder.rb +27 -26
  197. data/lib/rubocop/target_ruby.rb +1 -1
  198. data/lib/rubocop/version.rb +6 -1
  199. metadata +19 -18
  200. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
  201. data/lib/rubocop/cop/tokens_util.rb +0 -84
@@ -35,7 +35,6 @@ module RuboCop
35
35
  # baz
36
36
  # end
37
37
  class RescueType < Base
38
- include RescueNode
39
38
  extend AutoCorrector
40
39
 
41
40
  MSG = 'Rescuing from `%<invalid_exceptions>s` will raise a ' \
@@ -40,10 +40,12 @@ module RuboCop
40
40
 
41
41
  MSG = 'Use `%<method>s %<module_name>s` instead of `%<bad_method>s`.'
42
42
  MIXIN_METHODS = %i[include prepend extend].freeze
43
+ SEND_METHODS = %i[send public_send __send__].freeze
44
+ RESTRICT_ON_SEND = SEND_METHODS
43
45
 
44
46
  def_node_matcher :send_with_mixin_argument?, <<~PATTERN
45
47
  (send
46
- (const _ _) {:send :public_send :__send__}
48
+ (const _ _) {:#{SEND_METHODS.join(' :')}}
47
49
  ({sym str} $#mixin_method?)
48
50
  $(const _ _))
49
51
  PATTERN
@@ -75,8 +75,7 @@ module RuboCop
75
75
 
76
76
  def rescued_groups_for(rescues)
77
77
  rescues.map do |group|
78
- rescue_group, = *group
79
- evaluate_exceptions(rescue_group)
78
+ evaluate_exceptions(group)
80
79
  end
81
80
  end
82
81
 
@@ -117,14 +116,15 @@ module RuboCop
117
116
  $VERBOSE = old_verbose
118
117
  end
119
118
 
120
- def evaluate_exceptions(rescue_group)
121
- if rescue_group
122
- rescued_exceptions = rescued_exceptions(rescue_group)
119
+ def evaluate_exceptions(group)
120
+ rescued_exceptions = group.exceptions
121
+
122
+ if rescued_exceptions.any?
123
123
  rescued_exceptions.each_with_object([]) do |exception, converted|
124
124
  begin
125
125
  silence_warnings do
126
126
  # Avoid printing deprecation warnings about constants
127
- converted << Kernel.const_get(exception)
127
+ converted << Kernel.const_get(exception.source)
128
128
  end
129
129
  rescue NameError
130
130
  converted << nil
@@ -24,6 +24,7 @@ module RuboCop
24
24
  class StructNewOverride < Base
25
25
  MSG = '`%<member_name>s` member overrides `Struct#%<method_name>s`' \
26
26
  ' and it may be unexpected.'
27
+ RESTRICT_ON_SEND = %i[new].freeze
27
28
 
28
29
  STRUCT_METHOD_NAMES = Struct.instance_methods
29
30
  STRUCT_MEMBER_NAME_TYPES = %i[sym str].freeze
@@ -9,12 +9,23 @@ module RuboCop
9
9
  # for an optional argument, your method should too.
10
10
  #
11
11
  # @example
12
- # # bad
13
- # def to_json
14
- # end
12
+ # class Point
13
+ # attr_reader :x, :y
14
+ #
15
+ # # bad, incorrect arity
16
+ # def to_json
17
+ # JSON.generate([x, y])
18
+ # end
19
+ #
20
+ # # good, preserving args
21
+ # def to_json(*args)
22
+ # JSON.generate([x, y], *args)
23
+ # end
15
24
  #
16
- # # good
17
- # def to_json(*_args)
25
+ # # good, discarding args
26
+ # def to_json(*_args)
27
+ # JSON.generate([x, y])
28
+ # end
18
29
  # end
19
30
  #
20
31
  class ToJSON < Base
@@ -130,7 +130,8 @@ module RuboCop
130
130
  case node.type
131
131
  when :begin, :kwbegin
132
132
  statements = *node
133
- statements.any? { |statement| break_statement?(statement) }
133
+ break_statement = statements.find { |statement| break_statement?(statement) }
134
+ break_statement && !preceded_by_continue_statement?(break_statement)
134
135
  when :if
135
136
  check_if(node)
136
137
  when :case
@@ -158,16 +159,12 @@ module RuboCop
158
159
  end
159
160
 
160
161
  def preceded_by_continue_statement?(break_statement)
161
- left_siblings_of(break_statement).any? do |sibling|
162
+ break_statement.left_siblings.any? do |sibling|
162
163
  next if sibling.loop_keyword? || loop_method?(sibling)
163
164
 
164
165
  sibling.each_descendant(:next, :redo).any?
165
166
  end
166
167
  end
167
-
168
- def left_siblings_of(node)
169
- node.parent.children[0, node.sibling_index]
170
- end
171
168
  end
172
169
  end
173
170
  end
@@ -44,10 +44,12 @@ module RuboCop
44
44
  MSG = '`%<uri_method>s` method is obsolete and should not be used. ' \
45
45
  'Instead, use %<replacements>s depending on your specific use ' \
46
46
  'case.'
47
+ METHOD_NAMES = %i[escape encode unescape decode].freeze
48
+ RESTRICT_ON_SEND = METHOD_NAMES
47
49
 
48
50
  def_node_matcher :uri_escape_unescape?, <<~PATTERN
49
51
  (send
50
- (const ${nil? cbase} :URI) ${:escape :encode :unescape :decode}
52
+ (const ${nil? cbase} :URI) ${:#{METHOD_NAMES.join(' :')}}
51
53
  ...)
52
54
  PATTERN
53
55
 
@@ -18,9 +18,10 @@ module RuboCop
18
18
 
19
19
  MSG = '`%<current>s` is obsolete and should not be used. Instead, use `%<preferred>s`.'
20
20
  URI_CONSTANTS = ['URI', '::URI'].freeze
21
+ RESTRICT_ON_SEND = %i[regexp].freeze
21
22
 
22
23
  def on_send(node)
23
- return unless node.method?(:regexp) && node.receiver
24
+ return unless node.receiver
24
25
  return unless URI_CONSTANTS.include?(node.receiver.source)
25
26
 
26
27
  argument = node.first_argument ? "(#{node.first_argument.source})" : ''
@@ -131,12 +131,10 @@ module RuboCop
131
131
  MSG = 'Useless `%<current>s` access modifier.'
132
132
 
133
133
  def on_class(node)
134
- check_node(node.children[2]) # class body
135
- end
136
-
137
- def on_module(node)
138
- check_node(node.children[1]) # module body
134
+ check_node(node.body)
139
135
  end
136
+ alias on_module on_class
137
+ alias on_sclass on_class
140
138
 
141
139
  def on_block(node)
142
140
  return unless eval_call?(node)
@@ -144,10 +142,6 @@ module RuboCop
144
142
  check_node(node.body)
145
143
  end
146
144
 
147
- def on_sclass(node)
148
- check_node(node.children[1]) # singleton class body
149
- end
150
-
151
145
  private
152
146
 
153
147
  def autocorrect(corrector, node)
@@ -12,32 +12,26 @@ module RuboCop
12
12
  # @example
13
13
  # # bad
14
14
  # def initialize
15
+ # super
15
16
  # end
16
17
  #
17
18
  # def method
18
19
  # super
19
20
  # end
20
21
  #
21
- # # good
22
- # def initialize
23
- # initialize_internals
24
- # end
25
- #
26
- # def method
22
+ # # good - with default arguments
23
+ # def initialize(x = Object.new)
27
24
  # super
28
- # do_something_else
29
25
  # end
30
26
  #
31
- # @example AllowComments: true (default)
32
27
  # # good
33
28
  # def initialize
34
- # # Comment.
29
+ # super
30
+ # initialize_internals
35
31
  # end
36
32
  #
37
- # @example AllowComments: false
38
- # # bad
39
- # def initialize
40
- # # Comment.
33
+ # def method(*args)
34
+ # super(:extra_arg, *args)
41
35
  # end
42
36
  #
43
37
  class UselessMethodDefinition < Base
@@ -46,8 +40,8 @@ module RuboCop
46
40
  MSG = 'Useless method definition detected.'
47
41
 
48
42
  def on_def(node)
49
- return unless (constructor?(node) && empty_constructor?(node)) ||
50
- delegating?(node.body, node)
43
+ return if optional_args?(node)
44
+ return unless delegating?(node.body, node)
51
45
 
52
46
  add_offense(node) { |corrector| corrector.remove(node) }
53
47
  end
@@ -55,21 +49,20 @@ module RuboCop
55
49
 
56
50
  private
57
51
 
58
- def empty_constructor?(node)
59
- return false if node.body
60
- return false if cop_config['AllowComments'] && comment_lines?(node)
61
-
62
- true
63
- end
64
-
65
- def constructor?(node)
66
- node.def_type? && node.method?(:initialize)
52
+ def optional_args?(node)
53
+ node.arguments.any? { |arg| arg.optarg_type? || arg.kwoptarg_type? }
67
54
  end
68
55
 
69
56
  def delegating?(node, def_node)
70
- return false unless node&.super_type? || node&.zsuper_type?
71
-
72
- !node.arguments? || node.arguments.map(&:source) == def_node.arguments.map(&:source)
57
+ if node.nil?
58
+ false
59
+ elsif node.zsuper_type?
60
+ true
61
+ elsif node.super_type?
62
+ node.arguments.map(&:source) == def_node.arguments.map(&:source)
63
+ else
64
+ false
65
+ end
73
66
  end
74
67
  end
75
68
  end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for uses of `Integer#times` that will never yield
7
+ # (when the integer <= 0) or that will only ever yield once
8
+ # (`1.times`).
9
+ #
10
+ # This cop is marked as unsafe as `times` returns its receiver, which
11
+ # is *usually* OK, but might change behavior.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # -5.times { do_something }
16
+ # 0.times { do_something }
17
+ # 1.times { do_something }
18
+ # 1.times { |i| do_something(i) }
19
+ #
20
+ # # good
21
+ # do_something
22
+ # do_something(1)
23
+ class UselessTimes < Base
24
+ include RangeHelp
25
+ extend AutoCorrector
26
+
27
+ MSG = 'Useless call to `%<count>i.times` detected.'
28
+ RESTRICT_ON_SEND = %i[times].freeze
29
+
30
+ def_node_matcher :times_call?, <<~PATTERN
31
+ (send (int $_) :times (block-pass (sym $_))?)
32
+ PATTERN
33
+
34
+ def_node_matcher :block_arg, <<~PATTERN
35
+ (block _ (args (arg $_)) ...)
36
+ PATTERN
37
+
38
+ def_node_search :block_reassigns_arg?, <<~PATTERN
39
+ (lvasgn %)
40
+ PATTERN
41
+
42
+ def on_send(node)
43
+ return unless (count, proc_name = times_call?(node))
44
+ return if count > 1
45
+
46
+ # Get the block node if applicable
47
+ node = node.block_node if node.block_literal?
48
+
49
+ add_offense(node, message: format(MSG, count: count)) do |corrector|
50
+ next unless own_line?(node)
51
+
52
+ if never_process?(count, node)
53
+ remove_node(corrector, node)
54
+ elsif !proc_name.empty?
55
+ autocorrect_block_pass(corrector, node, proc_name)
56
+ else
57
+ autocorrect_block(corrector, node)
58
+ end
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def never_process?(count, node)
65
+ count < 1 || node.block_type? && node.body.nil?
66
+ end
67
+
68
+ def remove_node(corrector, node)
69
+ corrector.remove(range_by_whole_lines(node.loc.expression, include_final_newline: true))
70
+ end
71
+
72
+ def autocorrect_block_pass(corrector, node, proc_name)
73
+ corrector.replace(node, proc_name)
74
+ end
75
+
76
+ def autocorrect_block(corrector, node)
77
+ block_arg = block_arg(node)
78
+ return if block_reassigns_arg?(node, block_arg)
79
+
80
+ source = node.body.source
81
+ source.gsub!(/\b#{block_arg}\b/, '1') if block_arg
82
+
83
+ corrector.replace(node, fix_indentation(source, node.loc.column...node.body.loc.column))
84
+ end
85
+
86
+ def fix_indentation(source, range)
87
+ # Cleanup indentation in a multiline block
88
+ source_lines = source.split("\n")
89
+
90
+ source_lines[1..-1].each do |line|
91
+ next if line.empty?
92
+
93
+ line[range] = ''
94
+ end
95
+ source_lines.join("\n")
96
+ end
97
+
98
+ def own_line?(node)
99
+ # If there is anything else on the line other than whitespace,
100
+ # don't try to autocorrect
101
+ processed_source.buffer.source_line(node.loc.line)[0...node.loc.column] !~ /\S/
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -29,6 +29,8 @@ module RuboCop
29
29
  # content.
30
30
  # HEREDOC
31
31
  # end # 5 points
32
+ #
33
+ # NOTE: This cop does not apply for `Struct` definitions.
32
34
  class BlockLength < Base
33
35
  include CodeLength
34
36
 
@@ -36,7 +38,7 @@ module RuboCop
36
38
 
37
39
  def on_block(node)
38
40
  return if excluded_method?(node)
39
- return if node.class_constructor?
41
+ return if node.class_constructor? || node.struct_constructor?
40
42
 
41
43
  check_code_length(node)
42
44
  end
@@ -29,6 +29,8 @@ module RuboCop
29
29
  # HEREDOC
30
30
  # end # 5 points
31
31
  #
32
+ #
33
+ # NOTE: This cop also applies for `Struct` definitions.
32
34
  class ClassLength < Base
33
35
  include CodeLength
34
36
 
@@ -37,17 +39,23 @@ module RuboCop
37
39
  end
38
40
 
39
41
  def on_casgn(node)
40
- class_definition?(node) do
41
- check_code_length(node)
42
+ parent = node.parent
43
+
44
+ if parent&.assignment?
45
+ block_node = parent.children[1]
46
+ elsif parent&.parent&.masgn_type?
47
+ block_node = parent.parent.children[1]
48
+ else
49
+ _scope, _name, block_node = *node
42
50
  end
51
+
52
+ return unless block_node.respond_to?(:class_definition?) && block_node.class_definition?
53
+
54
+ check_code_length(block_node)
43
55
  end
44
56
 
45
57
  private
46
58
 
47
- def_node_matcher :class_definition?, <<~PATTERN
48
- (casgn nil? _ (block (send (const {nil? cbase} :Class) :new) ...))
49
- PATTERN
50
-
51
59
  def message(length, max_length)
52
60
  format('Class has too many lines. [%<length>d/%<max>d]',
53
61
  length: length,
@@ -81,40 +81,49 @@ module RuboCop
81
81
  private
82
82
 
83
83
  def assignment?(node)
84
+ return compound_assignment(node) if node.masgn_type? || node.shorthand_asgn?
85
+
84
86
  node.for_type? ||
85
- node.op_asgn_type? ||
86
87
  (node.respond_to?(:setter_method?) && node.setter_method?) ||
87
- (simple_assignment?(node) && capturing_variable?(node.children.first))
88
+ simple_assignment?(node) ||
89
+ argument?(node)
88
90
  end
89
91
 
90
- def simple_assignment?(node)
91
- return false if node.masgn_type?
92
+ def compound_assignment(node)
93
+ # Methods setter can not be detected for multiple assignments
94
+ # and shorthand assigns, so we'll count them here instead
95
+ children = node.masgn_type? ? node.children[0].children : node.children
92
96
 
93
- if node.equals_asgn?
94
- reset_on_lvasgn(node) if node.lvasgn_type?
95
- return true
97
+ will_be_miscounted = children.count do |child|
98
+ child.respond_to?(:setter_method?) &&
99
+ !child.setter_method?
96
100
  end
101
+ @assignment += will_be_miscounted
97
102
 
98
- argument?(node)
103
+ false
99
104
  end
100
105
 
101
- def capturing_variable?(name)
102
- name && !/^_/.match?(name)
106
+ def simple_assignment?(node)
107
+ if !node.equals_asgn?
108
+ false
109
+ elsif node.lvasgn_type?
110
+ reset_on_lvasgn(node)
111
+ capturing_variable?(node.children.first)
112
+ else
113
+ true
114
+ end
103
115
  end
104
116
 
105
- # Returns true for nodes which otherwise would be counted
106
- # as one too many assignment
107
- def assignment_doubled_in_ast?(node)
108
- node.masgn_type? || node.or_asgn_type? || node.and_asgn_type?
117
+ def capturing_variable?(name)
118
+ name && !/^_/.match?(name)
109
119
  end
110
120
 
111
121
  def branch?(node)
112
122
  BRANCH_NODES.include?(node.type)
113
123
  end
114
124
 
115
- # TODO: move to rubocop-ast
116
125
  def argument?(node)
117
- ARGUMENT_TYPES.include?(node.type)
126
+ ARGUMENT_TYPES.include?(node.type) && capturing_variable?(node.children.first)
118
127
  end
119
128
 
120
129
  def condition?(node)