rubocop 0.36.0 → 0.37.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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -2
  3. data/README.md +10 -1
  4. data/assets/output.html.erb +55 -1
  5. data/config/default.yml +9 -3
  6. data/config/disabled.yml +21 -0
  7. data/config/enabled.yml +11 -10
  8. data/lib/rubocop.rb +9 -2
  9. data/lib/rubocop/ast_node.rb +67 -19
  10. data/lib/rubocop/ast_node/builder.rb +1 -0
  11. data/lib/rubocop/ast_node/sexp.rb +1 -0
  12. data/lib/rubocop/ast_node/traversal.rb +171 -0
  13. data/lib/rubocop/cached_data.rb +4 -1
  14. data/lib/rubocop/cli.rb +1 -1
  15. data/lib/rubocop/config.rb +36 -20
  16. data/lib/rubocop/config_loader.rb +6 -5
  17. data/lib/rubocop/cop/commissioner.rb +27 -18
  18. data/lib/rubocop/cop/cop.rb +7 -6
  19. data/lib/rubocop/cop/lint/duplicated_key.rb +1 -8
  20. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  21. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
  22. data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
  23. data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
  24. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -0
  25. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +9 -2
  26. data/lib/rubocop/cop/mixin/check_assignment.rb +1 -1
  27. data/lib/rubocop/cop/mixin/classish_length.rb +3 -4
  28. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +8 -4
  29. data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
  30. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -1
  31. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +35 -0
  32. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  33. data/lib/rubocop/cop/mixin/min_body_length.rb +1 -1
  34. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +58 -0
  35. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  36. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  37. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -2
  38. data/lib/rubocop/cop/performance/case_when_splat.rb +7 -0
  39. data/lib/rubocop/cop/performance/casecmp.rb +56 -17
  40. data/lib/rubocop/cop/performance/redundant_block_call.rb +17 -3
  41. data/lib/rubocop/cop/performance/redundant_merge.rb +7 -1
  42. data/lib/rubocop/cop/performance/times_map.rb +3 -4
  43. data/lib/rubocop/cop/severity.rb +1 -1
  44. data/lib/rubocop/cop/style/align_hash.rb +1 -1
  45. data/lib/rubocop/cop/style/align_parameters.rb +1 -1
  46. data/lib/rubocop/cop/style/and_or.rb +1 -1
  47. data/lib/rubocop/cop/style/block_comments.rb +2 -0
  48. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -0
  49. data/lib/rubocop/cop/style/copyright.rb +2 -2
  50. data/lib/rubocop/cop/style/documentation.rb +19 -29
  51. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  52. data/lib/rubocop/cop/style/else_alignment.rb +2 -2
  53. data/lib/rubocop/cop/style/encoding.rb +1 -1
  54. data/lib/rubocop/cop/style/first_parameter_indentation.rb +1 -1
  55. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -12
  56. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  57. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -8
  58. data/lib/rubocop/cop/style/indent_assignment.rb +1 -1
  59. data/lib/rubocop/cop/style/indentation_width.rb +3 -7
  60. data/lib/rubocop/cop/style/method_call_parentheses.rb +2 -1
  61. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  62. data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +3 -41
  63. data/lib/rubocop/cop/style/multiline_hash_brace_layout.rb +57 -0
  64. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +65 -0
  65. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +5 -4
  66. data/lib/rubocop/cop/style/multiline_method_definition_brace_layout.rb +62 -0
  67. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +9 -3
  68. data/lib/rubocop/cop/style/mutable_constant.rb +18 -3
  69. data/lib/rubocop/cop/style/nested_modifier.rb +5 -2
  70. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -1
  71. data/lib/rubocop/cop/style/next.rb +32 -11
  72. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  73. data/lib/rubocop/cop/style/redundant_freeze.rb +13 -3
  74. data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -7
  75. data/lib/rubocop/cop/style/send.rb +1 -1
  76. data/lib/rubocop/cop/style/space_around_keyword.rb +198 -0
  77. data/lib/rubocop/cop/style/space_around_operators.rb +2 -12
  78. data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
  79. data/lib/rubocop/cop/style/special_global_vars.rb +4 -4
  80. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  81. data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
  82. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +1 -0
  83. data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -0
  84. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  85. data/lib/rubocop/cop/style/zero_length_predicate.rb +55 -0
  86. data/lib/rubocop/cop/team.rb +30 -5
  87. data/lib/rubocop/cop/util.rb +16 -1
  88. data/lib/rubocop/cop/variable_force.rb +3 -12
  89. data/lib/rubocop/cop/variable_force/assignment.rb +3 -3
  90. data/lib/rubocop/cop/variable_force/locatable.rb +25 -6
  91. data/lib/rubocop/cop/variable_force/reference.rb +3 -3
  92. data/lib/rubocop/cop/variable_force/scope.rb +8 -7
  93. data/lib/rubocop/cop/variable_force/variable.rb +3 -3
  94. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  95. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  96. data/lib/rubocop/node_pattern.rb +1 -1
  97. data/lib/rubocop/options.rb +10 -10
  98. data/lib/rubocop/path_util.rb +5 -0
  99. data/lib/rubocop/processed_source.rb +8 -2
  100. data/lib/rubocop/result_cache.rb +1 -1
  101. data/lib/rubocop/runner.rb +1 -1
  102. data/lib/rubocop/token.rb +2 -2
  103. data/lib/rubocop/version.rb +1 -1
  104. data/relnotes/v0.30.1.md +1 -0
  105. data/relnotes/v0.33.0.md +1 -1
  106. data/relnotes/v0.36.0.md +2 -1
  107. data/relnotes/v0.37.0.md +200 -0
  108. data/rubocop.gemspec +2 -1
  109. metadata +28 -7
  110. data/lib/rubocop/cop/style/space_after_control_keyword.rb +0 -35
  111. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +0 -38
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Style
7
+ # This cop checks that the closing brace in an a hash literal is
8
+ # symmetrical with respect to the opening brace and the hash
9
+ # elements.
10
+ #
11
+ # If a hash's opening brace is on the same line as the first element
12
+ # of the hash, then the closing brace should be on the same line as
13
+ # the last element of the hash.
14
+ #
15
+ # If a hash's opening brace is on a separate line from the first
16
+ # element of the hash, then the closing brace should be on the line
17
+ # after the last element of the hash.
18
+ #
19
+ # @example
20
+ #
21
+ # # bad
22
+ # { a: 'a',
23
+ # b: 'b'
24
+ # }
25
+ #
26
+ # # bad
27
+ # {
28
+ # a: 'a',
29
+ # b: 'b' }
30
+ #
31
+ # # good
32
+ # { a: 'a',
33
+ # b: 'b' }
34
+ #
35
+ # #good
36
+ # {
37
+ # a: 'a',
38
+ # b: 'b'
39
+ # }
40
+ class MultilineHashBraceLayout < Cop
41
+ include MultilineLiteralBraceLayout
42
+
43
+ SAME_LINE_MESSAGE = 'Closing hash brace must be on the same line as ' \
44
+ 'the last hash element when opening brace is on the same line as ' \
45
+ 'the first hash element.'.freeze
46
+
47
+ NEW_LINE_MESSAGE = 'Closing hash brace must be on the line after ' \
48
+ 'the last hash element when opening brace is on a separate line ' \
49
+ 'from the first hash element.'.freeze
50
+
51
+ def on_hash(node)
52
+ check_brace_layout(node)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Style
7
+ # This cop checks that the closing brace in a method call is
8
+ # symmetrical with respect to the opening brace and the method
9
+ # arguments.
10
+ #
11
+ # If a method call's opening brace is on the same line as the
12
+ # first argument of the call, then the closing brace should be
13
+ # on the same line as the last argument of the call.
14
+ #
15
+ # If a method call's opening brace is on a separate line from
16
+ # the first argument of the call, then the closing brace should
17
+ # be on the line after the last argument of the call.
18
+ #
19
+ # @example
20
+ #
21
+ # # bad
22
+ # foo(a,
23
+ # b
24
+ # )
25
+ #
26
+ # # bad
27
+ # foo(
28
+ # a,
29
+ # b)
30
+ #
31
+ # # good
32
+ # foo(a,
33
+ # b)
34
+ #
35
+ # #good
36
+ # foo(
37
+ # a,
38
+ # b
39
+ # )
40
+ class MultilineMethodCallBraceLayout < Cop
41
+ include MultilineLiteralBraceLayout
42
+
43
+ SAME_LINE_MESSAGE = 'Closing method call brace must be on the ' \
44
+ 'same line as the last argument when opening brace is on the same ' \
45
+ 'line as the first argument.'.freeze
46
+
47
+ NEW_LINE_MESSAGE = 'Closing method call brace must be on the ' \
48
+ 'line after the last argument when opening brace is on a separate ' \
49
+ 'line from the first argument.'.freeze
50
+
51
+ def on_send(node)
52
+ check_brace_layout(node)
53
+ end
54
+
55
+ private
56
+
57
+ def children(node)
58
+ _receiver, _method_name, *args = *node
59
+
60
+ args
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -37,10 +37,11 @@ module RuboCop
37
37
 
