rubocop 0.39.0 → 0.40.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -1
  3. data/config/default.yml +65 -2
  4. data/config/disabled.yml +0 -28
  5. data/config/enabled.yml +40 -0
  6. data/lib/rubocop.rb +3 -0
  7. data/lib/rubocop/ast_node.rb +28 -13
  8. data/lib/rubocop/cached_data.rb +15 -2
  9. data/lib/rubocop/cli.rb +24 -8
  10. data/lib/rubocop/config.rb +3 -3
  11. data/lib/rubocop/config_loader.rb +0 -7
  12. data/lib/rubocop/cop/cop.rb +2 -2
  13. data/lib/rubocop/cop/lint/condition_position.rb +3 -1
  14. data/lib/rubocop/cop/lint/else_layout.rb +3 -2
  15. data/lib/rubocop/cop/lint/end_alignment.rb +2 -2
  16. data/lib/rubocop/cop/lint/nested_method_definition.rb +15 -9
  17. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  18. data/lib/rubocop/cop/lint/unused_block_argument.rb +2 -0
  19. data/lib/rubocop/cop/lint/useless_access_modifier.rb +86 -20
  20. data/lib/rubocop/cop/lint/useless_array_splat.rb +56 -0
  21. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  22. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +11 -25
  23. data/lib/rubocop/cop/mixin/if_node.rb +4 -0
  24. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +14 -12
  25. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +75 -9
  26. data/lib/rubocop/cop/mixin/on_normal_if_unless.rb +1 -1
  27. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -2
  28. data/lib/rubocop/cop/mixin/trailing_comma.rb +15 -5
  29. data/lib/rubocop/cop/performance/case_when_splat.rb +71 -44
  30. data/lib/rubocop/cop/performance/detect.rb +28 -18
  31. data/lib/rubocop/cop/performance/end_with.rb +1 -1
  32. data/lib/rubocop/cop/performance/redundant_merge.rb +29 -11
  33. data/lib/rubocop/cop/performance/start_with.rb +1 -1
  34. data/lib/rubocop/cop/performance/string_replacement.rb +39 -20
  35. data/lib/rubocop/cop/rails/action_filter.rb +1 -2
  36. data/lib/rubocop/cop/rails/date.rb +2 -5
  37. data/lib/rubocop/cop/rails/time_zone.rb +3 -6
  38. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +57 -0
  39. data/lib/rubocop/cop/style/alias.rb +10 -3
  40. data/lib/rubocop/cop/style/align_parameters.rb +8 -2
  41. data/lib/rubocop/cop/style/and_or.rb +29 -21
  42. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  43. data/lib/rubocop/cop/style/collection_methods.rb +1 -2
  44. data/lib/rubocop/cop/style/comment_indentation.rb +1 -1
  45. data/lib/rubocop/cop/style/conditional_assignment.rb +13 -7
  46. data/lib/rubocop/cop/style/empty_case_condition.rb +96 -0
  47. data/lib/rubocop/cop/style/encoding.rb +9 -5
  48. data/lib/rubocop/cop/style/extra_spacing.rb +22 -7
  49. data/lib/rubocop/cop/style/file_name.rb +7 -2
  50. data/lib/rubocop/cop/style/guard_clause.rb +18 -10
  51. data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
  52. data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -1
  53. data/lib/rubocop/cop/style/indentation_width.rb +7 -4
  54. data/lib/rubocop/cop/style/lambda.rb +98 -30
  55. data/lib/rubocop/cop/style/line_end_concatenation.rb +5 -0
  56. data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +34 -9
  57. data/lib/rubocop/cop/style/multiline_assignment_layout.rb +2 -1
  58. data/lib/rubocop/cop/style/multiline_hash_brace_layout.rb +42 -17
  59. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +39 -14
  60. data/lib/rubocop/cop/style/multiline_method_definition_brace_layout.rb +36 -15
  61. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +8 -6
  62. data/lib/rubocop/cop/style/negated_while.rb +2 -1
  63. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +15 -0
  64. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -8
  65. data/lib/rubocop/cop/style/next.rb +1 -1
  66. data/lib/rubocop/cop/style/not.rb +5 -2
  67. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  68. data/lib/rubocop/cop/style/raise_args.rb +70 -7
  69. data/lib/rubocop/cop/style/redundant_exception.rb +34 -20
  70. data/lib/rubocop/cop/style/redundant_parentheses.rb +27 -1
  71. data/lib/rubocop/cop/style/space_after_colon.rb +14 -10
  72. data/lib/rubocop/cop/style/space_after_comma.rb +5 -0
  73. data/lib/rubocop/cop/style/space_after_not.rb +3 -4
  74. data/lib/rubocop/cop/style/space_after_semicolon.rb +5 -0
  75. data/lib/rubocop/cop/style/space_around_operators.rb +2 -1
  76. data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
  77. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  78. data/lib/rubocop/cop/style/string_methods.rb +1 -2
  79. data/lib/rubocop/cop/style/symbol_proc.rb +7 -1
  80. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +25 -0
  81. data/lib/rubocop/cop/style/word_array.rb +50 -22
  82. data/lib/rubocop/cop/util.rb +0 -4
  83. data/lib/rubocop/formatter/clang_style_formatter.rb +38 -22
  84. data/lib/rubocop/options.rb +45 -10
  85. data/lib/rubocop/path_util.rb +2 -34
  86. data/lib/rubocop/result_cache.rb +10 -4
  87. data/lib/rubocop/runner.rb +5 -3
  88. data/lib/rubocop/version.rb +1 -1
  89. metadata +7 -4
