rubocop 0.37.2 → 0.38.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/assets/output.html.erb +3 -0
  4. data/config/default.yml +14 -1
  5. data/config/disabled.yml +0 -4
  6. data/lib/rubocop.rb +0 -1
  7. data/lib/rubocop/ast_node.rb +6 -0
  8. data/lib/rubocop/ast_node/traversal.rb +1 -1
  9. data/lib/rubocop/cached_data.rb +6 -2
  10. data/lib/rubocop/config_loader.rb +7 -3
  11. data/lib/rubocop/cop/cop.rb +1 -1
  12. data/lib/rubocop/cop/lint/block_alignment.rb +91 -17
  13. data/lib/rubocop/cop/lint/else_layout.rb +24 -14
  14. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +6 -12
  15. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +16 -10
  16. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  17. data/lib/rubocop/cop/lint/unneeded_disable.rb +36 -23
  18. data/lib/rubocop/cop/lint/unused_block_argument.rb +0 -1
  19. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  20. data/lib/rubocop/cop/metrics/line_length.rb +25 -18
  21. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
  22. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  23. data/lib/rubocop/cop/mixin/if_node.rb +0 -4
  24. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -1
  25. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +6 -6
  26. data/lib/rubocop/cop/mixin/trailing_comma.rb +26 -24
  27. data/lib/rubocop/cop/mixin/unused_argument.rb +9 -1
  28. data/lib/rubocop/cop/offense.rb +16 -0
  29. data/lib/rubocop/cop/performance/casecmp.rb +15 -10
  30. data/lib/rubocop/cop/performance/count.rb +3 -2
  31. data/lib/rubocop/cop/performance/fixed_size.rb +13 -12
  32. data/lib/rubocop/cop/performance/reverse_each.rb +15 -14
  33. data/lib/rubocop/cop/rails/date.rb +13 -1
  34. data/lib/rubocop/cop/rails/output.rb +2 -1
  35. data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -1
  36. data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
  37. data/lib/rubocop/cop/style/and_or.rb +1 -2
  38. data/lib/rubocop/cop/style/block_delimiters.rb +41 -48
  39. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +4 -2
  40. data/lib/rubocop/cop/style/class_and_module_children.rb +3 -3
  41. data/lib/rubocop/cop/style/comment_annotation.rb +8 -10
  42. data/lib/rubocop/cop/style/conditional_assignment.rb +7 -2
  43. data/lib/rubocop/cop/style/encoding.rb +15 -10
  44. data/lib/rubocop/cop/style/extra_spacing.rb +14 -12
  45. data/lib/rubocop/cop/style/file_name.rb +3 -7
  46. data/lib/rubocop/cop/style/lambda.rb +17 -6
  47. data/lib/rubocop/cop/style/method_call_parentheses.rb +1 -1
  48. data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
  49. data/lib/rubocop/cop/style/nested_modifier.rb +7 -1
  50. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +0 -4
  51. data/lib/rubocop/cop/style/not.rb +27 -5
  52. data/lib/rubocop/cop/style/one_line_conditional.rb +21 -0
  53. data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -1
  54. data/lib/rubocop/cop/style/signal_exception.rb +28 -26
  55. data/lib/rubocop/cop/style/space_around_keyword.rb +10 -6
  56. data/lib/rubocop/cop/style/string_literals.rb +1 -0
  57. data/lib/rubocop/cop/style/unless_else.rb +24 -0
  58. data/lib/rubocop/cop/style/unneeded_interpolation.rb +26 -13
  59. data/lib/rubocop/cop/style/zero_length_predicate.rb +5 -3
  60. data/lib/rubocop/cop/team.rb +6 -1
  61. data/lib/rubocop/cop/util.rb +13 -6
  62. data/lib/rubocop/formatter/clang_style_formatter.rb +18 -14
  63. data/lib/rubocop/formatter/html_formatter.rb +9 -10
  64. data/lib/rubocop/rake_task.rb +4 -4
  65. data/lib/rubocop/remote_config.rb +4 -2
  66. data/lib/rubocop/result_cache.rb +14 -8
  67. data/lib/rubocop/runner.rb +9 -0
  68. data/lib/rubocop/version.rb +1 -1
  69. data/spec/support/cop_helper.rb +81 -0
  70. metadata +13 -7
  71. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +0 -57
@@ -15,7 +15,7 @@ module RuboCop
15
15
  'called `%s`.'.freeze
16
16
  MSG_REGEX = '`%s` should match `%s`.'.freeze
17
17
 