38
38
  def validate_config
39
39
  if style == :aligned && cop_config['IndentationWidth']
40
- fail ValidationError, 'The `Style/MultilineMethodCallIndentation`' \
41
- ' cop only accepts an `IndentationWidth` ' \
42
- 'configuration parameter when ' \
43
- '`EnforcedStyle` is `indented`.'
40
+ raise ValidationError,
41
+ 'The `Style/MultilineMethodCallIndentation`' \
42
+ ' cop only accepts an `IndentationWidth` ' \
43
+ 'configuration parameter when ' \
44
+ '`EnforcedStyle` is `indented`.'
44
45
  end
45
46
  end
46
47
 
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Style
7
+ # This cop checks that the closing brace in a method definition is
8
+ # symmetrical with respect to the opening brace and the method
9
+ # parameters.
10
+ #
11
+ # If a method definition's opening brace is on the same line as the
12
+ # first parameter of the definition, then the closing brace should be
13
+ # on the same line as the last parameter of the definition.
14
+ #
15
+ # If a method definition's opening brace is on a separate line from
16
+ # the first parameter of the definition, then the closing brace should
17
+ # be on the line after the last parameter of the definition.
18
+ #
19
+ # @example
20
+ #
21
+ # # bad
22
+ # def foo(a,
23
+ # b
24
+ # )
25
+ # end
26
+ #
27
+ # # bad
28
+ # def foo(
29
+ # a,
30
+ # b)
31
+ # end
32
+ #
33
+ # # good
34
+ # def foo(a,
35
+ # b)
36
+ # end
37
+ #
38
+ # #good
39
+ # def foo(
40
+ # a,
41
+ # b
42
+ # )
43
+ # end
44
+ class MultilineMethodDefinitionBraceLayout < Cop
45
+ include OnMethodDef
46
+ include MultilineLiteralBraceLayout
47
+
48
+ SAME_LINE_MESSAGE = 'Closing method definition brace must be on the ' \
49
+ 'same line as the last parameter when opening brace is on the same ' \
50
+ 'line as the first parameter.'.freeze
51
+
52
+ NEW_LINE_MESSAGE = 'Closing method definition brace must be on the ' \
53
+ 'line after the last parameter when opening brace is on a separate ' \
54
+ 'line from the first parameter.'.freeze
55
+
56
+ def on_method_def(_node, _method_name, args, _body)
57
+ check_brace_layout(args)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -28,7 +28,7 @@ module RuboCop
28
28
 
