rubocop 0.31.0 → 0.35.0

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 (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +315 -0
  3. data/README.md +199 -38
  4. data/config/default.yml +91 -12
  5. data/config/disabled.yml +45 -4
  6. data/config/enabled.yml +107 -9
  7. data/lib/rubocop/ast_node.rb +48 -0
  8. data/lib/rubocop/cli.rb +11 -1
  9. data/lib/rubocop/comment_config.rb +4 -1
  10. data/lib/rubocop/config.rb +26 -17
  11. data/lib/rubocop/config_loader.rb +61 -14
  12. data/lib/rubocop/cop/commissioner.rb +7 -12
  13. data/lib/rubocop/cop/cop.rb +43 -20
  14. data/lib/rubocop/cop/lint/block_alignment.rb +1 -1
  15. data/lib/rubocop/cop/lint/circular_argument_reference.rb +69 -0
  16. data/lib/rubocop/cop/lint/debugger.rb +9 -48
  17. data/lib/rubocop/cop/lint/def_end_alignment.rb +8 -4
  18. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +42 -23
  19. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  20. data/lib/rubocop/cop/lint/duplicated_key.rb +37 -0
  21. data/lib/rubocop/cop/lint/end_alignment.rb +33 -13
  22. data/lib/rubocop/cop/lint/eval.rb +6 -2
  23. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +175 -0
  24. data/lib/rubocop/cop/lint/literal_in_condition.rb +0 -5
  25. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +10 -0
  26. data/lib/rubocop/cop/lint/nested_method_definition.rb +31 -0
  27. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +19 -1
  28. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  29. data/lib/rubocop/cop/lint/space_before_first_arg.rb +1 -1
  30. data/lib/rubocop/cop/lint/unneeded_disable.rb +72 -0
  31. data/lib/rubocop/cop/lint/unused_block_argument.rb +6 -0
  32. data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -0
  33. data/lib/rubocop/cop/metrics/abc_size.rb +17 -6
  34. data/lib/rubocop/cop/metrics/class_length.rb +1 -1
  35. data/lib/rubocop/cop/metrics/method_length.rb +1 -3
  36. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  37. data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
  38. data/lib/rubocop/cop/mixin/access_modifier_node.rb +1 -1
  39. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -2
  40. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +28 -4
  41. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +26 -3
  42. data/lib/rubocop/cop/mixin/check_assignment.rb +2 -3
  43. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +59 -12
  44. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -1
  45. data/lib/rubocop/cop/mixin/configurable_naming.rb +14 -3
  46. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -3
  47. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +10 -1
  48. data/lib/rubocop/cop/mixin/first_element_line_break.rb +41 -0
  49. data/lib/rubocop/cop/mixin/if_node.rb +10 -0
  50. data/lib/rubocop/cop/mixin/method_preference.rb +28 -0
  51. data/lib/rubocop/cop/mixin/negative_conditional.rb +1 -1
  52. data/lib/rubocop/cop/mixin/on_method_def.rb +4 -5
  53. data/lib/rubocop/cop/mixin/safe_assignment.rb +3 -14
  54. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +8 -1
  55. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +8 -1
  56. data/lib/rubocop/cop/mixin/statement_modifier.rb +4 -7
  57. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  58. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  59. data/lib/rubocop/cop/mixin/surrounding_space.rb +5 -4
  60. data/lib/rubocop/cop/offense.rb +16 -3
  61. data/lib/rubocop/cop/performance/case_when_splat.rb +160 -0
  62. data/lib/rubocop/cop/performance/count.rb +35 -30
  63. data/lib/rubocop/cop/performance/detect.rb +16 -3
  64. data/lib/rubocop/cop/performance/fixed_size.rb +50 -0
  65. data/lib/rubocop/cop/performance/flat_map.rb +3 -3
  66. data/lib/rubocop/cop/performance/sample.rb +103 -59
  67. data/lib/rubocop/cop/performance/size.rb +2 -1
  68. data/lib/rubocop/cop/performance/string_replacement.rb +187 -0
  69. data/lib/rubocop/cop/rails/action_filter.rb +31 -5
  70. data/lib/rubocop/cop/rails/date.rb +15 -14
  71. data/lib/rubocop/cop/rails/pluralization_grammar.rb +97 -0
  72. data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
  73. data/lib/rubocop/cop/rails/time_zone.rb +46 -18
  74. data/lib/rubocop/cop/style/alias.rb +1 -0
  75. data/lib/rubocop/cop/style/align_hash.rb +8 -15
  76. data/lib/rubocop/cop/style/align_parameters.rb +19 -7
  77. data/lib/rubocop/cop/style/and_or.rb +42 -13
  78. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +2 -1
  79. data/lib/rubocop/cop/style/block_comments.rb +4 -2
  80. data/lib/rubocop/cop/style/block_delimiters.rb +69 -24
  81. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +40 -12
  82. data/lib/rubocop/cop/style/case_indentation.rb +18 -4
  83. data/lib/rubocop/cop/style/collection_methods.rb +2 -20
  84. data/lib/rubocop/cop/style/command_literal.rb +2 -10
  85. data/lib/rubocop/cop/style/comment_annotation.rb +29 -8
  86. data/lib/rubocop/cop/style/copyright.rb +5 -3
  87. data/lib/rubocop/cop/style/documentation.rb +21 -12
  88. data/lib/rubocop/cop/style/dot_position.rb +6 -0
  89. data/lib/rubocop/cop/style/double_negation.rb +4 -15
  90. data/lib/rubocop/cop/style/each_with_object.rb +17 -4
  91. data/lib/rubocop/cop/style/else_alignment.rb +2 -1
  92. data/lib/rubocop/cop/style/empty_else.rb +25 -0
  93. data/lib/rubocop/cop/style/empty_line_between_defs.rb +39 -14
  94. data/lib/rubocop/cop/style/encoding.rb +10 -4
  95. data/lib/rubocop/cop/style/extra_spacing.rb +126 -5
  96. data/lib/rubocop/cop/style/first_array_element_line_break.rb +41 -0
  97. data/lib/rubocop/cop/style/first_hash_element_line_break.rb +35 -0
  98. data/lib/rubocop/cop/style/first_method_argument_line_break.rb +37 -0
  99. data/lib/rubocop/cop/style/first_method_parameter_line_break.rb +42 -0
  100. data/lib/rubocop/cop/style/first_parameter_indentation.rb +5 -3
  101. data/lib/rubocop/cop/style/for.rb +2 -1
  102. data/lib/rubocop/cop/style/hash_syntax.rb +5 -0
  103. data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -5
  104. data/lib/rubocop/cop/style/indent_hash.rb +67 -37
  105. data/lib/rubocop/cop/style/indentation_width.rb +36 -10
  106. data/lib/rubocop/cop/style/initial_indentation.rb +37 -0
  107. data/lib/rubocop/cop/style/leading_comment_space.rb +3 -2
  108. data/lib/rubocop/cop/style/method_call_parentheses.rb +28 -1
  109. data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -7
  110. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +21 -24
  111. data/lib/rubocop/cop/style/mutable_constant.rb +35 -0
  112. data/lib/rubocop/cop/style/nested_modifier.rb +97 -0
  113. data/lib/rubocop/cop/style/next.rb +50 -15
  114. data/lib/rubocop/cop/style/non_nil_check.rb +12 -8
  115. data/lib/rubocop/cop/style/one_line_conditional.rb +8 -4
  116. data/lib/rubocop/cop/style/option_hash.rb +64 -0
  117. data/lib/rubocop/cop/style/optional_arguments.rb +49 -0
  118. data/lib/rubocop/cop/style/parallel_assignment.rb +218 -0
  119. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -66
  120. data/lib/rubocop/cop/style/predicate_name.rb +7 -2
  121. data/lib/rubocop/cop/style/redundant_begin.rb +2 -13
  122. data/lib/rubocop/cop/style/redundant_freeze.rb +37 -0
  123. data/lib/rubocop/cop/style/redundant_return.rb +32 -3
  124. data/lib/rubocop/cop/style/regexp_literal.rb +2 -10
  125. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +81 -0
  126. data/lib/rubocop/cop/style/rescue_modifier.rb +30 -22
  127. data/lib/rubocop/cop/style/send.rb +18 -0
  128. data/lib/rubocop/cop/style/signal_exception.rb +24 -11
  129. data/lib/rubocop/cop/style/single_line_methods.rb +8 -9
  130. data/lib/rubocop/cop/style/single_space_before_first_arg.rb +1 -1
  131. data/lib/rubocop/cop/style/space_around_operators.rb +2 -0
  132. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +61 -0
  133. data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
  134. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +108 -0
  135. data/lib/rubocop/cop/style/string_methods.rb +32 -0
  136. data/lib/rubocop/cop/style/struct_inheritance.rb +11 -10
  137. data/lib/rubocop/cop/style/symbol_literal.rb +1 -1
  138. data/lib/rubocop/cop/style/symbol_proc.rb +62 -13
  139. data/lib/rubocop/cop/style/trailing_blank_lines.rb +9 -1
  140. data/lib/rubocop/cop/style/trailing_comma.rb +17 -7
  141. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -2
  142. data/lib/rubocop/cop/style/trivial_accessors.rb +10 -1
  143. data/lib/rubocop/cop/style/unneeded_percent_q.rb +31 -20
  144. data/lib/rubocop/cop/style/variable_name.rb +5 -0
  145. data/lib/rubocop/cop/style/while_until_do.rb +1 -1
  146. data/lib/rubocop/cop/style/word_array.rb +15 -2
  147. data/lib/rubocop/cop/team.rb +25 -5
  148. data/lib/rubocop/cop/util.rb +7 -2
  149. data/lib/rubocop/cop/variable_force/locatable.rb +6 -6
  150. data/lib/rubocop/cop/variable_force.rb +10 -10
  151. data/lib/rubocop/formatter/base_formatter.rb +1 -1
  152. data/lib/rubocop/formatter/disabled_config_formatter.rb +70 -8
  153. data/lib/rubocop/formatter/formatter_set.rb +27 -1
  154. data/lib/rubocop/formatter/progress_formatter.rb +10 -2
  155. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  156. data/lib/rubocop/node_pattern.rb +390 -0
  157. data/lib/rubocop/options.rb +148 -81
  158. data/lib/rubocop/processed_source.rb +7 -2
  159. data/lib/rubocop/rake_task.rb +1 -1
  160. data/lib/rubocop/remote_config.rb +60 -0
  161. data/lib/rubocop/result_cache.rb +123 -0
  162. data/lib/rubocop/runner.rb +85 -22
  163. data/lib/rubocop/target_finder.rb +4 -4
  164. data/lib/rubocop/token.rb +2 -1
  165. data/lib/rubocop/version.rb +1 -1
  166. data/lib/rubocop/warning.rb +11 -0
  167. data/lib/rubocop.rb +32 -3
  168. data/relnotes/v0.32.0.md +139 -0
  169. data/relnotes/v0.32.1.md +122 -0
  170. data/relnotes/v0.33.0.md +157 -0
  171. data/relnotes/v0.34.0.md +182 -0
  172. data/relnotes/v0.34.1.md +129 -0
  173. data/relnotes/v0.34.2.md +139 -0
  174. data/relnotes/v0.35.0.md +210 -0
  175. data/rubocop.gemspec +4 -4
  176. metadata +50 -12
  177. data/lib/rubocop/cop/performance/parallel_assignment.rb +0 -79
@@ -17,23 +17,31 @@ module RuboCop
17
17
  PROC_NODE = s(:send, s(:const, nil, :Proc), :new)
18
18
 
19
19
  def on_block(node)
20
- block_send, block_args, block_body = *node
20
+ block_send_or_super, block_args, block_body = *node
21
21
 
22
- _breceiver, bmethod_name, bargs = *block_send
22
+ if super?(block_send_or_super)
23
+ bmethod_name = :super
24
+ else
25
+ _breceiver, bmethod_name, _bargs = *block_send_or_super
26
+ end
23
27
 
24
28
  # TODO: Rails-specific handling that we should probably make
25
29
  # configurable - https://github.com/bbatsov/rubocop/issues/1485
26
30
  # we should ignore lambdas & procs
27
- return if block_send == PROC_NODE
31
+ return if block_send_or_super == PROC_NODE
28
32
  return if [:lambda, :proc].include?(bmethod_name)
29
33
  return if ignored_method?(bmethod_name)
30
- # File.open(file) { |f| f.readlines }
31
- return if bargs
32
34
  return unless can_shorten?(block_args, block_body)
33
35
 
34
36
  _receiver, method_name, _args = *block_body
37
+
38
+ sb = node.loc.expression.source_buffer
39
+ block_start = node.loc.begin.begin_pos
40
+ block_end = node.loc.end.end_pos
41
+ range = Parser::Source::Range.new(sb, block_start, block_end)
42
+
35
43
  add_offense(node,
36
- :expression,
44
+ range,
37
45
  format(MSG,
38
46
  method_name,
39
47
  bmethod_name))
@@ -41,16 +49,52 @@ module RuboCop
41
49
 
42
50
  def autocorrect(node)
43
51
  lambda do |corrector|
44
- _block_method, _block_args, block_body = *node
52
+ block_send_or_super, _block_args, block_body = *node
45
53
  _receiver, method_name, _args = *block_body
46
54
 
47
- block_range =
48
- Parser::Source::Range.new(node.loc.expression.source_buffer,
49
- node.loc.begin.begin_pos,
50
- node.loc.end.end_pos)
55
+ if super?(block_send_or_super)
56
+ args = *block_send_or_super
57
+ autocorrect_method(corrector, node, args, method_name)
58
+ else
59
+ _breceiver, _bmethod_name, *args = *block_send_or_super
60
+ autocorrect_method(corrector, node, args, method_name)
61
+ end
62
+ end
63
+ end
51
64
 
52
- corrector.replace(range_with_surrounding_space(block_range, :left),
53
- "(&:#{method_name})")
65
+ def autocorrect_method(corrector, node, args, method_name)
66
+ if args.empty?
67
+ autocorrect_no_args(corrector, node, method_name)
68
+ else
69
+ autocorrect_with_args(corrector, node, args, method_name)
70
+ end
71
+ end
72
+
73
+ def autocorrect_no_args(corrector, node, method_name)
74
+ corrector.replace(block_range_with_space(node), "(&:#{method_name})")
75
+ end
76
+
77
+ def autocorrect_with_args(corrector, node, args, method_name)
78
+ corrector.insert_after(args.last.loc.expression, ", &:#{method_name}")
79
+ corrector.remove(block_range_with_space(node))
80
+ end
81
+
82
+ def block_range_with_space(node)
83
+ block_range =
84
+ Parser::Source::Range.new(node.loc.expression.source_buffer,
85
+ begin_pos_for_replacement(node),
86
+ node.loc.end.end_pos)
87
+ range_with_surrounding_space(block_range, :left)
88
+ end
89
+
90
+ def begin_pos_for_replacement(node)
91
+ block_send_or_super, _block_args, _block_body = *node
92
+ expr = block_send_or_super.loc.expression
93
+
94
+ if (paren_pos = (expr.source =~ /\(\s*\)$/))
95
+ expr.begin_pos + paren_pos
96
+ else
97
+ node.loc.begin.begin_pos
54
98
  end
55
99
  end
56
100
 
@@ -65,6 +109,7 @@ module RuboCop
65
109
  def can_shorten?(block_args, block_body)
66
110
  # something { |x, y| ... }
67
111
  return false unless block_args.children.size == 1
112
+ return false if block_args.children.first.blockarg_type?
68
113
  return false unless block_body && block_body.type == :send
69
114
 
70
115
  receiver, _method_name, args = *block_body
@@ -78,6 +123,10 @@ module RuboCop
78
123
 
79
124
  block_arg_name == receiver_name
80
125
  end
126
+
127
+ def super?(node)
128
+ [:super, :zsuper].include?(node.type)
129
+ end
81
130
  end
82
131
  end
83
132
  end
@@ -24,10 +24,18 @@ module RuboCop
24
24
 
25
25
  return unless blank_lines != wanted_blank_lines
26
26
 
27
+ offense_detected(sb, wanted_blank_lines, blank_lines,
28
+ whitespace_at_end)
29
+ end
30
+
31
+ private
32
+
33
+ def offense_detected(sb, wanted_blank_lines, blank_lines,
34
+ whitespace_at_end)
27
35
  begin_pos = sb.source.length - whitespace_at_end.length
28
36
  autocorrect_range = Parser::Source::Range.new(sb, begin_pos,
29
37
  sb.source.length)
30
- begin_pos += "\n".length unless whitespace_at_end.length == 0
38
+ begin_pos += 1 unless whitespace_at_end.length == 0
31
39
  report_range = Parser::Source::Range.new(sb, begin_pos,
32
40
  sb.source.length)
33
41
  add_offense(autocorrect_range, report_range,
@@ -68,18 +68,17 @@ module RuboCop
68
68
  node.loc.end.begin_pos)
69
69
  end
70
70
 
71
- # rubocop:disable Metrics/MethodLength
72
71
  def check(node, items, kind, begin_pos, end_pos)
73
72
  sb = items.first.loc.expression.source_buffer
73
+
74
74
  after_last_item = Parser::Source::Range.new(sb, begin_pos, end_pos)
75
75
 
76
76
  return if heredoc?(after_last_item.source)
77
77
 
78
78
  comma_offset = after_last_item.source =~ /,/
79
- should_have_comma =
80
- [:comma, :consistent_comma].include?(style) && multiline?(node)
79
+
81
80
  if comma_offset && !inside_comment?(after_last_item, comma_offset)
82
- unless should_have_comma
81
+ unless should_have_comma?(style, node, items)
83
82
  extra_info = case style
84
83
  when :comma
85
84
  ', unless each item is on its own line'
@@ -91,11 +90,16 @@ module RuboCop
91
90
  avoid_comma(kind, after_last_item.begin_pos + comma_offset, sb,
92
91
  extra_info)
93
92
  end
94
- elsif should_have_comma
93
+ elsif should_have_comma?(style, node, items)
95
94
  put_comma(items, kind, sb)
96
95
  end
97
96
  end
98
- # rubocop:enable Metrics/MethodLength
97
+
98
+ def should_have_comma?(style, node, items)
99
+ [:comma, :consistent_comma].include?(style) &&
100
+ multiline?(node) &&
101
+ (items.size > 1 || items.last.hash_type?)
102
+ end
99
103
 
100
104
  def inside_comment?(range, comma_offset)
101
105
  processed_source.comments.any? do |comment|
@@ -119,10 +123,16 @@ module RuboCop
119
123
  def multiline?(node)
120
124
  elements = if node.type == :send
121
125
  _receiver, _method_name, *args = *node
122
- args
126
+ args.flat_map { |a| a.type == :hash ? a.children : a }
123
127
  else
124
128
  node.children
125
129
  end
130
+
131
+ # Without this check, Foo.new({}) is considered multiline, which
132
+ # it should not be. Essentially, if there are no elements, the
133
+ # expression can not be multiline.
134
+ return if elements.empty?
135
+
126
136
  items = elements.map { |e| e.loc.expression }
127
137
  if style == :consistent_comma
128
138
  items.each_cons(2).any? { |a, b| !on_same_line?(a, b) }
@@ -15,10 +15,13 @@ module RuboCop
15
15
  # #good
16
16
  # a, b, = foo()
17
17
  # a, = foo()
18
+ # *a, b, _ = foo() => We need to know to not include 2 variables in a
19
+ # a, *b, _ = foo() => The correction `a, *b, = foo()` is a syntax error
18
20
  class TrailingUnderscoreVariable < Cop
19
21
  include SurroundingSpace
20
22
 
21
- MSG = 'Do not use trailing `_`s in parallel assignment.'
23
+ MSG = 'Do not use trailing `_`s in parallel assignment.'.freeze
24
+ UNDERSCORE = '_'.freeze
22
25
 
23
26
  def on_masgn(node)
24
27
  left, = *node
@@ -60,12 +63,30 @@ module RuboCop
60
63
  first_offense = nil
61
64
 
62
65
  variables.reverse_each do |variable|
63
- break unless variable.children.first == :_
66
+ var, = *variable
67
+ var, = *var
68
+ if allow_named_underscore_variables
69
+ break unless var == :_
70
+ else
71
+ break unless var.to_s.start_with?(UNDERSCORE)
72
+ end
64
73
  first_offense = variable
65
74
  end
66
75
 
76
+ return nil if first_offense.nil?
77
+
78
+ first_offense_index = variables.index(first_offense)
79
+ 0.upto(first_offense_index - 1).each do |index|
80
+ return nil if variables[index].splat_type?
81
+ end
82
+
67
83
  first_offense
68
84
  end
85
+
86
+ def allow_named_underscore_variables
87
+ @allow_named_underscore_variables ||=
88
+ cop_config['AllowNamedUnderscoreVariables']
89
+ end
69
90
  end
70
91
  end
71
92
  end
@@ -9,11 +9,13 @@ module RuboCop
9
9
  MSG = 'Use `attr_%s` to define trivial %s methods.'
10
10
 
11
11
  def on_def(node)
12
+ return if in_module?(node)
12
13
  method_name, args, body = *node
13
14
  on_method_def(node, method_name, args, body)
14
15
  end
15
16
 
16
17
  def on_defs(node)
18
+ return if in_module?(node)
17
19
  return if ignore_class_methods?
18
20
  _scope, method_name, args, body = *node
19
21
  on_method_def(node, method_name, args, body)
@@ -21,6 +23,12 @@ module RuboCop
21
23
 
22
24
  private
23
25
 
26
+ def in_module?(node)
27
+ pnode = node.parent
28
+ pnode = pnode.parent if pnode && pnode.type == :begin
29
+ !pnode.nil? && pnode.type == :module
30
+ end
31
+
24
32
  def on_method_def(node, method_name, args, body)
25
33
  kind = if trivial_reader?(method_name, args, body)
26
34
  'reader'
@@ -100,7 +108,7 @@ module RuboCop
100
108
  def names_match?(method_name, body)
101
109
  ivar_name, = *body
102
110
 
103
- method_name.to_s.chomp('=') == ivar_name[1..-1]
111
+ method_name.to_s.sub(/[=?]$/, '') == ivar_name[1..-1]
104
112
  end
105
113
 
106
114
  def trivial_accessor_kind(method_name, args, body)
@@ -127,6 +135,7 @@ module RuboCop
127
135
  def autocorrect_instance(node)
128
136
  method_name, args, body = *node
129
137
  unless names_match?(method_name, body) &&
138
+ !predicate?(method_name) &&
130
139
  (kind = trivial_accessor_kind(method_name, args, body))
131
140
  return
132
141
  end
@@ -7,51 +7,62 @@ module RuboCop
7
7
  class UnneededPercentQ < Cop
8
8
  MSG = 'Use `%s` only for strings that contain both single quotes and ' \
9
9
  'double quotes%s.'
10
+ DYNAMIC_MSG = ', or for dynamic strings that contain double quotes'
11
+ SINGLE_QUOTE = "'".freeze
12
+ QUOTE = '"'.freeze
13
+ EMPTY = ''.freeze
14
+ PERCENT_Q = '%q'.freeze
15
+ PERCENT_CAPITAL_Q = '%Q'.freeze
16
+ STRING_INTERPOLATION_REGEXP = /#\{.+}/
10
17
 
11
18
  def on_dstr(node)
12
- # Using %Q to avoid escaping inner " is ok.
13
- check(node) unless node.loc.expression.source =~ /"/
19
+ check(node)
14
20
  end
15
21
 
16
22
  def on_str(node)
23
+ # Interpolated strings that contain more than just interpolation
24
+ # will call `on_dstr` for the entire string and `on_str` for the
25
+ # non interpolated portion of the string
26
+ return unless string_literal?(node)
17
27
  check(node)
18
28
  end
19
29
 
20
- # We process regexp nodes because the inner str nodes can cause
21
- # confusion in on_str if they start with %( or %Q(.
22
- def on_regexp(node)
23
- string_parts = node.children.select { |child| child.type == :str }
24
- string_parts.each { |s| ignore_node(s) }
25
- end
26
-
27
30
  private
28
31
 
29
32
  def check(node)
30
- if node.loc.respond_to?(:heredoc_body)
31
- ignore_node(node)
32
- return
33
- end
34
- return if ignored_node?(node) || part_of_ignored_node?(node)
35
33
  src = node.loc.expression.source
36
- return unless src.start_with?('%q') || src.start_with?('%Q')
37
- return if src =~ /'/ && src =~ /"/
34
+ return unless start_with_percent_q_variant?(src)
35
+ return if src.include?(SINGLE_QUOTE) && src.include?(QUOTE)
38
36
  return if src =~ StringHelp::ESCAPED_CHAR_REGEXP
37
+ if src.start_with?(PERCENT_Q) && src =~ STRING_INTERPOLATION_REGEXP
38
+ return
39
+ end
39
40
 
40
- extra = if src.start_with?('%Q')
41
- ', or for dynamic strings that contain double quotes'
41
+ extra = if src.start_with?(PERCENT_CAPITAL_Q)
42
+ DYNAMIC_MSG
42
43
  else
43
- ''
44
+ EMPTY
44
45
  end
45
46
  add_offense(node, :expression, format(MSG, src[0, 2], extra))
46
47
  end
47
48
 
48
49
  def autocorrect(node)
49
- delimiter = node.loc.expression.source =~ /^%Q[^"]+$|'/ ? '"' : "'"
50
+ delimiter =
51
+ node.loc.expression.source =~ /^%Q[^"]+$|'/ ? QUOTE : SINGLE_QUOTE
50
52
  lambda do |corrector|
51
53
  corrector.replace(node.loc.begin, delimiter)
52
54
  corrector.replace(node.loc.end, delimiter)
53
55
  end
54
56
  end
57
+
58
+ def string_literal?(node)
59
+ node.loc.respond_to?(:begin) && node.loc.respond_to?(:end) &&
60
+ node.loc.begin && node.loc.end
61
+ end
62
+
63
+ def start_with_percent_q_variant?(string)
64
+ string.start_with?(PERCENT_Q) || string.start_with?(PERCENT_CAPITAL_Q)
65
+ end
55
66
  end
56
67
  end
57
68
  end
@@ -23,6 +23,11 @@ module RuboCop
23
23
  check_name(node, name, node.loc.name)
24
24
  end
25
25
 
26
+ def on_arg(node)
27
+ name, = *node
28
+ check_name(node, name, node.loc.name)
29
+ end
30
+
26
31
  private
27
32
 
28
33
  def message(style)
@@ -16,7 +16,7 @@ module RuboCop
16
16
  def handle(node)
17
17
  length = node.loc.expression.source.lines.to_a.size
18
18
  return unless length > 1
19
- return unless node.loc.begin && node.loc.begin.is?('do')
19
+ return unless node.loc.begin && node.loc.begin.is?('do')
20
20
 
21
21
  add_offense(node, :begin, error_message(node.type))
22
22
  end
@@ -13,6 +13,7 @@ module RuboCop
13
13
  include ConfigurableMax
14
14
 
15
15
  MSG = 'Use `%w` or `%W` for array of words.'
16
+ QUESTION_MARK_SIZE = '?'.size
16
17
 
17
18
  def on_array(node)
18
19
  array_elems = node.children
@@ -61,7 +62,8 @@ module RuboCop
61
62
 
62
63
  def autocorrect(node)
63
64
  @interpolated = false
64
- contents = node.children.map { |n| source_for(n) }.join(' ')
65
+ contents = autocorrect_words(node.children, node.loc.line)
66
+
65
67
  char = @interpolated ? 'W' : 'w'
66
68
 
67
69
  lambda do |corrector|
@@ -69,10 +71,21 @@ module RuboCop
69
71
  end
70
72
  end
71
73
 
74
+ def autocorrect_words(word_nodes, base_line_number)
75
+ previous_node_line_number = base_line_number
76
+ word_nodes.map do |node|
77
+ number_of_line_breaks = node.loc.line - previous_node_line_number
78
+ line_breaks = "\n" * number_of_line_breaks
79
+ previous_node_line_number = node.loc.line
80
+
81
+ line_breaks + source_for(node)
82
+ end.join(' ')
83
+ end
84
+
72
85
  def source_for(str_node)
73
86
  if character_literal?(str_node)
74
87
  @interpolated = true
75
- begin_pos = str_node.loc.expression.begin_pos + '?'.length
88
+ begin_pos = str_node.loc.expression.begin_pos + QUESTION_MARK_SIZE
76
89
  end_pos = str_node.loc.expression.end_pos
77
90
  else
78
91
  begin_pos = str_node.loc.begin.end_pos
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  # FIXME
6
6
  class Team
7
- attr_reader :errors, :updated_source_file
7
+ attr_reader :errors, :warnings, :updated_source_file
8
8
 
9
9
  alias_method :updated_source_file?, :updated_source_file
10
10
 
@@ -13,6 +13,7 @@ module RuboCop
13
13
  @config = config
14
14
  @options = options || { auto_correct: false, debug: false }
15
15
  @errors = []
16
+ @warnings = []
16
17
  end
17
18
 
18
19
  def autocorrect?
@@ -79,7 +80,14 @@ module RuboCop
79
80
  cop.relevant_file?(buffer.name) && cop.corrections.any?
80
81
  end
81
82
  if cop_with_corrections
82
- corrector = Corrector.new(buffer, cop_with_corrections.corrections)
83
+ corrections = cop_with_corrections.corrections
84
+ # Be extra careful if there are tabs in the source and just correct
85
+ # one offense, because inserting or removing space next to a tab has
86
+ # special implications, and existing ranges can't be used after such
87
+ # a change.
88
+ corrections = [corrections.first] if buffer.source =~ /\t/
89
+
90
+ corrector = Corrector.new(buffer, corrections)
83
91
  corrector.rewrite
84
92
  else
85
93
  buffer.source
@@ -89,13 +97,25 @@ module RuboCop
89
97
  def process_commissioner_errors(file, file_errors)
90
98
  file_errors.each do |cop, errors|
91
99
  errors.each do |e|
92
- handle_error(e,
93
- "An error occurred while #{cop.name}".color(:red) +
94
- " cop was inspecting #{file}.".color(:red))
100
+ if e.is_a?(Warning)
101
+ handle_warning(e,
102
+ Rainbow("#{e.message} (from file: " \
103
+ "#{file})").yellow)
104
+ else
105
+ handle_error(e,
106
+ Rainbow("An error occurred while #{cop.name}" \
107
+ " cop was inspecting #{file}.").red)
108
+ end
95
109
  end
96
110
  end
97
111
  end
98
112
 
113
+ def handle_warning(e, message)
114
+ @warnings << message
115
+ warn message
116
+ puts e.backtrace if debug?
117
+ end
118
+
99
119
  def handle_error(e, message)
100
120
  @errors << message
101
121
  warn message
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
+ # rubocop:disable Metrics/ModuleLength
3
4
  module RuboCop
4
5
  module Cop
5
6
  # This module contains a collection of useful utility methods.
@@ -12,6 +13,10 @@ module RuboCop
12
13
  SHORTHAND_ASGN_NODES = [:op_asgn, :or_asgn, :and_asgn]
13
14
  ASGN_NODES = EQUALS_ASGN_NODES + SHORTHAND_ASGN_NODES
14
15
 
16
+ LITERALS = [:str, :dstr, :int, :float, :sym, :dsym, :array,
17
+ :hash, :regexp, :nil, :true, :false]
18
+ BASIC_LITERALS = LITERALS - [:dstr, :dsym, :array, :hash]
19
+
15
20
  # http://phrogz.net/programmingruby/language.html#table_18.4
16
21
  # Backtick is added last just to help editors parse this code.
17
22
  OPERATOR_METHODS = %w(
@@ -186,8 +191,8 @@ module RuboCop
186
191
  end
187
192
 
188
193
  def begins_its_line?(range)
189
- source_before_end = range.source_buffer.source[0...range.begin_pos]
190
- source_before_end =~ /\n\s*\Z/
194
+ source_before_range = range.source_buffer.source[0...range.begin_pos]
195
+ source_before_range.rpartition("\n").last.strip.empty?
191
196
  end
192
197
 
193
198
  def within_node?(inner, outer)
@@ -80,9 +80,9 @@ module RuboCop
80
80
  case branch_point_node.type
81
81
  when :if then if_body_name
82
82
  when :case then case_body_name
83
- when *LOGICAL_OPERATOR_TYPES then logical_operator_body_name
84
83
  when RESCUE_TYPE then rescue_body_name
85
84
  when ENSURE_TYPE then ensure_body_name
85
+ when *LOGICAL_OPERATOR_TYPES then logical_operator_body_name
86
86
  else fail InvalidBranchBodyError
87
87
  end
88
88
  rescue InvalidBranchBodyError
@@ -133,7 +133,7 @@ module RuboCop
133
133
  end
134
134
 
135
135
  def body_index
136
- branch_point_node.children.index(branch_body_node)
136
+ branch_point_node.children.index { |n| n.equal?(branch_body_node) }
137
137
  end
138
138
 
139
139
  def set_branch_point_and_body_nodes!
@@ -157,14 +157,14 @@ module RuboCop
157
157
  child_index = parent_node.children.index(child_node)
158
158
 
159
159
  case parent_node.type
160
- when *BRANCH_TYPES
161
- child_index != CONDITION_INDEX_OF_BRANCH_NODE
162
- when *LOGICAL_OPERATOR_TYPES
163
- child_index != LEFT_SIDE_INDEX_OF_LOGICAL_OPERATOR_NODE
164
160
  when RESCUE_TYPE
165
161
  true
166
162
  when ENSURE_TYPE
167
163
  child_index != ENSURE_INDEX_OF_ENSURE_NODE
164
+ when *BRANCH_TYPES
165
+ child_index != CONDITION_INDEX_OF_BRANCH_NODE
166
+ when *LOGICAL_OPERATOR_TYPES
167
+ child_index != LEFT_SIDE_INDEX_OF_LOGICAL_OPERATOR_NODE
168
168
  else
169
169
  false
170
170
  end
@@ -106,28 +106,28 @@ module RuboCop
106
106
  # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
107
107
  def dispatch_node(node)
108
108
  case node.type
109
- when *ARGUMENT_DECLARATION_TYPES
110
- process_variable_declaration(node)
111
109
  when VARIABLE_ASSIGNMENT_TYPE
112
110
  process_variable_assignment(node)
113
111
  when REGEXP_NAMED_CAPTURE_TYPE
114
112
  process_regexp_named_captures(node)
115
- when *OPERATOR_ASSIGNMENT_TYPES
116
- process_variable_operator_assignment(node)
117
113
  when MULTIPLE_ASSIGNMENT_TYPE
118
114
  process_variable_multiple_assignment(node)
119
115
  when VARIABLE_REFERENCE_TYPE
120
116
  process_variable_referencing(node)
121
- when *LOOP_TYPES
122
- process_loop(node)
123
117
  when RESCUE_TYPE
124
118
  process_rescue(node)
125
119
  when ZERO_ARITY_SUPER_TYPE
126
120
  process_zero_arity_super(node)
127
- when *SCOPE_TYPES
128
- process_scope(node)
129
121
  when SEND_TYPE
130
122
  process_send(node)
123
+ when *ARGUMENT_DECLARATION_TYPES
124
+ process_variable_declaration(node)
125
+ when *OPERATOR_ASSIGNMENT_TYPES
126
+ process_variable_operator_assignment(node)
127
+ when *LOOP_TYPES
128
+ process_loop(node)
129
+ when *SCOPE_TYPES
130
+ process_scope(node)
131
131
  end
132
132
  end
133
133
  # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
@@ -326,13 +326,13 @@ module RuboCop
326
326
  case node.type
327
327
  when :lvar
328
328
  referenced_variable_names_in_loop << node.children.first
329
+ when :lvasgn
330
+ assignment_nodes_in_loop << node
329
331
  when *OPERATOR_ASSIGNMENT_TYPES
330
332
  asgn_node = node.children.first
331
333
  if asgn_node.type == :lvasgn
332
334
  referenced_variable_names_in_loop << asgn_node.children.first
333
335
  end
334
- when :lvasgn
335
- assignment_nodes_in_loop << node
336
336
  end
337
337
  end
338
338
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- # rubocop:disable Metrics/LineLength, Lint/UnusedMethodArgument
3
+ # rubocop:disable Metrics/LineLength
4
4
 
5
5
  module RuboCop
6
6
  module Formatter