18
- SNAKE_CASE = /^[\da-z_]+$/
18
+ SNAKE_CASE = /^[\da-z_.?!]+$/
19
19
 
20
20
  def investigate(processed_source)
21
21
  file_path = processed_source.buffer.name
@@ -44,12 +44,8 @@ module RuboCop
44
44
 
45
45
  private
46
46
 
47
- def snake_case?(basename)
48
- basename.split('.').all? { |fragment| fragment =~ SNAKE_CASE }
49
- end
50
-
51
47
  def shebang?(line)
52
- line.start_with?('#!')
48
+ line && line.start_with?('#!')
53
49
  end
54
50
 
55
51
  def expect_matching_definition?
@@ -62,7 +58,7 @@ module RuboCop
62
58
 
63
59
  def filename_good?(basename)
64
60
  basename = basename.sub(/\.[^\.]+$/, '')
65
- regex ? basename =~ regex : snake_case?(basename)
61
+ basename =~ (regex || SNAKE_CASE)
66
62
  end
67
63
 
68
64
  def find_class_or_module(node, namespace)
@@ -8,8 +8,6 @@ module RuboCop
8
8
  # anonymous functions and uses of the 1.9 lambda syntax for multi-line
9
9
  # anonymous functions.
10
10
  class Lambda < Cop
11
- include AutocorrectUnlessChangingAST
12
-
13
11
  SINGLE_MSG = 'Use the new lambda literal syntax ' \
14
12
  '`->(params) {...}`.'.freeze
15
13
  SINGLE_NO_ARG_MSG = 'Use the new lambda literal syntax ' \
@@ -26,7 +24,7 @@ module RuboCop
26
24
  block_method, args, = *node
27
25
 
28
26
  return unless block_method == TARGET
29
- selector = block_method.loc.selector.source
27
+ selector = block_method.source
30
28
  length = lambda_length(node)
31
29
 
32
30
  if selector != '->' && length == 1
@@ -53,10 +51,14 @@ module RuboCop
53
51
  end_line - start_line + 1
54
52
  end
55
53
 
56
- def correction(node)
57
- lambda do |corrector|
58
- block_method, _args = *node
54
+ def autocorrect(node)
55
+ block_method, _args = *node
56
+ selector = block_method.source
59
57
 
58
+ # Don't autocorrect if this would change the meaning of the code
59
+ return if selector == '->' && arg_to_unparenthesized_call?(node)
60
+
61
+ lambda do |corrector|
60
62
  if block_method.source == 'lambda'
61
63
  autocorrect_old_to_new(corrector, node)
62
64
  else
@@ -102,6 +104,15 @@ module RuboCop
102
104
  def lambda_arg_string(args)
103
105
  args.children.map(&:source).join(', ')
104
106
  end
107
+
108
+ def arg_to_unparenthesized_call?(node)
109
+ parent = node.parent
110
+ return false unless parent && parent.send_type?
111
+ return false if parenthesized_call?(parent)
112
+
113
+ index = parent.children.index { |c| c.equal?(node) }
114
+ index >= 2
115
+ end
105
116
  end
106
117
  end
107
118
  end
@@ -9,7 +9,7 @@ module RuboCop
9
9
  MSG = 'Do not use parentheses for method calls with ' \
10
10
  'no arguments.'.freeze
11
11
 
12
- ASGN_NODES = [:lvasgn, :masgn] + Util::SHORTHAND_ASGN_NODES
12
+ ASGN_NODES = [:lvasgn, :masgn] + SHORTHAND_ASGN_NODES
13
13
 
14
14
  def on_send(node)
15
15
  _receiver, method_name, *args = *node
@@ -71,10 +71,6 @@ module RuboCop
71
71
  def arguments?(args)
72
72
  !args.children.empty?
73
73
  end
74
-
75
- def parentheses?(args)
76
- args.loc.begin
77
- end
78
74
  end
79
75
  end
80
76
  end
@@ -89,12 +89,18 @@ module RuboCop
89
89
  outer_expr = "(#{outer_expr})" if outer_cond.or_type? &&
90
90
  operator == '&&'.freeze
91
91
  inner_expr = inner_cond.source
92
- inner_expr = "(#{inner_expr})" if inner_cond.or_type?
92
+
93
+ inner_expr = "(#{inner_expr})" if requires_parens?(inner_cond)
93
94
  inner_expr = "!#{inner_expr}" unless outer_keyword == inner_keyword
94
95
 
95
96
  "#{outer_node.loc.keyword.source} " \
96
97
  "#{outer_expr} #{operator} #{inner_expr}"
97
98
  end