29
29
  def validate_config
30
30
  if style == :aligned && cop_config['IndentationWidth']
31
- fail ValidationError, 'The `Style/MultilineOperationIndentation`' \
31
+ raise ValidationError, 'The `Style/MultilineOperationIndentation`' \
32
32
  ' cop only accepts an `IndentationWidth` ' \
33
33
  'configuration parameter when ' \
34
34
  '`EnforcedStyle` is `indented`.'
@@ -53,7 +53,7 @@ module RuboCop
53
53
  return false if not_for_this_cop?(node)
54
54
 
55
55
  correct_column = if should_align?(node, rhs, given_style)
56
- lhs.loc.column
56
+ node.loc.column
57
57
  else
58
58
  indentation(lhs) + correct_indentation(node)
59
59
  end
@@ -62,8 +62,14 @@ module RuboCop
62
62
  end
63
63
 
64
64
  def should_align?(node, rhs, given_style)
65
+ assignment_node = part_of_assignment_rhs(node, rhs)
66
+ if assignment_node
67
+ assignment_rhs = CheckAssignment.extract_rhs(assignment_node)
68
+ return true if begins_its_line?(assignment_rhs.source_range)
69
+ end
70
+
65
71
  given_style == :aligned && (kw_node_with_special_indentation(node) ||
66
- part_of_assignment_rhs(node, rhs) ||
72
+ assignment_node ||
67
73
  argument_in_method_call(node))
68
74
  end
69
75
 
@@ -16,18 +16,33 @@ module RuboCop
16
16
  class MutableConstant < Cop
