rubocop 0.42.0 → 0.43.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/assets/output.html.erb +21 -10
  4. data/config/default.yml +32 -2
  5. data/config/disabled.yml +8 -1
  6. data/config/enabled.yml +40 -12
  7. data/lib/rubocop.rb +14 -2
  8. data/lib/rubocop/ast_node.rb +2 -0
  9. data/lib/rubocop/cached_data.rb +13 -11
  10. data/lib/rubocop/cli.rb +5 -5
  11. data/lib/rubocop/config.rb +68 -24
  12. data/lib/rubocop/config_loader.rb +13 -11
  13. data/lib/rubocop/config_loader_resolver.rb +4 -2
  14. data/lib/rubocop/cop/cop.rb +16 -5
  15. data/lib/rubocop/cop/lint/assignment_in_condition.rb +21 -20
  16. data/lib/rubocop/cop/lint/block_alignment.rb +3 -4
  17. data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -3
  18. data/lib/rubocop/cop/lint/duplicate_methods.rb +16 -6
  19. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  20. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  21. data/lib/rubocop/cop/lint/end_alignment.rb +4 -6
  22. data/lib/rubocop/cop/lint/eval.rb +1 -1
  23. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  24. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +8 -8
  25. data/lib/rubocop/cop/lint/inherit_exception.rb +22 -7
  26. data/lib/rubocop/cop/lint/literal_in_condition.rb +5 -5
  27. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +3 -5
  28. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  29. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +9 -8
  30. data/lib/rubocop/cop/lint/percent_string_array.rb +17 -6
  31. data/lib/rubocop/cop/lint/percent_symbol_array.rb +4 -4
  32. data/lib/rubocop/cop/lint/rand_one.rb +3 -3
  33. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -3
  34. data/lib/rubocop/cop/lint/shadowed_exception.rb +39 -44
  35. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +2 -2
  36. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +1 -2
  37. data/lib/rubocop/cop/lint/unified_integer.rb +38 -0
  38. data/lib/rubocop/cop/lint/unneeded_disable.rb +51 -38
  39. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +114 -0
  40. data/lib/rubocop/cop/lint/useless_assignment.rb +25 -12
  41. data/lib/rubocop/cop/lint/useless_setter_call.rb +27 -28
  42. data/lib/rubocop/cop/lint/void.rb +2 -4
  43. data/lib/rubocop/cop/mixin/access_modifier_node.rb +5 -5
  44. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +19 -17
  45. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +3 -5
  46. data/lib/rubocop/cop/mixin/configurable_naming.rb +4 -5
  47. data/lib/rubocop/cop/mixin/configurable_numbering.rb +52 -0
  48. data/lib/rubocop/cop/mixin/def_node.rb +28 -0
  49. data/lib/rubocop/cop/mixin/documentation_comment.rb +41 -0
  50. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +18 -13
  51. data/lib/rubocop/cop/mixin/if_node.rb +6 -0
  52. data/lib/rubocop/cop/mixin/match_range.rb +2 -5
  53. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  54. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +40 -28
  55. data/lib/rubocop/cop/mixin/negative_conditional.rb +6 -6
  56. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -5
  57. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +14 -4
  58. data/lib/rubocop/cop/mixin/safe_mode.rb +23 -0
  59. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +2 -4
  60. data/lib/rubocop/cop/mixin/space_inside.rb +1 -3
  61. data/lib/rubocop/cop/mixin/statement_modifier.rb +30 -20
  62. data/lib/rubocop/cop/mixin/trailing_comma.rb +19 -17
  63. data/lib/rubocop/cop/performance/case_when_splat.rb +16 -41
  64. data/lib/rubocop/cop/performance/casecmp.rb +28 -16
  65. data/lib/rubocop/cop/performance/count.rb +58 -34
  66. data/lib/rubocop/cop/performance/detect.rb +3 -7
  67. data/lib/rubocop/cop/performance/double_start_end_with.rb +17 -13
  68. data/lib/rubocop/cop/performance/fixed_size.rb +19 -14
  69. data/lib/rubocop/cop/performance/flat_map.rb +16 -9
  70. data/lib/rubocop/cop/performance/hash_each.rb +2 -3
  71. data/lib/rubocop/cop/performance/lstrip_rstrip.rb +4 -6
  72. data/lib/rubocop/cop/performance/redundant_match.rb +4 -1
  73. data/lib/rubocop/cop/performance/redundant_merge.rb +63 -32
  74. data/lib/rubocop/cop/performance/redundant_sort_by.rb +8 -7
  75. data/lib/rubocop/cop/performance/reverse_each.rb +1 -4
  76. data/lib/rubocop/cop/performance/size.rb +21 -8
  77. data/lib/rubocop/cop/performance/sort_with_block.rb +54 -0
  78. data/lib/rubocop/cop/performance/string_replacement.rb +3 -7
  79. data/lib/rubocop/cop/rails/delegate.rb +2 -3
  80. data/lib/rubocop/cop/rails/find_by.rb +4 -8
  81. data/lib/rubocop/cop/rails/not_null_column.rb +45 -0
  82. data/lib/rubocop/cop/rails/request_referer.rb +3 -3
  83. data/lib/rubocop/cop/rails/safe_navigation.rb +89 -0
  84. data/lib/rubocop/cop/rails/save_bang.rb +78 -9
  85. data/lib/rubocop/cop/rails/scope_args.rb +3 -1
  86. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +2 -3
  87. data/lib/rubocop/cop/rails/validation.rb +1 -1
  88. data/lib/rubocop/cop/security/json_load.rb +36 -0
  89. data/lib/rubocop/cop/style/alias.rb +1 -1
  90. data/lib/rubocop/cop/style/align_hash.rb +25 -14
  91. data/lib/rubocop/cop/style/and_or.rb +13 -3
  92. data/lib/rubocop/cop/style/array_join.rb +3 -3
  93. data/lib/rubocop/cop/style/ascii_comments.rb +1 -2
  94. data/lib/rubocop/cop/style/ascii_identifiers.rb +1 -2
  95. data/lib/rubocop/cop/style/attr.rb +1 -3
  96. data/lib/rubocop/cop/style/block_comments.rb +2 -6
  97. data/lib/rubocop/cop/style/block_delimiters.rb +35 -21
  98. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +4 -4
  99. data/lib/rubocop/cop/style/case_indentation.rb +1 -3
  100. data/lib/rubocop/cop/style/class_methods.rb +3 -4
  101. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  102. data/lib/rubocop/cop/style/command_literal.rb +15 -8
  103. data/lib/rubocop/cop/style/comment_annotation.rb +1 -2
  104. data/lib/rubocop/cop/style/conditional_assignment.rb +68 -36
  105. data/lib/rubocop/cop/style/copyright.rb +1 -5
  106. data/lib/rubocop/cop/style/def_with_parentheses.rb +3 -5
  107. data/lib/rubocop/cop/style/documentation.rb +28 -56
  108. data/lib/rubocop/cop/style/documentation_method.rb +80 -0
  109. data/lib/rubocop/cop/style/each_for_simple_loop.rb +6 -5
  110. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  111. data/lib/rubocop/cop/style/else_alignment.rb +10 -9
  112. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -4
  113. data/lib/rubocop/cop/style/empty_else.rb +1 -4
  114. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -3
  115. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +2 -5
  116. data/lib/rubocop/cop/style/encoding.rb +28 -14
  117. data/lib/rubocop/cop/style/even_odd.rb +28 -17
  118. data/lib/rubocop/cop/style/extra_spacing.rb +36 -25
  119. data/lib/rubocop/cop/style/file_name.rb +19 -10
  120. data/lib/rubocop/cop/style/first_parameter_indentation.rb +2 -3
  121. data/lib/rubocop/cop/style/for.rb +12 -8
  122. data/lib/rubocop/cop/style/format_string.rb +1 -1
  123. data/lib/rubocop/cop/style/guard_clause.rb +22 -56
  124. data/lib/rubocop/cop/style/hash_syntax.rb +72 -7
  125. data/lib/rubocop/cop/style/if_unless_modifier.rb +23 -19
  126. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +3 -3
  127. data/lib/rubocop/cop/style/indentation_width.rb +30 -16
  128. data/lib/rubocop/cop/style/infinite_loop.rb +16 -13
  129. data/lib/rubocop/cop/style/initial_indentation.rb +23 -18
  130. data/lib/rubocop/cop/style/inline_comment.rb +16 -3
  131. data/lib/rubocop/cop/style/lambda.rb +22 -10
  132. data/lib/rubocop/cop/style/leading_comment_space.rb +12 -1
  133. data/lib/rubocop/cop/style/line_end_concatenation.rb +24 -6
  134. data/lib/rubocop/cop/style/method_call_parentheses.rb +18 -9
  135. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  136. data/lib/rubocop/cop/style/method_def_parentheses.rb +3 -4
  137. data/lib/rubocop/cop/style/method_missing.rb +10 -2
  138. data/lib/rubocop/cop/style/module_function.rb +14 -6
  139. data/lib/rubocop/cop/style/multiline_assignment_layout.rb +2 -5
  140. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -5
  141. data/lib/rubocop/cop/style/multiline_block_layout.rb +22 -15
  142. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +9 -0
  143. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +41 -20
  144. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +6 -6
  145. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +3 -5
  146. data/lib/rubocop/cop/style/mutable_constant.rb +21 -13
  147. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  148. data/lib/rubocop/cop/style/negated_while.rb +3 -3
  149. data/lib/rubocop/cop/style/nested_modifier.rb +2 -4
  150. data/lib/rubocop/cop/style/next.rb +4 -4
  151. data/lib/rubocop/cop/style/non_nil_check.rb +18 -10
  152. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +8 -0
  153. data/lib/rubocop/cop/style/numeric_predicate.rb +9 -9
  154. data/lib/rubocop/cop/style/one_line_conditional.rb +11 -1
  155. data/lib/rubocop/cop/style/op_method.rb +1 -1
  156. data/lib/rubocop/cop/style/option_hash.rb +8 -8
  157. data/lib/rubocop/cop/style/optional_arguments.rb +21 -8
  158. data/lib/rubocop/cop/style/parallel_assignment.rb +51 -35
  159. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  160. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  161. data/lib/rubocop/cop/style/raise_args.rb +2 -2
  162. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  163. data/lib/rubocop/cop/style/redundant_parentheses.rb +26 -15
  164. data/lib/rubocop/cop/style/redundant_return.rb +5 -5
  165. data/lib/rubocop/cop/style/redundant_self.rb +20 -11
  166. data/lib/rubocop/cop/style/regexp_literal.rb +16 -10
  167. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +8 -6
  168. data/lib/rubocop/cop/style/safe_navigation.rb +125 -0
  169. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  170. data/lib/rubocop/cop/style/semicolon.rb +9 -10
  171. data/lib/rubocop/cop/style/signal_exception.rb +2 -4
  172. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  173. data/lib/rubocop/cop/style/single_line_methods.rb +18 -11
  174. data/lib/rubocop/cop/style/space_after_method_name.rb +2 -3
  175. data/lib/rubocop/cop/style/space_after_not.rb +4 -6
  176. data/lib/rubocop/cop/style/space_around_block_parameters.rb +1 -2
  177. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +1 -3
  178. data/lib/rubocop/cop/style/space_around_operators.rb +21 -16
  179. data/lib/rubocop/cop/style/space_before_block_braces.rb +2 -12
  180. data/lib/rubocop/cop/style/space_before_first_arg.rb +1 -3
  181. data/lib/rubocop/cop/style/space_inside_array_percent_literal.rb +1 -1
  182. data/lib/rubocop/cop/style/space_inside_block_braces.rb +33 -40
  183. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +38 -23
  184. data/lib/rubocop/cop/style/space_inside_percent_literal_delimiters.rb +1 -1
  185. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +26 -12
  186. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -4
  187. data/lib/rubocop/cop/style/symbol_array.rb +10 -10
  188. data/lib/rubocop/cop/style/symbol_proc.rb +28 -13
  189. data/lib/rubocop/cop/style/ternary_parentheses.rb +35 -5
  190. data/lib/rubocop/cop/style/trailing_blank_lines.rb +2 -4
  191. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +29 -17
  192. data/lib/rubocop/cop/style/trivial_accessors.rb +6 -6
  193. data/lib/rubocop/cop/style/unless_else.rb +2 -6
  194. data/lib/rubocop/cop/style/unneeded_capital_w.rb +8 -4
  195. data/lib/rubocop/cop/style/unneeded_interpolation.rb +4 -5
  196. data/lib/rubocop/cop/style/unneeded_percent_q.rb +13 -7
  197. data/lib/rubocop/cop/style/variable_number.rb +79 -0
  198. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  199. data/lib/rubocop/cop/style/word_array.rb +25 -15
  200. data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -0
  201. data/lib/rubocop/cop/util.rb +23 -4
  202. data/lib/rubocop/cop/variable_force.rb +59 -25
  203. data/lib/rubocop/cop/variable_force/locatable.rb +8 -6
  204. data/lib/rubocop/cop/variable_force/variable.rb +2 -2
  205. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  206. data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -11
  207. data/lib/rubocop/formatter/formatter_set.rb +12 -10
  208. data/lib/rubocop/formatter/worst_offenders_formatter.rb +4 -4
  209. data/lib/rubocop/node_pattern.rb +79 -35
  210. data/lib/rubocop/options.rb +4 -4
  211. data/lib/rubocop/processed_source.rb +9 -5
  212. data/lib/rubocop/remote_config.rb +14 -10
  213. data/lib/rubocop/result_cache.rb +14 -6
  214. data/lib/rubocop/runner.rb +55 -34
  215. data/lib/rubocop/string_util.rb +9 -5
  216. data/lib/rubocop/target_finder.rb +1 -1
  217. data/lib/rubocop/token.rb +1 -1
  218. data/lib/rubocop/version.rb +1 -1
  219. metadata +15 -4
  220. data/lib/rubocop/cop/lint/useless_array_splat.rb +0 -56
  221. data/lib/rubocop/cop/performance/push_splat.rb +0 -47
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Lint
7
+ # This cop checks for using Fixnum or Bignum constant.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # 1.is_a?(Fixnum)
12
+ # 1.is_a?(Bignum)
13
+ #
14
+ # # good
15
+ # 1.is_a?(Integer)
16
+ class UnifiedInteger < Cop
17
+ MSG = 'Use `Integer` instead of `%s`.'.freeze
18
+
19
+ def_node_matcher :fixnum_or_bignum_const?, <<-PATTERN
20
+ (:const {nil (:cbase)} ${:Fixnum :Bignum})
21
+ PATTERN
22
+
23
+ def on_const(node)
24
+ klass = fixnum_or_bignum_const?(node)
25
+ return unless klass
26
+
27
+ add_offense(node, :expression, format(MSG, klass))
28
+ end
29
+
30
+ def autocorrect(node)
31
+ lambda do |corrector|
32
+ corrector.replace(node.loc.name, 'Integer')
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -33,30 +33,11 @@ module RuboCop
33
33
  lambda do |corrector|