99
+
100
+ def requires_parens?(node)
101
+ node.or_type? ||
102
+ !(RuboCop::Node::COMPARISON_OPERATORS & node.children).empty?
103
+ end
98
104
  end
99
105
  end
100
106
  end
@@ -34,10 +34,6 @@ module RuboCop
34
34
 
35
35
  private
36
36
 
37
- def parenthesized_call?(send)
38
- send.loc.begin && send.loc.begin.is?('(')
39
- end
40
-
41
37
  def rspec_matcher?(parent, send)
42
38
  parent.method_args.one? && # .to, .not_to, etc
43
39
  RSPEC_MATCHERS.include?(send.method_name) &&
@@ -6,10 +6,16 @@ module RuboCop
6
6
  module Style
7
7
  # This cop checks for uses if the keyword *not* instead of !.
8
8
  class Not < Cop
9
- include AutocorrectUnlessChangingAST
10
-
11
9
  MSG = 'Use `!` instead of `not`.'.freeze
12
10
 
11
+ OPPOSITE_METHODS = {
12
+ :== => :!=,
13
+ :!= => :==,
14
+ :<= => :>,
15
+ :> => :<=,
16
+ :< => :>=,
17
+ :>= => :< }.freeze
18
+
13
19
  def on_send(node)
14
20
  return unless node.keyword_not?
15
21
 
@@ -18,9 +24,25 @@ module RuboCop
18
24
 
19
25
  private
20
26
 
21
- def correction(node)
22
- new_source = node.source.sub(/not\s*/, '!')
23
- ->(corrector) { corrector.replace(node.source_range, new_source) }
27
+ def autocorrect(node)
28
+ range = range_with_surrounding_space(node.loc.selector, :right)
29
+ child = node.children.first
30
+
31
+ if child.send_type? && OPPOSITE_METHODS.key?(child.method_name)
32
+ lambda do |corrector|
33
+ corrector.remove(range)
34
+ corrector.replace(child.loc.selector,
35
+ OPPOSITE_METHODS[child.method_name].to_s)
36
+ end
37
+ elsif child.and_type? || child.or_type? || child.binary_operation? ||
38
+ ternary_op?(child)
39
+ lambda do |corrector|
40
+ corrector.replace(range, '!(')
41
+ corrector.insert_after(node.source_range, ')')
42
+ end
43
+ else
44
+ ->(corrector) { corrector.replace(range, '!') }
45
+ end
24
46
  end
25
47
  end
26
48
  end
@@ -20,6 +20,27 @@ module RuboCop
20
20
 
21
21
  add_offense(node, :expression, format(MSG, condition))
22
22
  end
23
+
24
+ def autocorrect(node)
25
+ lambda do |corrector|
26
+ corrector.replace(node.source_range, replacement(node))
27
+ end
28
+ end
29
+
30
+ def replacement(node)
31
+ cond, body, else_clause = *node
32
+ ternary = "#{cond.source} ? #{body.source} : #{else_clause.source}"
33
+
34
+ return ternary unless node.parent
35
+ return "(#{ternary})" if [:and, :or].include?(node.parent.type)
36
+
37
+ if node.parent.send_type?
38
+ _receiver, method_name, = *node.parent
39
+ return "(#{ternary})" if operator?(method_name)
40
+ end
41
+
42
+ ternary
43
+ end
23
44
  end
24
45
  end
25
46
  end
@@ -58,7 +58,15 @@ module RuboCop
58
58
 
59
59
  def check_send(begin_node, node)
60
60
  if node.unary_operation?
61
- offense(begin_node, 'an unary operation') unless begin_node.chained?
61
+ return if begin_node.chained?
62
+
63
+ # parens are not redundant in `(!recv.method arg)`
64
+ node = node.children.first while node.unary_operation?
65
+ if node.send_type?
66
+ return unless method_call_with_redundant_parentheses?(node)
67
+ end
68
+
69
+ offense(begin_node, 'an unary operation')
62
70
  else
63
71
  return unless method_call_with_redundant_parentheses?(node)
64
72
  offense(begin_node, 'a method call')
@@ -12,14 +12,23 @@ module RuboCop
12
12
  RAISE_MSG = 'Use `raise` instead of `fail` to ' \
13
13
  'rethrow exceptions.'.freeze
14
14
 
15
+ def_node_matcher :kernel_call?, '(send (const nil :Kernel) %1 ...)'
16
+ def_node_search :custom_fail_methods,
17
+ '{(def :fail ...) (defs _ :fail ...)}'
18
+
19
+ def investigate(processed_source)
20
+ ast = processed_source.ast
21
+ @custom_fail_defined = ast && custom_fail_methods(ast).any?
22
+ end
23
+
15
24
  def on_rescue(node)