17
17
  MSG = 'Freeze mutable objects assigned to constants.'.freeze
18
18
 
19
+ include FrozenStringLiteral
20
+
19
21
  def on_casgn(node)
20
22
  _scope, _const_name, value = *node
23
+ on_assignment(value)
24
+ end
21
25
 
22
- return if value && !value.mutable_literal?
23
-
24
- add_offense(value, :expression)
26
+ def on_or_asgn(node)
27
+ lhs, value = *node
28
+ on_assignment(value) if lhs && lhs.type == :casgn
25
29
  end
26
30
 
27
31
  def autocorrect(node)
28
32
  expr = node.source_range
29
33
  ->(corrector) { corrector.replace(expr, "#{expr.source}.freeze") }
30
34
  end
35
+
36
+ private
37
+
38
+ def on_assignment(value)
39
+ return unless value
40
+ return unless value.mutable_literal?
41
+ return if FROZEN_STRING_LITERAL_TYPES.include?(value.type) &&
42
+ frozen_string_literals_enabled?(processed_source)
43
+
44
+ add_offense(value, :expression)
45
+ end
31
46
  end
32
47
  end
33
48
  end
@@ -83,14 +83,17 @@ module RuboCop
83
83
  outer_keyword = outer_node.loc.keyword.source
84
84
  inner_keyword = inner_node.loc.keyword.source
85
85
 
86
- operator = outer_keyword == 'if' ? '&&' : '||'
86
+ operator = outer_keyword == 'if'.freeze ? '&&'.freeze : '||'.freeze
87
87
 
88
+ outer_expr = outer_cond.source
89
+ outer_expr = "(#{outer_expr})" if outer_cond.or_type? &&
90
+ operator == '&&'.freeze
88
91
  inner_expr = inner_cond.source
89
92
  inner_expr = "(#{inner_expr})" if inner_cond.or_type?
90
93
  inner_expr = "!#{inner_expr}" unless outer_keyword == inner_keyword
91
94
 
92
95
  "#{outer_node.loc.keyword.source} " \
93
- "#{outer_cond.source} #{operator} #{inner_expr}"
96
+ "#{outer_expr} #{operator} #{inner_expr}"
94
97
  end
95
98
  end
96
99
  end
@@ -26,7 +26,8 @@ module RuboCop
26
26
  next if nested.method_args.empty? ||
27
27
  parenthesized_call?(nested) ||
28
28
  operator?(nested.method_name) ||
29
- rspec_matcher?(node, nested)
29
+ rspec_matcher?(node, nested) ||
30
+ nested.asgn_method_call?
30
31
  add_offense(nested, nested.source_range, format(MSG, nested.source))
31
32
  end
32
33
  end
@@ -108,20 +108,41 @@ module RuboCop
108
108
 
109
109
  def autocorrect(node)
110
110
  lambda do |corrector|
111
- cond, if_body, = *node
111
+ if modifier_if?(node)
112
+ autocorrect_modifier(corrector, node)
113
+ else
114
+ autocorrect_block(corrector, node)
115
+ end
116
+ end
117
+ end
112
118
 
113
- opposite_kw = if_body.nil? ? 'if' : 'unless'
114
- next_code = "next #{opposite_kw} #{cond.source}"
115
- corrector.insert_before(node.source_range, next_code)
119
+ def autocorrect_modifier(corrector, node)
120
+ cond, if_body, else_body = *node
121
+ body = if_body || else_body
116
122
 
117
- corrector.remove(cond_range(node, cond))
118
- corrector.remove(end_range(node))
123
+ replacement = "next #{opposite_kw(if_body)} #{cond.source}\n" \
124
+ "#{' ' * node.source_range.column}#{body.source}"
119
125
 
120
- # end_range starts with the final newline of the if body
121
- reindent_lines = (node.source_range.line + 1)...node.loc.end.line
122
- reindent_lines = reindent_lines.to_a - heredoc_lines(node)
123
- reindent(reindent_lines, cond, corrector)
124
- end
126
+ corrector.replace(node.source_range, replacement)
127
+ end
128
+
129
+ def autocorrect_block(corrector, node)
130
+ cond, if_body, = *node
131
+
132
+ next_code = "next #{opposite_kw(if_body)} #{cond.source}"
133
+ corrector.insert_before(node.source_range, next_code)
134
+
135
+ corrector.remove(cond_range(node, cond))
136
+ corrector.remove(end_range(node))
137
+
138
+ # end_range starts with the final newline of the if body
139
+ reindent_lines = (node.source_range.line + 1)...node.loc.end.line
140
+ reindent_lines = reindent_lines.to_a - heredoc_lines(node)
141
+ reindent(reindent_lines, cond, corrector)
142
+ end
143
+
144
+ def opposite_kw(if_body)
145
+ if_body.nil? ? 'if' : 'unless'
125
146
  end