34
34
  ranges, range = *args # Ranges are sorted by position.
35
35
 
36
- if range.source.start_with?('#')
37
- # Eat the entire comment, the preceding space, and the preceding
38
- # newline if there is one.
39
- original_begin = range.begin_pos
40
- range = range_with_surrounding_space(range, :left, true)
41
- range = range_with_surrounding_space(range, :right,
42
- # Special for a comment that
43
- # begins the file: remove
44
- # the newline at the end.
45
- original_begin.zero?)
46
- else
47
- # Is there any cop between this one and the end of the line, which
48
- # is NOT being removed?
49
-
50
- if ends_its_line?(ranges.last) && trailing_range?(ranges, range)
51
- # Eat the comma on the left.
52
- range = range_with_surrounding_space(range, :left)
53
- range = range_with_surrounding_comma(range, :left)
54
- end
55
-
56
- range = range_with_surrounding_comma(range, :right)
57
- # Eat following spaces up to EOL, but not the newline itself.
58
- range = range_with_surrounding_space(range, :right, false)
59
- end
36
+ range = if range.source.start_with?('#')
37
+ comment_range_with_surrounding_space(range)
38
+ else
39
+ directive_range_in_list(range, ranges)
40
+ end
60
41
 
61
42
  corrector.remove(range)