16
25
  return unless style == :semantic
17
26
 
18
27
  begin_node, *rescue_nodes, _else_node = *node
19
- check_for(:raise, begin_node)
28
+ check_scope(:raise, begin_node)
20
29
 
21
30
  rescue_nodes.each do |rescue_node|
22
- check_for(:fail, rescue_node)
31
+ check_scope(:fail, rescue_node)
23
32
  allow(:raise, rescue_node)
24
33
  end
25
34
  end
@@ -27,11 +36,12 @@ module RuboCop
27
36
  def on_send(node)
28
37
  case style
29
38
  when :semantic
30
- check_for(:raise, node) unless ignored_node?(node)
39
+ check_send(:raise, node) unless ignored_node?(node)
31
40
  when :only_raise
32
- check_for(:raise, node)
41
+ return if @custom_fail_defined
42
+ check_send(:fail, node)
33
43
  when :only_fail
34
- check_for(:fail, node)
44
+ check_send(:raise, node)
35
45
  end
36
46
  end
37
47
 
@@ -62,35 +72,27 @@ module RuboCop
62
72
  end
63
73
  end
64
74
 
65
- def check_for(method_name, node)
75
+ def check_scope(method_name, node)
66
76
  return unless node
67
77
 
68
- if style == :semantic
69
- each_command_or_kernel_call(method_name, node) do |send_node|
70
- next if ignored_node?(send_node)
78
+ each_command_or_kernel_call(method_name, node) do |send_node|
79
+ next if ignored_node?(send_node)
71
80
 
72
- add_offense(send_node, :selector, message(method_name))
73
- ignore_node(send_node)
74
- end
75
- elsif command_or_kernel_call?(method_name == :raise ? :fail : :raise,
76
- node)
77
- add_offense(node, :selector, message(method_name))
81
+ add_offense(send_node, :selector, message(method_name))
82
+ ignore_node(send_node)
78
83
  end
79
84
  end
80
85
 
81
- def command_or_kernel_call?(name, node)
82
- node.command?(name) || kernel_call?(name, node)
83
- end
84
-
85
- def kernel_call?(name, node)
86
- return false unless node.type == :send
87
- receiver, selector, _args = *node
86
+ def check_send(method_name, node)
87
+ return unless node
88
88
 
89
- return false unless name == selector
90
- return false unless receiver.const_type?
89
+ if command_or_kernel_call?(method_name, node)
90
+ add_offense(node, :selector, message(method_name))
91
+ end
92
+ end
91
93
 
92
- _, constant = *receiver
93
- constant == :Kernel
94
+ def command_or_kernel_call?(name, node)
95
+ node.command?(name) || kernel_call?(node, name)
94
96
  end
95
97
 
96
98
  def allow(method_name, node)
@@ -31,7 +31,7 @@ module RuboCop
31
31
 
32
32
  DO = 'do'.freeze
33
33
  ACCEPT_LEFT_PAREN =
34
- %w(break next not return super yield defined?).freeze
34
+ %w(break defined? next not rescue return super yield).freeze
35
35
 
36
36
  def on_and(node)
37
37
  check(node, [:operator].freeze) if node.keyword?
@@ -187,11 +187,15 @@ module RuboCop
187
187
  end
188
188
 
189
189
  def preceded_by_operator?(node, _range)
190
- ancestor = node.ancestors.first
191
- return false unless ancestor
192
- return true if ancestor.and_type? || ancestor.or_type?
193
- return false unless ancestor.send_type?
194
- operator?(ancestor.method_name)
190
+ # regular dotted method calls bind more tightly than operators
191
+ # so we need to climb up the AST past them
192
+ while (ancestor = node.parent)
193
+ return true if ancestor.and_type? || ancestor.or_type?
194
+ return false unless ancestor.send_type?
195
+ return true if operator?(ancestor.method_name)
196
+ node = ancestor
197
+ end
198
+ false
195
199
  end
196
200
 
197
201
  def autocorrect(range)
@@ -17,6 +17,7 @@ module RuboCop
17
17
  # If one part of that continued string contains interpolations,
18
18
  # then it will be parsed as a nested `dstr` node
19
19
  return unless consistent_multiline?
20
+ return if node.loc.is_a?(Parser::Source::Map::Heredoc)
20
21
 
21
22
  children = node.children
22
23
  return unless children.all? { |c| c.str_type? || c.dstr_type? }