@@ -5,6 +5,10 @@ module RuboCop
5
5
  module Cop
6
6
  # Common functionality for checking if nodes.
7
7
  module IfNode
8
+ def ternary?(node)
9
+ node.loc.respond_to?(:question)
10
+ end
11
+
8
12
  def modifier_if?(node)
9
13
  node.loc.respond_to?(:keyword) &&
10
14
  %w(if unless).include?(node.loc.keyword.source) &&
@@ -1,8 +1,6 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'pp'
5
-
6
4
  module RuboCop
7
5
  module Cop
8
6
  # Common functionality for checking multiline method calls and binary
@@ -36,16 +34,20 @@ module RuboCop
36
34
  if operator?(method_name) && args.any?
37
35
  args.first.source_range # not used for method calls
38
36
  else
39
- dot = send_node.loc.dot
40
- selector = send_node.loc.selector
41
- if dot && selector && dot.line == selector.line
42
- dot.join(selector)
43
- elsif selector
44
- selector
45
- elsif dot.line == send_node.loc.begin.line
46
- # lambda.(args)
47
- dot.join(send_node.loc.begin)
48
- end
37
+ regular_method_right_hand_side(send_node)
38
+ end
39
+ end
40
+
41
+ def regular_method_right_hand_side(send_node)
42
+ dot = send_node.loc.dot
43
+ selector = send_node.loc.selector
44
+ if dot && selector && dot.line == selector.line
45
+ dot.join(selector)
46
+ elsif selector
47
+ selector
48
+ elsif dot.line == send_node.loc.begin.line
49
+ # lambda.(args)
50
+ dot.join(send_node.loc.begin)
49
51
  end
50
52
  end
51
53
 
@@ -3,21 +3,23 @@
3
3
 
4
4
  module RuboCop
5
5
  module Cop
6
- # Common functionality for checking that the closing brace of a literal is
7
- # symmetrical with respect to the opening brace and contained elements.
6
+ # Common functionality for checking the closing brace of a literal is
7
+ # either on the same line as the last contained elements, or a new line.
8
8
  module MultilineLiteralBraceLayout
9
+ include ConfigurableEnforcedStyle
10
+
9
11
  def check_brace_layout(node)
10
12
  return unless node.loc.begin # Ignore implicit literals.
11
13
  return if children(node).empty? # Ignore empty literals.
12
14
 
13
- if opening_brace_on_same_line?(node)
14
- return if closing_brace_on_same_line?(node)
15
-
16
- add_offense(node, :expression, self.class::SAME_LINE_MESSAGE)
17
- else
18
- return unless closing_brace_on_same_line?(node)
15
+ # If the last node is or contains a conflicting HEREDOC, we don't want
16
+ # to adjust the brace layout because this will result in invalid code.
17
+ return if last_line_heredoc?(children(node).last)
19
18
 
20
- add_offense(node, :expression, self.class::NEW_LINE_MESSAGE)
19
+ case style
20
+ when :symmetrical then handle_symmetrical(node)
21
+ when :new_line then handle_new_line(node)
22
+ when :same_line then handle_same_line(node)
21
23
  end
22
24
  end
23
25
 
@@ -38,6 +40,30 @@ module RuboCop
38
40
 
39
41
  private
40
42
 