62
43
  end
@@ -64,6 +45,32 @@ module RuboCop
64
45
 
65
46
  private
66
47
 
48
+ def comment_range_with_surrounding_space(range)
49
+ # Eat the entire comment, the preceding space, and the preceding
50
+ # newline if there is one.
51
+ original_begin = range.begin_pos
52
+ range = range_with_surrounding_space(range, :left, true)
53
+ range_with_surrounding_space(range, :right,
54
+ # Special for a comment that
55
+ # begins the file: remove
56
+ # the newline at the end.
57
+ original_begin.zero?)
58
+ end
59
+
60
+ def directive_range_in_list(range, ranges)
61
+ # Is there any cop between this one and the end of the line, which
62
+ # is NOT being removed?
63
+ if ends_its_line?(ranges.last) && trailing_range?(ranges, range)
64
+ # Eat the comma on the left.
65
+ range = range_with_surrounding_space(range, :left)
66
+ range = range_with_surrounding_comma(range, :left)
67
+ end
68
+
69
+ range = range_with_surrounding_comma(range, :right)
70
+ # Eat following spaces up to EOL, but not the newline itself.
71
+ range_with_surrounding_space(range, :right, false)
72
+ end
73
+
67
74
  def each_unneeded_disable(cop_disabled_line_ranges, offenses, comments)