@@ -18,6 +18,30 @@ module RuboCop
18
18
 
19
19
  add_offense(node, :expression)
20
20
  end
21
+
22
+ def autocorrect(node)
23
+ condition, = *node
24
+ body_range = range_between_condition_and_else(node, condition)
25
+ else_range = range_between_else_and_end(node)
26
+
27
+ lambda do |corrector|
28
+ corrector.replace(node.loc.keyword, 'if'.freeze)
29
+ corrector.replace(body_range, else_range.source)
30
+ corrector.replace(else_range, body_range.source)
31
+ end
32
+ end
33
+
34
+ def range_between_condition_and_else(node, condition)
35
+ Parser::Source::Range.new(node.source_range.source_buffer,
36
+ condition.source_range.end_pos,
37
+ node.loc.else.begin_pos)
38
+ end
39
+
40
+ def range_between_else_and_end(node)
41
+ Parser::Source::Range.new(node.source_range.source_buffer,
42
+ node.loc.else.end_pos,
43
+ node.loc.end.begin_pos)
44
+ end
21
45
  end
22
46
  end
23
47
  end
@@ -61,24 +61,37 @@ module RuboCop
61
61
  end
62
62
 
63
63
  def autocorrect(node)
64
- loc = node.loc
65
64
  embedded_node = node.children.first
66
- embedded_loc = embedded_node.loc
67
65
 
68
66
  if variable_interpolation?(embedded_node)
69
- replacement = "#{embedded_loc.expression.source}.to_s"
70
- ->(corrector) { corrector.replace(loc.expression, replacement) }
67
+ autocorrect_variable_interpolation(embedded_node, node)
71
68
  elsif single_variable_interpolation?(embedded_node)
72
- variable_loc = embedded_node.children.first.loc
73
- replacement = "#{variable_loc.expression.source}.to_s"
74
- ->(corrector) { corrector.replace(loc.expression, replacement) }
69
+ autocorrect_single_variable_interpolation(embedded_node, node)
75
70
  else
76
- lambda do |corrector|
77
- corrector.replace(loc.begin, '')
78
- corrector.replace(loc.end, '')
79
- corrector.replace(embedded_loc.begin, '(')
80
- corrector.replace(embedded_loc.end, ').to_s')
81
- end
71
+ autocorrect_other(embedded_node, node)
72
+ end
73
+ end
74
+
75
+ def autocorrect_variable_interpolation(embedded_node, node)
76
+ replacement = "#{embedded_node.loc.expression.source}.to_s"
77
+ ->(corrector) { corrector.replace(node.loc.expression, replacement) }
78
+ end
79
+
80
+ def autocorrect_single_variable_interpolation(embedded_node, node)
81
+ variable_loc = embedded_node.children.first.loc
82
+ replacement = "#{variable_loc.expression.source}.to_s"
83
+ ->(corrector) { corrector.replace(node.loc.expression, replacement) }
84
+ end
85
+
86
+ def autocorrect_other(embedded_node, node)
87
+ loc = node.loc
88
+ embedded_loc = embedded_node.loc
89
+
90
+ lambda do |corrector|
91
+ corrector.replace(loc.begin, '')
92
+ corrector.replace(loc.end, '')
93
+ corrector.replace(embedded_loc.begin, '(')
94
+ corrector.replace(embedded_loc.end, ').to_s')
82
95
  end
83
96
  end
84
97
  end
@@ -21,7 +21,7 @@ module RuboCop
21
21
  # "foobar".empty?
22
22
  # !hash.empty?
23
23
  class ZeroLengthPredicate < Cop
24
- ZERO_MSG = 'Use `empty?` instead of `%s == 0`.'.freeze
24
+ ZERO_MSG = 'Use `empty?` instead of `%s %s %s`.'.freeze
25
25
  NONZERO_MSG = 'Use `!empty?` instead of `%s %s %s`.'.freeze
26
26
 
27
27
  def on_send(node)
@@ -41,8 +41,10 @@ module RuboCop
41
41
  end
42
42
 
43
43
  def_node_matcher :zero_length_predicate, <<-END
44
- {(send (send _ ${:length :size}) :== (int 0))
45
- (send (int 0) :== (send _ ${:length :size}))}
44
+ {(send (send _ ${:length :size}) $:== (int $0))
45
+ (send (int $0) $:== (send _ ${:length :size}))
46
+ (send (send _ ${:length :size}) $:< (int $1))
47
+ (send (int $1) $:> (send _ ${:length :size}))}
46
48
  END
47
49
 
48
50
  def_node_matcher :nonzero_length_predicate, <<-END