126
147
 
127
148
  def cond_range(node, cond)
@@ -49,7 +49,7 @@ module RuboCop
49
49
 
50
50
  def validate_config
51
51
  if target_ruby_version < 2.0
52
- fail ValidationError, 'The `Style/OptionHash` cop is only ' \
52
+ raise ValidationError, 'The `Style/OptionHash` cop is only ' \
53
53
  'compatible with Ruby 2.0 and up, but the ' \
54
54
  'target Ruby version for your project is ' \
55
55
  "1.9.\nPlease disable this cop or adjust " \
@@ -13,15 +13,16 @@ module RuboCop
13
13
  # # good
14
14
  # CONST = 1
15
15
  class RedundantFreeze < Cop
16
+ include FrozenStringLiteral
17
+
16
18
  MSG = 'Freezing immutable objects is pointless.'.freeze
17
19
 
18
20
  def on_send(node)
19
21
  receiver, method_name, *args = *node
20
22
 
21
- return unless receiver &&
22
- method_name == :freeze &&
23
+ return unless method_name == :freeze &&
23
24
  args.empty? &&
24
- receiver.immutable_literal?
25
+ immutable_literal?(receiver)
25
26
 
26
27
  add_offense(node, :expression)
27
28
  end
@@ -32,6 +33,15 @@ module RuboCop
32
33
  corrector.remove(node.loc.selector)
33
34
  end
34
35
  end
36
+
37
+ private
38
+
39
+ def immutable_literal?(node)
40
+ return false unless node
41
+ return true if node.immutable_literal?
42
+ FROZEN_STRING_LITERAL_TYPES.include?(node.type) &&
43
+ frozen_string_literals_enabled?(processed_source)
44
+ end
35
45
  end
36
46
  end
37
47
  end
@@ -28,16 +28,30 @@ module RuboCop
28
28
 
29
29
  child_node = node.children.first
30
30
  return if keyword_ancestor?(node) && parens_required?(node)
31
+ return if child_node.hash_type? && first_argument?(node) &&
32
+ !parentheses?(node.parent)
31
33
 
32
- if keyword_with_redundant_parentheses?(child_node)
33
- return offense(node, 'a keyword')
34
+ return if rescue?(node)
35
+ check(node, child_node)
36
+ end
37
+
38
+ def check(begin_node, node)
39
+ if keyword_with_redundant_parentheses?(node)
40
+ return offense(begin_node, 'a keyword')
34
41
  end
35
- return offense(node, 'a literal') if disallowed_literal?(child_node)
36
- return offense(node, 'a variable') if child_node.variable?
37
- return offense(node, 'a constant') if child_node.const_type?
38
- return unless method_call_with_redundant_parentheses?(child_node)
42
+ return offense(begin_node, 'a literal') if disallowed_literal?(node)
43
+ return offense(begin_node, 'a variable') if node.variable?
44
+ return offense(begin_node, 'a constant') if node.const_type?
45
+ check_send(begin_node, node) if node.send_type?
46
+ end
39
47
 
40
- offense(node, 'a method call')
48
+ def check_send(begin_node, node)
49
+ if node.unary_operation?
50
+ offense(begin_node, 'an unary operation') unless begin_node.chained?
51
+ else
52
+ return unless method_call_with_redundant_parentheses?(node)
53
+ offense(begin_node, 'a method call')
54
+ end
41
55
  end
42
56
 
43
57
  def offense(node, msg)
@@ -74,6 +88,18 @@ module RuboCop
74
88
 
75
89
  args.empty? || parentheses?(send_node) || square_brackets?(send_node)
76
90
  end
91
+
92
+ def first_argument?(node)
93
+ send_node = node.parent
94
+ return false unless send_node && send_node.send_type?
95
+
96
+ _receiver, _method_name, *args = *send_node
97
+ node == args.first
98
+ end
99
+
100
+ def rescue?(node)
101
+ node.parent && node.parent.array_type?
102
+ end
77
103
  end
78
104
  end
79
105
  end