rubocop 0.34.2 → 0.35.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +86 -0
- data/README.md +103 -31
- data/config/default.yml +32 -2
- data/config/disabled.yml +24 -0
- data/config/enabled.yml +20 -2
- data/lib/rubocop.rb +13 -0
- data/lib/rubocop/ast_node.rb +48 -0
- data/lib/rubocop/cli.rb +9 -0
- data/lib/rubocop/config.rb +8 -6
- data/lib/rubocop/config_loader.rb +30 -8
- data/lib/rubocop/cop/commissioner.rb +1 -1
- data/lib/rubocop/cop/cop.rb +19 -6
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +33 -2
- data/lib/rubocop/cop/lint/debugger.rb +9 -56
- data/lib/rubocop/cop/lint/end_alignment.rb +29 -9
- data/lib/rubocop/cop/lint/eval.rb +6 -2
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +24 -6
- data/lib/rubocop/cop/lint/literal_in_condition.rb +0 -5
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +10 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/space_before_first_arg.rb +1 -1
- data/lib/rubocop/cop/lint/unused_block_argument.rb +6 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -0
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/mixin/access_modifier_node.rb +1 -1
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +26 -3
- data/lib/rubocop/cop/mixin/check_assignment.rb +2 -3
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +59 -12
- data/lib/rubocop/cop/mixin/configurable_max.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +41 -0
- data/lib/rubocop/cop/mixin/negative_conditional.rb +1 -1
- data/lib/rubocop/cop/mixin/safe_assignment.rb +3 -14
- data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
- data/lib/rubocop/cop/performance/detect.rb +5 -1
- data/lib/rubocop/cop/performance/fixed_size.rb +50 -0
- data/lib/rubocop/cop/performance/size.rb +1 -1
- data/lib/rubocop/cop/performance/string_replacement.rb +14 -8
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +97 -0
- data/lib/rubocop/cop/style/align_hash.rb +1 -12
- data/lib/rubocop/cop/style/align_parameters.rb +19 -7
- data/lib/rubocop/cop/style/and_or.rb +42 -13
- data/lib/rubocop/cop/style/block_comments.rb +4 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +57 -18
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
- data/lib/rubocop/cop/style/command_literal.rb +2 -10
- data/lib/rubocop/cop/style/copyright.rb +5 -3
- data/lib/rubocop/cop/style/documentation.rb +9 -6
- data/lib/rubocop/cop/style/dot_position.rb +6 -0
- data/lib/rubocop/cop/style/double_negation.rb +4 -15
- data/lib/rubocop/cop/style/each_with_object.rb +17 -4
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -5
- data/lib/rubocop/cop/style/encoding.rb +10 -4
- data/lib/rubocop/cop/style/extra_spacing.rb +23 -13
- data/lib/rubocop/cop/style/first_array_element_line_break.rb +41 -0
- data/lib/rubocop/cop/style/first_hash_element_line_break.rb +35 -0
- data/lib/rubocop/cop/style/first_method_argument_line_break.rb +37 -0
- data/lib/rubocop/cop/style/first_method_parameter_line_break.rb +42 -0
- data/lib/rubocop/cop/style/for.rb +2 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +31 -0
- data/lib/rubocop/cop/style/indent_hash.rb +67 -37
- data/lib/rubocop/cop/style/indentation_width.rb +1 -1
- data/lib/rubocop/cop/style/leading_comment_space.rb +3 -2
- data/lib/rubocop/cop/style/method_call_parentheses.rb +8 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -7
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +8 -13
- data/lib/rubocop/cop/style/nested_modifier.rb +97 -0
- data/lib/rubocop/cop/style/next.rb +18 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +57 -15
- data/lib/rubocop/cop/style/predicate_name.rb +7 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +2 -10
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -5
- data/lib/rubocop/cop/style/single_space_before_first_arg.rb +1 -1
- data/lib/rubocop/cop/style/space_around_operators.rb +2 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +108 -0
- data/lib/rubocop/cop/style/trailing_comma.rb +9 -6
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -2
- data/lib/rubocop/cop/style/unneeded_percent_q.rb +31 -20
- data/lib/rubocop/cop/style/variable_name.rb +5 -0
- data/lib/rubocop/cop/style/word_array.rb +2 -1
- data/lib/rubocop/cop/team.rb +17 -4
- data/lib/rubocop/cop/util.rb +5 -0
- data/lib/rubocop/cop/variable_force/locatable.rb +1 -1
- data/lib/rubocop/formatter/base_formatter.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +22 -10
- data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
- data/lib/rubocop/node_pattern.rb +390 -0
- data/lib/rubocop/options.rb +48 -36
- data/lib/rubocop/processed_source.rb +3 -1
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +60 -0
- data/lib/rubocop/result_cache.rb +4 -2
- data/lib/rubocop/runner.rb +33 -10
- data/lib/rubocop/token.rb +2 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/warning.rb +11 -0
- data/relnotes/v0.35.0.md +210 -0
- data/rubocop.gemspec +2 -2
- metadata +20 -6
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# appropriate value with --auto-gen-config.
|
7
7
|
module ConfigurableMax
|
8
8
|
def max=(value)
|
9
|
-
cfg =
|
9
|
+
cfg = config_to_allow_offenses
|
10
10
|
value = [cfg[parameter_name], value].max if cfg[parameter_name]
|
11
11
|
cfg[parameter_name] = value
|
12
12
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for checking for a line break before the first
|
6
|
+
# element in a multi-line collection.
|
7
|
+
module FirstElementLineBreak
|
8
|
+
def autocorrect(node)
|
9
|
+
->(corrector) { corrector.insert_before(node.loc.expression, "\n") }
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def check_method_line_break(node, children)
|
15
|
+
return if children.empty?
|
16
|
+
|
17
|
+
return unless method_uses_parens?(node, children.first)
|
18
|
+
|
19
|
+
check_children_line_break(node, children)
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_uses_parens?(node, limit)
|
23
|
+
source = node.loc.expression.source_line[0...limit.loc.column]
|
24
|
+
source =~ /\s*\(\s*$/
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_children_line_break(node, children, start = node)
|
28
|
+
return if children.size < 2
|
29
|
+
|
30
|
+
line = start.loc.line
|
31
|
+
min = children.min_by { |n| n.loc.first_line }
|
32
|
+
return if line != min.loc.first_line
|
33
|
+
|
34
|
+
max = children.max_by { |n| n.loc.last_line }
|
35
|
+
return if line == max.loc.last_line
|
36
|
+
|
37
|
+
add_offense(min, :expression, self.class::MSG)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
def check_negative_conditional(node)
|
9
9
|
condition, _body, _rest = *node
|
10
10
|
|
11
|
-
# Look at last expression of contents if there
|
11
|
+
# Look at last expression of contents if there are parentheses
|
12
12
|
# around condition.
|
13
13
|
condition = condition.children.last while condition.type == :begin
|
14
14
|
return unless condition.type == :send
|
@@ -6,21 +6,10 @@ module RuboCop
|
|
6
6
|
# putting parentheses around an assignment to indicate "I know I'm using an
|
7
7
|
# assignment as a condition. It's not a mistake."
|
8
8
|
module SafeAssignment
|
9
|
-
|
10
|
-
return false unless node.type == :begin
|
11
|
-
return false unless node.children.size == 1
|
9
|
+
extend NodePattern::Macros
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
when :send
|
16
|
-
_receiver, method_name, _args = *child
|
17
|
-
method_name.to_s.end_with?('=')
|
18
|
-
when *Util::EQUALS_ASGN_NODES
|
19
|
-
true
|
20
|
-
else
|
21
|
-
false
|
22
|
-
end
|
23
|
-
end
|
11
|
+
def_node_matcher :safe_assignment?,
|
12
|
+
'(begin {equals_asgn? asgn_method_call?})'
|
24
13
|
|
25
14
|
def safe_assignment_allowed?
|
26
15
|
cop_config['AllowSafeAssignment']
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def max_line_length
|
33
|
-
cop_config
|
33
|
+
cop_config['MaxLineLength'] ||
|
34
34
|
config.for_cop('Metrics/LineLength')['Max']
|
35
35
|
end
|
36
36
|
|
@@ -55,7 +55,7 @@ module RuboCop
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def comment_lines
|
58
|
-
@comment_lines ||= processed_source.comments.map
|
58
|
+
@comment_lines ||= processed_source.comments.map { |c| c.location.line }
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -57,7 +57,11 @@ module RuboCop
|
|
57
57
|
else
|
58
58
|
preferred_method
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
|
+
first_range = Parser::Source::Range.new(
|
62
|
+
receiver.loc.expression.source,
|
63
|
+
receiver.loc.end.end_pos,
|
64
|
+
receiver.loc.end.end_pos).join(node.loc.selector)
|
61
65
|
|
62
66
|
receiver, _args, _body = *receiver if receiver.block_type?
|
63
67
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# Do not compute the size of statically sized objects.
|
7
|
+
class FixedSize < Cop
|
8
|
+
MSG = 'Do not compute the size of statically sized objects.'.freeze
|
9
|
+
COUNTERS = [:count, :length, :size].freeze
|
10
|
+
STATIC_SIZED_TYPES = [:array, :hash, :str, :sym].freeze
|
11
|
+
|
12
|
+
def on_send(node)
|
13
|
+
variable, method, arg = *node
|
14
|
+
return unless variable
|
15
|
+
return unless COUNTERS.include?(method)
|
16
|
+
return unless STATIC_SIZED_TYPES.include?(variable.type)
|
17
|
+
return if contains_splat?(variable)
|
18
|
+
return if contains_double_splat?(variable)
|
19
|
+
return if string_argument?(arg)
|
20
|
+
if node.parent
|
21
|
+
return if node.parent.casgn_type? || node.parent.block_type?
|
22
|
+
end
|
23
|
+
add_offense(node, :expression)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def contains_splat?(node)
|
29
|
+
return unless node.array_type?
|
30
|
+
|
31
|
+
node.children.any? do |child|
|
32
|
+
child.respond_to?(:splat_type?) && child.splat_type?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def contains_double_splat?(node)
|
37
|
+
return unless node.hash_type?
|
38
|
+
|
39
|
+
node.children.any? do |child|
|
40
|
+
child.respond_to?(:kwsplat_type?) && child.kwsplat_type?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def string_argument?(node)
|
45
|
+
node && !node.str_type?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
return unless method == :count
|
34
34
|
return unless array?(receiver) || hash?(receiver)
|
35
35
|
return if node.parent && node.parent.block_type?
|
36
|
-
return if args
|
36
|
+
return if args
|
37
37
|
|
38
38
|
add_offense(node, node.loc.selector)
|
39
39
|
end
|
@@ -20,7 +20,7 @@ module RuboCop
|
|
20
20
|
# 'a b c'.delete(' ')
|
21
21
|
class StringReplacement < Cop
|
22
22
|
MSG = 'Use `%s` instead of `%s`.'
|
23
|
-
DETERMINISTIC_REGEX = /^[\w\s
|
23
|
+
DETERMINISTIC_REGEX = /^[\w\s\-,"']+$/.freeze
|
24
24
|
REGEXP_CONSTRUCTOR_METHODS = [:new, :compile].freeze
|
25
25
|
GSUB_METHODS = [:gsub, :gsub!].freeze
|
26
26
|
DETERMINISTIC_TYPES = [:regexp, :str, :send].freeze
|
@@ -32,16 +32,17 @@ module RuboCop
|
|
32
32
|
def on_send(node)
|
33
33
|
_string, method, first_param, second_param = *node
|
34
34
|
return unless GSUB_METHODS.include?(method)
|
35
|
-
return unless second_param
|
35
|
+
return unless string?(second_param)
|
36
36
|
return unless DETERMINISTIC_TYPES.include?(first_param.type)
|
37
37
|
|
38
|
-
first_source = first_source(first_param)
|
38
|
+
first_source, options = first_source(first_param)
|
39
39
|
second_source, = *second_param
|
40
40
|
|
41
41
|
return if first_source.nil?
|
42
42
|
|
43
43
|
if regex?(first_param)
|
44
44
|
return unless first_source =~ DETERMINISTIC_REGEX
|
45
|
+
return if options
|
45
46
|
end
|
46
47
|
|
47
48
|
return if first_source.length != 1
|
@@ -53,7 +54,7 @@ module RuboCop
|
|
53
54
|
|
54
55
|
def autocorrect(node)
|
55
56
|
_string, method, first_param, second_param = *node
|
56
|
-
first_source = first_source(first_param)
|
57
|
+
first_source, = first_source(first_param)
|
57
58
|
second_source, = *second_param
|
58
59
|
replacement_method = replacement_method(method,
|
59
60
|
first_source,
|
@@ -74,17 +75,21 @@ module RuboCop
|
|
74
75
|
|
75
76
|
private
|
76
77
|
|
78
|
+
def string?(node)
|
79
|
+
node && node.str_type?
|
80
|
+
end
|
81
|
+
|
77
82
|
def first_source(first_param)
|
78
83
|
case first_param.type
|
79
84
|
when :regexp, :send
|
80
85
|
return nil unless regex?(first_param)
|
81
86
|
|
82
|
-
source, = extract_source(first_param)
|
87
|
+
source, options = extract_source(first_param)
|
83
88
|
when :str
|
84
89
|
source, = *first_param
|
85
90
|
end
|
86
91
|
|
87
|
-
source
|
92
|
+
[source, options]
|
88
93
|
end
|
89
94
|
|
90
95
|
def extract_source(node)
|
@@ -97,9 +102,10 @@ module RuboCop
|
|
97
102
|
end
|
98
103
|
|
99
104
|
def source_from_regex_literal(node)
|
100
|
-
regex, = *node
|
105
|
+
regex, options = *node
|
101
106
|
source, = *regex
|
102
|
-
|
107
|
+
options, = *options
|
108
|
+
[source, options]
|
103
109
|
end
|
104
110
|
|
105
111
|
def source_from_regex_constructor(node)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks for correct grammar when using ActiveSupport's
|
7
|
+
# core extensions to the numeric classes.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# 3.day.ago
|
12
|
+
# 1.months.ago
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# 3.days.ago
|
16
|
+
# 1.month.ago
|
17
|
+
class PluralizationGrammar < Cop
|
18
|
+
SINGULAR_DURATION_METHODS = { second: :seconds,
|
19
|
+
minute: :minutes,
|
20
|
+
hour: :hours,
|
21
|
+
day: :days,
|
22
|
+
week: :weeks,
|
23
|
+
fortnight: :fortnights,
|
24
|
+
month: :months,
|
25
|
+
year: :years }
|
26
|
+
|
27
|
+
PLURAL_DURATION_METHODS = SINGULAR_DURATION_METHODS.invert
|
28
|
+
|
29
|
+
MSG = 'Prefer `%s.%s`.'
|
30
|
+
|
31
|
+
def on_send(node)
|
32
|
+
receiver, method_name, *_args = *node
|
33
|
+
return if receiver.nil?
|
34
|
+
return unless duration_method?(method_name)
|
35
|
+
return unless literal_number?(receiver)
|
36
|
+
number, = *receiver
|
37
|
+
if singular_receiver?(number) && plural_method?(method_name)
|
38
|
+
add_offense(node,
|
39
|
+
:expression,
|
40
|
+
format(MSG, number, singularize(method_name)))
|
41
|
+
elsif plural_receiver?(number) && singular_method?(method_name)
|
42
|
+
add_offense(node,
|
43
|
+
:expression,
|
44
|
+
format(MSG, number, pluralize(method_name)))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def autocorrect(node)
|
51
|
+
lambda do |corrector|
|
52
|
+
method_name = node.loc.selector.source
|
53
|
+
replacement = if plural_method?(method_name)
|
54
|
+
singularize(method_name)
|
55
|
+
else
|
56
|
+
pluralize(method_name)
|
57
|
+
end
|
58
|
+
corrector.replace(node.loc.selector, replacement)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def plural_method?(method_name)
|
63
|
+
method_name.to_s.end_with?('s')
|
64
|
+
end
|
65
|
+
|
66
|
+
def singular_method?(method_name)
|
67
|
+
!plural_method?(method_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def singular_receiver?(number)
|
71
|
+
number == 1
|
72
|
+
end
|
73
|
+
|
74
|
+
def plural_receiver?(number)
|
75
|
+
!singular_receiver?(number)
|
76
|
+
end
|
77
|
+
|
78
|
+
def literal_number?(node)
|
79
|
+
node.int_type? || node.float_type?
|
80
|
+
end
|
81
|
+
|
82
|
+
def pluralize(method_name)
|
83
|
+
SINGULAR_DURATION_METHODS.fetch(method_name.to_sym).to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
def singularize(method_name)
|
87
|
+
PLURAL_DURATION_METHODS.fetch(method_name.to_sym).to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
def duration_method?(method_name)
|
91
|
+
SINGULAR_DURATION_METHODS.key?(method_name) ||
|
92
|
+
PLURAL_DURATION_METHODS.key?(method_name)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -156,7 +156,7 @@ module RuboCop
|
|
156
156
|
def on_hash(node)
|
157
157
|
return if ignored_node?(node)
|
158
158
|
return if node.children.empty?
|
159
|
-
return unless multiline?
|
159
|
+
return unless node.multiline?
|
160
160
|
|
161
161
|
@alignment_for_hash_rockets ||=
|
162
162
|
new_alignment('EnforcedHashRocketStyle')
|
@@ -201,17 +201,6 @@ module RuboCop
|
|
201
201
|
node.loc.begin
|
202
202
|
end
|
203
203
|
|
204
|
-
# Returns true if the hash spans multiple lines
|
205
|
-
def multiline?(node)
|
206
|
-
return false unless node.loc.expression.source.include?("\n")
|
207
|
-
|
208
|
-
return false if node.children[1..-1].all? do |child|
|
209
|
-
!begins_its_line?(child.loc.expression)
|
210
|
-
end
|
211
|
-
|
212
|
-
true
|
213
|
-
end
|
214
|
-
|
215
204
|
def alignment_for(pair)
|
216
205
|
if pair.loc.operator.is?('=>')
|
217
206
|
@alignment_for_hash_rockets
|
@@ -3,23 +3,33 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Here we check if the parameters on a multi-line method call
|
7
|
-
# aligned.
|
6
|
+
# Here we check if the parameters on a multi-line method call or
|
7
|
+
# definition are aligned.
|
8
8
|
class AlignParameters < Cop
|
9
9
|
include AutocorrectAlignment
|
10
|
-
|
11
|
-
MSG = 'Align the parameters of a method call if they span ' \
|
12
|
-
'more than one line.'
|
10
|
+
include OnMethodDef
|
13
11
|
|
14
12
|
def on_send(node)
|
15
13
|
_receiver, method, *args = *node
|
16
14
|
|
17
15
|
return if method == :[]=
|
18
|
-
return if args.size
|
16
|
+
return if args.size < 2
|
17
|
+
|
18
|
+
check_alignment(args, base_column(node, args))
|
19
|
+
end
|
19
20
|
|
21
|
+
def on_method_def(node, _method_name, args, _body)
|
22
|
+
args = args.children
|
23
|
+
return if args.size < 2
|
20
24
|
check_alignment(args, base_column(node, args))
|
21
25
|
end
|
22
26
|
|
27
|
+
def message(node)
|
28
|
+
type = node.parent.send_type? ? 'call' : 'definition'
|
29
|
+
"Align the parameters of a method #{type} if they span " \
|
30
|
+
'more than one line.'
|
31
|
+
end
|
32
|
+
|
23
33
|
private
|
24
34
|
|
25
35
|
def fixed_indentation?
|
@@ -38,7 +48,9 @@ module RuboCop
|
|
38
48
|
end
|
39
49
|
|
40
50
|
def target_method_lineno(node)
|
41
|
-
if node.
|
51
|
+
if node.def_type? || node.defs_type?
|
52
|
+
node.loc.keyword.line
|
53
|
+
elsif node.loc.selector
|
42
54
|
node.loc.selector.line
|
43
55
|
else
|
44
56
|
# l.(1) has no selector, so we use the opening parenthesis instead
|
@@ -63,25 +63,54 @@ module RuboCop
|
|
63
63
|
replacement = (node.type == :and ? '&&' : '||')
|
64
64
|
lambda do |corrector|
|
65
65
|
[expr1, expr2].each do |expr|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
corrector.replace(range, '(')
|
74
|
-
corrector.insert_after(args.last.loc.expression, ')')
|
66
|
+
if expr.send_type?
|
67
|
+
correct_send(expr, corrector)
|
68
|
+
elsif expr.return_type?
|
69
|
+
correct_other(expr, corrector)
|
70
|
+
elsif expr.assignment?
|
71
|
+
correct_other(expr, corrector)
|
72
|
+
end
|
75
73
|
end
|
76
74
|
corrector.replace(node.loc.operator, replacement)
|
77
75
|
end
|
78
76
|
end
|
79
77
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
78
|
+
def correct_send(node, corrector)
|
79
|
+
receiver, method_name, *args = *node
|
80
|
+
if method_name == :!
|
81
|
+
# ! is a special case:
|
82
|
+
# 'x and !obj.method arg' can be auto-corrected if we
|
83
|
+
# recurse down a level and add parens to 'obj.method arg'
|
84
|
+
# however, 'not x' also parses as (send x :!)
|
85
|
+
|
86
|
+
if node.loc.selector.source == '!'
|
87
|
+
node = receiver
|
88
|
+
_receiver, _method_name, *args = *node
|
89
|
+
elsif node.loc.selector.source == 'not'
|
90
|
+
return correct_other(node, corrector)
|
91
|
+
else
|
92
|
+
fail 'unrecognized unary negation operator'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
return unless correctable_send?(node)
|
96
|
+
|
97
|
+
sb = node.loc.expression.source_buffer
|
98
|
+
begin_paren = node.loc.selector.end_pos
|
99
|
+
range = Parser::Source::Range.new(sb, begin_paren, begin_paren + 1)
|
100
|
+
corrector.replace(range, '(')
|
101
|
+
corrector.insert_after(args.last.loc.expression, ')')
|
102
|
+
end
|
103
|
+
|
104
|
+
def correct_other(node, corrector)
|
105
|
+
return unless node.loc.expression.begin.source != '('
|
106
|
+
corrector.insert_before(node.loc.expression, '(')
|
107
|
+
corrector.insert_after(node.loc.expression, ')')
|
108
|
+
end
|
109
|
+
|
110
|
+
def correctable_send?(node)
|
111
|
+
_receiver, method_name, *args = *node
|
83
112
|
# don't clobber if we already have a starting paren
|
84
|
-
return false unless !
|
113
|
+
return false unless !node.loc.begin || node.loc.begin.source != '('
|
85
114
|
# don't touch anything unless we are sure it is a method call.
|
86
115
|
return false unless args.last && method_name.to_s =~ /[a-z]/
|
87
116
|
|