68
75
  disabled_ranges = cop_disabled_line_ranges[COP_NAME] || [0..0]
69
76
 
@@ -124,27 +131,33 @@ module RuboCop
124
131
 
125
132
  def add_offenses(unneeded_cops)
126
133
  unneeded_cops.each do |comment, cops|
127
- # Is the entire rubocop:disable line useless, or should just
128
- # some of the mentioned cops be removed?
129
134
  if all_disabled?(comment) ||
130
135
  directive_count(comment) == cops.size
131
- location = comment.loc.expression
132
- cop_list = cops.sort.map { |c| describe(c) }
133
- add_offense([[location], location], location,
134
- "Unnecessary disabling of #{cop_list.join(', ')}.")
136
+ add_offense_for_entire_comment(comment, cops)
135
137
  else
136
- cop_ranges = cops.map { |c| [c, cop_range(comment, c)] }
137
- cop_ranges.sort_by! { |_, r| r.begin_pos }
138
- ranges = cop_ranges.map { |_, r| r }
139
-
140
- cop_ranges.each do |cop, range|
141
- add_offense([ranges, range], range,
142
- "Unnecessary disabling of #{describe(cop)}.")
143
- end
138
+ add_offense_for_some_cops(comment, cops)
144
139
  end
145
140
  end