43
+ def handle_new_line(node)
44
+ return unless closing_brace_on_same_line?(node)
45
+
46
+ add_offense(node, :expression, self.class::ALWAYS_NEW_LINE_MESSAGE)
47
+ end
48
+
49
+ def handle_same_line(node)
50
+ return if closing_brace_on_same_line?(node)
51
+
52
+ add_offense(node, :expression, self.class::ALWAYS_SAME_LINE_MESSAGE)
53
+ end
54
+
55
+ def handle_symmetrical(node)
56
+ if opening_brace_on_same_line?(node)
57
+ return if closing_brace_on_same_line?(node)
58
+
59
+ add_offense(node, :expression, self.class::SAME_LINE_MESSAGE)
60
+ else
61
+ return unless closing_brace_on_same_line?(node)
62
+
63
+ add_offense(node, :expression, self.class::NEW_LINE_MESSAGE)
64
+ end
65
+ end
66
+
41
67
  def children(node)
42
68
  node.children
43
69
  end
@@ -53,6 +79,46 @@ module RuboCop
53
79
  def closing_brace_on_same_line?(node)
54
80
  node.loc.end.line == children(node).last.loc.last_line
55
81
  end
82
+
83
+ # Starting with the parent node and recursively for the parent node's
84
+ # children, check if the node is a HEREDOC and if the HEREDOC ends below
85
+ # or on the last line of the parent node.
86
+ #
87
+ # Example:
88
+ #
89
+ # # node is `b: ...` parameter
90
+ # # last_line_heredoc?(node) => false
91
+ # foo(a,
92
+ # b: {
93
+ # a: 1,
94
+ # c: <<-EOM
95
+ # baz
96
+ # EOM
97
+ # }
98
+ # )
99
+ #
100
+ # # node is `b: ...` parameter
101
+ # # last_line_heredoc?(node) => true
102
+ # foo(a,
103
+ # b: <<-EOM
104
+ # baz
105
+ # EOM
106
+ # )
107
+ def last_line_heredoc?(node, parent = nil)
108
+ parent ||= node
109
+
110
+ return false unless node.respond_to?(:loc)
111
+
112
+ if node.loc.respond_to?(:heredoc_end) &&
113
+ node.loc.heredoc_end.last_line >= parent.loc.last_line
114
+ return true
115
+ end
116
+
117
+ return false unless node.respond_to?(:children)
118
+ return false if node.children.empty?
119
+
120
+ node.children.any? { |child| last_line_heredoc?(child, parent) }
121
+ end
56
122
  end
57
123
  end
58
124
  end
@@ -13,7 +13,7 @@ module RuboCop
13
13
 
14
14
  def invoke_hook_for_normal_if_unless(node)
15
15
  # We won't check modifier or ternary conditionals.
16
- return if modifier_if?(node) || ternary_op?(node)
16
+ return if modifier_if?(node) || ternary?(node)
17
17
  on_normal_if_unless(node)
18
18
  end
19
19
 
@@ -20,8 +20,7 @@ module RuboCop
20
20
  end
21
21
 
22
22
  def space_forbidden_before_rcurly?
23
- cfg = config.for_cop('Style/SpaceInsideBlockBraces')
24
- style = cfg['EnforcedStyle'] || 'space'
23
+ style = space_style_before_rcurly
25
24
  style == 'no_space'
26
25
  end
27
26
 
@@ -36,7 +36,7 @@ module RuboCop
36
36
  extra_info)
37
37
  end
38
38
  elsif should_have_comma?(style, node)
39
- put_comma(items, kind, sb)
39
+ put_comma(node, items, kind, sb)
40
40
  end
41
41
  end
42
42
 
@@ -87,10 +87,11 @@ module RuboCop
87
87
 
88
88
  _receiver, _method_name, *args = *node
89
89
  args.flat_map do |a|
90
- # For each argument, if it is a multi-line hash,
90
+ # For each argument, if it is a multi-line hash without braces,
91
91
  # then promote the hash elements to method arguments
92
92
  # for the purpose of determining multi-line-ness.
93
- if a.hash_type? && a.loc.first_line != a.loc.last_line
93
+ if a.hash_type? && a.loc.first_line != a.loc.last_line &&
94
+ !brackets?(a)
94
95
  a.children
95
96
  else
96
97
  a
@@ -111,7 +112,7 @@ module RuboCop
111
112
  "#{extra_info}.")
112
113
  end
113
114
 
114
- def put_comma(items, kind, sb)
115
+ def put_comma(node, items, kind, sb)
115
116
  last_item = items.last
116
117
  return if last_item.type == :block_pass
117
118
 
@@ -120,11 +121,20 @@ module RuboCop
120
121
  ix += last_expr.source[ix..-1] =~ /\S/
121
122
  range = Parser::Source::Range.new(sb, last_expr.begin_pos + ix,
122
123
  last_expr.end_pos)
123
- add_offense(range, range,
124
+ autocorrect_range = avoid_autocorrect?(elements(node)) ? nil : range
125
+
126
+ add_offense(autocorrect_range, range,
124
127
  format(MSG, 'Put a', format(kind, 'a multiline') + '.'))
125
128
  end
126
129
 
130
+ # By default, there's no reason to avoid auto-correct.
131
+ def avoid_autocorrect?(_)
132
+ false
133
+ end
134
+
127
135
  def autocorrect(range)
136
+ return unless range
137
+
128
138
  lambda do |corrector|
129
139
  case range.source
130
140
  when ',' then corrector.remove(range)
@@ -57,23 +57,17 @@ module RuboCop
57
57
  MSG = 'Place `when` conditions with a splat ' \
58
58
  'at the end of the `when` branches.'.freeze
59
59
  ARRAY_MSG = 'Do not expand array literals in `when` conditions.'.freeze
60
- OPEN_BRACKET = '['.freeze
61
60
  PERCENT_W = '%w'.freeze
62
61
  PERCENT_CAPITAL_W = '%W'.freeze
63
62
  PERCENT_I = '%i'.freeze
64
63
  PERCENT_CAPITAL_I = '%I'.freeze
65
64
 
66
- def initialize(*)
67
- super
68
- @reordered_splat_condition = false
69
- end
70
-
71
65
  def on_case(node)
72
66
  _case_branch, *when_branches, _else_branch = *node
73
67
  when_conditions =
74
68
  when_branches.each_with_object([]) do |branch, conditions|
75
- condition, = *branch
76
- conditions << condition
69
+ *condition, _ = *branch
70
+ condition.each { |c| conditions << c }
77
71
  end
78
72
 
79
73
  splat_offenses(when_conditions).reverse_each do |condition|
@@ -85,19 +79,74 @@ module RuboCop
85
79
  end
86
80
 
87
81
  def autocorrect(node)
88
- condition, = *node
89
- variable, = *condition
90
- if variable.array_type?
91
- correct_array_literal(condition, variable)
92
- else
93
- return if @reordered_splat_condition
94
- @reordered_splat_condition = true
95
- reorder_splat_condition(node)
82
+ *conditions, _body = *node
83
+
84
+ new_condition =
85
+ conditions.each_with_object([]) do |condition, correction|
86
+ variable, = *condition
87
+ if variable.respond_to?(:array_type?) && variable.array_type?
88
+ correction << expand_percent_array(variable)
89
+ next
90
+ end
91
+
92
+ correction << condition.source
93
+ end
94
+ new_condition = new_condition.join(', ')
95
+
96
+ lambda do |corrector|
97
+ if needs_reorder?(conditions)
98
+ reorder_condition(corrector, node, new_condition)
99
+ else
100
+ inline_fix_branch(corrector, node, conditions, new_condition)
101
+ end
96
102
  end
97
103
  end
98
104
 
99
105
  private
100
106
 
107
+ def inline_fix_branch(corrector, node, conditions, new_condition)
108
+ range =
109
+ Parser::Source::Range.new(node.loc.expression.source_buffer,
110
+ conditions[0].loc.expression.begin_pos,
111
+ conditions[-1].loc.expression.end_pos)
112
+ corrector.replace(range, new_condition)
113
+ end
114
+
115
+ def reorder_condition(corrector, node, new_condition)
116
+ *_conditions, body = *node
117
+ parent = node.parent
118
+ _case_branch, *when_branches, _else_branch = *parent
119
+ current_index = when_branches.index { |branch| branch == node }
120
+ next_branch = when_branches[current_index + 1]
121
+ range = Parser::Source::Range.new(parent,
122
+ node.source_range.begin_pos,
123
+ next_branch.source_range.begin_pos)
124
+
125
+ corrector.remove(range)
126
+
127
+ correction = if same_line?(node, body)
128
+ new_condition_with_then(node, new_condition)
129
+ else
130
+ new_branch_without_then(node, body, new_condition)
131
+ end
132
+
133
+ corrector.insert_after(when_branches.last.source_range, correction)
134
+ end
135
+
136
+ def same_line?(node, other)
137
+ node.loc.first_line == other.loc.first_line
138
+ end
139
+
140
+ def new_condition_with_then(node, new_condition)
141
+ "\n#{' ' * node.loc.column}when " \
142
+ "#{new_condition} then #{node.children.last.source}"
143
+ end
144
+
145
+ def new_branch_without_then(node, body, new_condition)
146
+ "\n#{' ' * node.loc.column}when #{new_condition}\n" \
147
+ "#{' ' * body.loc.column}#{node.children.last.source}"
148
+ end
149
+
101
150
  def splat_offenses(when_conditions)
102
151
  found_non_splat = false
103
152
  when_conditions.reverse.each_with_object([]) do |condition, result|
@@ -115,34 +164,10 @@ module RuboCop
115
164
  !condition.splat_type?
116
165
  end
117
166
 
118
- def correct_array_literal(condition, variable)
119
- lambda do |corrector|
120
- array_start = variable.loc.begin.source
121
-
122
- if array_start.start_with?(OPEN_BRACKET)
123
- corrector.remove(condition.loc.operator)
124
- corrector.remove(variable.loc.begin)
125
- corrector.remove(variable.loc.end)
126
- else
127
- corrector.replace(condition.source_range,
128
- expand_percent_array(variable))
129
- end
130
- end
131
- end
132
-
133
- def reorder_splat_condition(node)
134
- _case_branch, *when_branches, _else_branch = *node.parent
135
- current_index = when_branches.index { |branch| branch == node }
136
- next_branch = when_branches[current_index + 1]
137
- correction = "\n#{offset(node)}#{node.source}"
138
- range =
139
- Parser::Source::Range.new(node.parent,
140
- node.source_range.begin_pos,
141
- next_branch.source_range.begin_pos)
142
-
143
- lambda do |corrector|
144
- corrector.remove(range)
145
- corrector.insert_after(when_branches.last.source_range, correction)
167
+ def needs_reorder?(conditions)
168
+ conditions.any? do |condition|
169
+ variable, = *condition
170
+ condition.splat_type? && !(variable && variable.array_type?)
146
171
  end
147
172
  end
148
173
 
@@ -159,6 +184,8 @@ module RuboCop
159
184
  ":#{elements.join(', :')}"
160
185
  elsif array_start.start_with?(PERCENT_CAPITAL_I)
161
186
  %(:"#{elements.join('", :"')}")
187
+ else
188
+ elements.join(', ')
162
189
  end
163
190
  end
164
191
  end
@@ -33,23 +33,12 @@ module RuboCop
33
33
  def on_send(node)
34
34
  return unless should_run?
35
35
  receiver, second_method, *args = *node
36
- return unless check_second_call(receiver, second_method, args)
36
+ return if accept_second_call?(receiver, second_method, args)
37
37
 
38
38
  receiver, _args, body = *receiver if receiver.block_type?
39
- caller, first_method, args = *receiver
40
-
41
- # check that we have usual block or block pass
42
- return if body.nil? && (args.nil? || !args.block_pass_type?)
43
- return unless SELECT_METHODS.include?(first_method)
44
- return if lazy?(caller)
39
+ return if accept_first_call?(receiver, body)
45
40
 
46
- range = receiver.loc.selector.join(node.loc.selector)
47
-
48
- message = second_method == :last ? REVERSE_MSG : MSG
49
- add_offense(node, range, format(message,
50
- preferred_method,
51
- first_method,
52
- second_method))
41
+ offense(node, receiver, second_method)
53
42
  end
54
43
 
55
44
  def autocorrect(node)
@@ -79,10 +68,31 @@ module RuboCop
79
68
  config['Rails'.freeze]['Enabled'.freeze])
80
69
  end
81
70
 
82
- def check_second_call(receiver, method, args)
83
- receiver &&
84
- DANGEROUS_METHODS.include?(method) &&
85
- args.empty?
71
+ def accept_second_call?(receiver, method, args)
72
+ !receiver ||
73
+ !DANGEROUS_METHODS.include?(method) ||
74
+ !args.empty?
75
+ end
76
+
77
+ def accept_first_call?(receiver, body)
78
+ caller, first_method, args = *receiver
79
+
80
+ # check that we have usual block or block pass
81
+ return true if body.nil? && (args.nil? || !args.block_pass_type?)
82
+ return true unless SELECT_METHODS.include?(first_method)
83
+
84
+ lazy?(caller)
85
+ end
86
+
87
+ def offense(node, receiver, second_method)
88
+ _caller, first_method, _args = *receiver
89
+ range = receiver.loc.selector.join(node.loc.selector)
90
+
91
+ message = second_method == :last ? REVERSE_MSG : MSG
92
+ add_offense(node, range, format(message,
93
+ preferred_method,
94
+ first_method,
95
+ second_method))
86
96
  end
87
97
 
88
98
  def preferred_method