146
141
  end
147
142
 
143
+ def add_offense_for_entire_comment(comment, cops)
144
+ location = comment.loc.expression
145
+ cop_list = cops.sort.map { |c| describe(c) }
146
+ add_offense([[location], location], location,
147
+ "Unnecessary disabling of #{cop_list.join(', ')}.")
148
+ end
149
+
150
+ def add_offense_for_some_cops(comment, cops)
151
+ cop_ranges = cops.map { |c| [c, cop_range(comment, c)] }
152
+ cop_ranges.sort_by! { |_, r| r.begin_pos }
153
+ ranges = cop_ranges.map { |_, r| r }
154
+
155
+ cop_ranges.each do |cop, range|
156
+ add_offense([ranges, range], range,
157
+ "Unnecessary disabling of #{describe(cop)}.")
158
+ end
159
+ end
160
+
148
161
  def cop_range(comment, cop)
149
162
  matching_range(comment.loc.expression, cop) ||
150
163
  matching_range(comment.loc.expression, cop.split('/').last) ||
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Lint
7
+ # This cop checks for unneeded usages of splat expansion
8
+ #
9
+ # @example
10
+ # # bad
11
+ # a = *[1, 2, 3]
12
+ # a = *'a'
13
+ # a = *1
14
+ #
15
+ # begin
16
+ # foo
17
+ # rescue *[StandardError, ApplicationError]
18
+ # bar
19
+ # end
20
+ #
21
+ # case foo
22
+ # when *[1, 2, 3]
23
+ # bar
24
+ # else
25
+ # baz
26
+ # end
27
+ #
28
+ # # good
29
+ # c = [1, 2, 3]
30
+ # a = *c
31
+ # a, b = *c
32
+ # a, *b = *c
33
+ # a = *1..10
34
+ # a = ['a']
35
+ #
36
+ # begin
37
+ # foo
38
+ # rescue StandardError, ApplicationError
39
+ # bar
40
+ # end
41
+ #
42
+ # case foo
43
+ # when *[1, 2, 3]
44
+ # bar
45
+ # else
46
+ # baz
47
+ # end
48
+ class UnneededSplatExpansion < Cop
49
+ MSG = 'Unnecessary splat expansion.'.freeze
50
+ PERCENT_W = '%w'.freeze
51
+ PERCENT_CAPITAL_W = '%W'.freeze
52
+ PERCENT_I = '%i'.freeze
53
+ PERCENT_CAPITAL_I = '%I'.freeze
54
+ ARRAY_NEW_PATTERN = '$(send (const nil :Array) :new ...)'.freeze
55
+ ASSIGNMENT_TYPES = [:lvasgn, :ivasgn, :cvasgn, :gvasgn].freeze
56
+
57
+ def_node_matcher :literal_expansion?, <<-PATTERN
58
+ (splat {$({str dstr int float array} ...) (block #{ARRAY_NEW_PATTERN} ...) #{ARRAY_NEW_PATTERN}} ...)
59
+ PATTERN
60
+
61
+ def on_splat(node)
62
+ literal_expansion?(node) do |object|
63
+ if object.send_type?
64
+ return unless ASSIGNMENT_TYPES.include?(node.parent.parent.type)
65
+ end
66
+ add_offense(node, :expression)
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def autocorrect(node)
73
+ variable, = *node
74
+ parent = node.parent
75
+ loc = node.loc
76
+
77
+ lambda do |corrector|
78
+ if !variable.array_type?
79
+ corrector.replace(loc.expression, "[#{variable.source}]")
80
+ elsif unneeded_brackets?(parent)
81
+ corrector.replace(loc.expression, remove_brackets(variable))
82
+ else
83
+ corrector.remove(loc.operator)
84
+ end
85
+ end
86
+ end
87
+
88
+ def unneeded_brackets?(node)
89
+ parent = node.parent
90
+
91
+ node.when_type? || node.send_type? || (parent && parent.resbody_type?)
92
+ end
93
+
94
+ def remove_brackets(array)
95
+ array_start = array.loc.begin.source
96
+ elements = *array
97
+ elements = elements.map(&:source)
98
+
99
+ if array_start.start_with?(PERCENT_W)
100
+ "'#{elements.join("', '")}'"
101
+ elsif array_start.start_with?(PERCENT_CAPITAL_W)
102
+ %("#{elements.join('", "')}")
103
+ elsif array_start.start_with?(PERCENT_I)
104
+ ":#{elements.join(', :')}"
105
+ elsif array_start.start_with?(PERCENT_CAPITAL_I)
106
+ %(:"#{elements.join('", :"')}")
107
+ else
108
+ elements.join(', ')
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -48,30 +48,43 @@ module RuboCop
48
48
  def message_for_useless_assignment(assignment)
49
49
  variable = assignment.variable
50
50
 
51
- message = format(MSG, variable.name)
51
+ format(MSG, variable.name) +
52
+ message_specification(assignment, variable).to_s
53
+ end
52
54
 
55
+ def message_specification(assignment, variable)
53
56
  if assignment.multiple_assignment?
54
- message << " Use `_` or `_#{variable.name}` as a variable name " \
55
- "to indicate that it won't be used."
57
+ multiple_assignment_message(variable.name)
56
58
  elsif assignment.operator_assignment?
57
- return_value_node = return_value_node_of_scope(variable.scope)
58
- if assignment.meta_assignment_node.equal?(return_value_node)
59
- non_assignment_operator = assignment.operator.sub(/=$/, '')
60
- message << " Use just operator `#{non_assignment_operator}`."
61
- end
59
+ operator_assignment_message(variable.scope, assignment)
62
60
  else
63
- similar_name = find_similar_name(variable.name, variable.scope)
64
- message << " Did you mean `#{similar_name}`?" if similar_name
61
+ similar_name_message(variable)
65
62
  end
63
+ end
64
+
65
+ def multiple_assignment_message(variable_name)
66
+ " Use `_` or `_#{variable_name}` as a variable name to indicate " \
67
+ "that it won't be used."
68
+ end
69
+
70
+ def operator_assignment_message(scope, assignment)
71
+ return_value_node = return_value_node_of_scope(scope)
72
+ return unless assignment.meta_assignment_node
73
+ .equal?(return_value_node)
74
+
75
+ " Use just operator `#{assignment.operator.sub(/=$/, '')}`."
76
+ end
66
77
 
67
- message
78
+ def similar_name_message(variable)
79
+ similar_name = find_similar_name(variable.name, variable.scope)
80
+ " Did you mean `#{similar_name}`?" if similar_name
68
81
  end
69
82
 
70
83
  # TODO: More precise handling (rescue, ensure, nested begin, etc.)
71
84
  def return_value_node_of_scope(scope)
72
85
  body_node = scope.body_node
73
86
 
74
- if body_node.type == :begin
87
+ if body_node.begin_type?
75
88
  body_node.children.last
76
89
  else
77
90
  body_node
@@ -24,14 +24,7 @@ module RuboCop
24
24
  def on_method_def(_node, _method_name, _args, body)
25
25
  return unless body
26
26
 
27
- expression = if body.type == :begin
28
- body.children
29
- else
30
- body
31
- end
32
-
33
- last_expr = expression.is_a?(Array) ? expression.last : expression
34
-
27
+ last_expr = last_expression(body)
35
28
  return unless setter_call_to_local_variable?(last_expr)
36
29
 
37
30
  tracker = MethodVariableTracker.new(body)
@@ -39,15 +32,19 @@ module RuboCop
39
32
  variable_name, = *receiver
40
33
  return unless tracker.contain_local_object?(variable_name)
41
34
 
42
- add_offense(receiver,
43
- :name,
44
- format(MSG, receiver.loc.name.source))
35
+ add_offense(receiver, :name, format(MSG, receiver.loc.name.source))
36
+ end
37
+
38
+ def last_expression(body)
39
+ expression = body.begin_type? ? body.children : body
40
+
41
+ expression.is_a?(Array) ? expression.last : expression
45
42
  end
46
43
 
47
44
  def setter_call_to_local_variable?(node)
48
- return unless node && node.type == :send
45
+ return unless node && node.send_type?
49
46
  receiver, method, _args = *node
50
- return unless receiver && receiver.type == :lvar
47
+ return unless receiver && receiver.lvar_type?
51
48
  method =~ /(?:\w|\[\])=$/
52
49
  end
53
50
 
@@ -64,19 +61,7 @@ module RuboCop
64
61
 
65
62
  @local = {}
66
63
 
67
- scan(@body_node) do |node|
68
- case node.type
69
- when :masgn
70
- process_multiple_assignment(node)
71
- when :or_asgn, :and_asgn
72
- process_logical_operator_assignment(node)
73
- when :op_asgn
74
- process_binary_operator_assignment(node)
75
- when *ASSIGNMENT_TYPES
76
- _, rhs_node = *node
77
- process_assignment(node, rhs_node) if rhs_node
78
- end
79
- end
64
+ scan(@body_node) { |node| process_assignment_node(node) }
80
65
 
81
66
  @local[variable_name]
82
67
  end
@@ -91,6 +76,20 @@ module RuboCop
91
76
  end
92
77
  end
93
78
 
79
+ def process_assignment_node(node)
80
+ case node.type
81
+ when :masgn
82
+ process_multiple_assignment(node)
83
+ when :or_asgn, :and_asgn
84
+ process_logical_operator_assignment(node)
85
+ when :op_asgn
86
+ process_binary_operator_assignment(node)
87
+ when *ASSIGNMENT_TYPES
88
+ _, rhs_node = *node
89
+ process_assignment(node, rhs_node) if rhs_node
90
+ end
91
+ end
92
+
94
93
  def process_multiple_assignment(masgn_node)
95
94
  mlhs_node, mrhs_node = *masgn_node
96
95
 
@@ -100,7 +99,7 @@ module RuboCop
100
99
  lhs_variable_name, = *lhs_node
101
100
  rhs_node = mrhs_node.children[index]
102
101
 
103
- if mrhs_node.type == :array && rhs_node
102
+ if mrhs_node.array_type? && rhs_node
104
103
  process_assignment(lhs_variable_name, rhs_node)
105
104
  else
106
105
  @local[lhs_variable_name] = true
@@ -140,7 +139,7 @@ module RuboCop
140
139
 
141
140
  def constructor?(node)
142
141
  return true if node.literal?
143
- return false unless node.type == :send
142
+ return false unless node.send_type?
144
143
  _receiver, method = *node
145
144
  method == :new
146
145
  end
@@ -34,8 +34,7 @@ module RuboCop
34
34
  end
35
35
 
36
36
  def check_for_void_op(node)
37
- return unless node.type == :send
38
- return unless node.loc.selector
37
+ return unless node.send_type? && node.loc.selector
39
38
 
40
39
  op = node.loc.selector.source
41
40
 
@@ -48,8 +47,7 @@ module RuboCop
48
47
  end
49
48
 
50
49
  def check_for_literal(node)
51
- return unless node.literal?
52
- return if node.xstr_type?
50
+ return if !node.literal? || node.xstr_type?
53
51
 
54
52
  add_offense(node, :expression, format(LIT_MSG, node.source))
55
53
  end
@@ -29,11 +29,11 @@ module RuboCop
29
29
  # is a Class or Module. Filters out simple method calls to similarly
30
30
  # named private, protected or public.
31
31
  def class_or_module_parent?(node)
32
- node.each_ancestor do |a|
33
- if a.type == :block
34
- return true if a.class_constructor?
35
- elsif a.type != :begin
36
- return [:casgn, :sclass, :class, :module].include?(a.type)
32
+ node.each_ancestor do |ancestor|
33
+ if ancestor.block_type?
34
+ return true if ancestor.class_constructor?
35
+ elsif !ancestor.begin_type?
36
+ return [:casgn, :sclass, :class, :module].include?(ancestor.type)
37
37
  end
38
38
  end
39
39
  end