rubocop 0.42.0 → 0.43.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/README.md +1 -1
- data/assets/output.html.erb +21 -10
- data/config/default.yml +32 -2
- data/config/disabled.yml +8 -1
- data/config/enabled.yml +40 -12
- data/lib/rubocop.rb +14 -2
- data/lib/rubocop/ast_node.rb +2 -0
- data/lib/rubocop/cached_data.rb +13 -11
- data/lib/rubocop/cli.rb +5 -5
- data/lib/rubocop/config.rb +68 -24
- data/lib/rubocop/config_loader.rb +13 -11
- data/lib/rubocop/config_loader_resolver.rb +4 -2
- data/lib/rubocop/cop/cop.rb +16 -5
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +21 -20
- data/lib/rubocop/cop/lint/block_alignment.rb +3 -4
- data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -3
- data/lib/rubocop/cop/lint/duplicate_methods.rb +16 -6
- data/lib/rubocop/cop/lint/else_layout.rb +1 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/end_alignment.rb +4 -6
- data/lib/rubocop/cop/lint/eval.rb +1 -1
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +8 -8
- data/lib/rubocop/cop/lint/inherit_exception.rb +22 -7
- data/lib/rubocop/cop/lint/literal_in_condition.rb +5 -5
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +3 -5
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +9 -8
- data/lib/rubocop/cop/lint/percent_string_array.rb +17 -6
- data/lib/rubocop/cop/lint/percent_symbol_array.rb +4 -4
- data/lib/rubocop/cop/lint/rand_one.rb +3 -3
- data/lib/rubocop/cop/lint/require_parentheses.rb +1 -3
- data/lib/rubocop/cop/lint/shadowed_exception.rb +39 -44
- data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +2 -2
- data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +1 -2
- data/lib/rubocop/cop/lint/unified_integer.rb +38 -0
- data/lib/rubocop/cop/lint/unneeded_disable.rb +51 -38
- data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +114 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +25 -12
- data/lib/rubocop/cop/lint/useless_setter_call.rb +27 -28
- data/lib/rubocop/cop/lint/void.rb +2 -4
- data/lib/rubocop/cop/mixin/access_modifier_node.rb +5 -5
- data/lib/rubocop/cop/mixin/array_hash_indentation.rb +19 -17
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +3 -5
- data/lib/rubocop/cop/mixin/configurable_naming.rb +4 -5
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +52 -0
- data/lib/rubocop/cop/mixin/def_node.rb +28 -0
- data/lib/rubocop/cop/mixin/documentation_comment.rb +41 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +18 -13
- data/lib/rubocop/cop/mixin/if_node.rb +6 -0
- data/lib/rubocop/cop/mixin/match_range.rb +2 -5
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +40 -28
- data/lib/rubocop/cop/mixin/negative_conditional.rb +6 -6
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -5
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +14 -4
- data/lib/rubocop/cop/mixin/safe_mode.rb +23 -0
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +2 -4
- data/lib/rubocop/cop/mixin/space_inside.rb +1 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +30 -20
- data/lib/rubocop/cop/mixin/trailing_comma.rb +19 -17
- data/lib/rubocop/cop/performance/case_when_splat.rb +16 -41
- data/lib/rubocop/cop/performance/casecmp.rb +28 -16
- data/lib/rubocop/cop/performance/count.rb +58 -34
- data/lib/rubocop/cop/performance/detect.rb +3 -7
- data/lib/rubocop/cop/performance/double_start_end_with.rb +17 -13
- data/lib/rubocop/cop/performance/fixed_size.rb +19 -14
- data/lib/rubocop/cop/performance/flat_map.rb +16 -9
- data/lib/rubocop/cop/performance/hash_each.rb +2 -3
- data/lib/rubocop/cop/performance/lstrip_rstrip.rb +4 -6
- data/lib/rubocop/cop/performance/redundant_match.rb +4 -1
- data/lib/rubocop/cop/performance/redundant_merge.rb +63 -32
- data/lib/rubocop/cop/performance/redundant_sort_by.rb +8 -7
- data/lib/rubocop/cop/performance/reverse_each.rb +1 -4
- data/lib/rubocop/cop/performance/size.rb +21 -8
- data/lib/rubocop/cop/performance/sort_with_block.rb +54 -0
- data/lib/rubocop/cop/performance/string_replacement.rb +3 -7
- data/lib/rubocop/cop/rails/delegate.rb +2 -3
- data/lib/rubocop/cop/rails/find_by.rb +4 -8
- data/lib/rubocop/cop/rails/not_null_column.rb +45 -0
- data/lib/rubocop/cop/rails/request_referer.rb +3 -3
- data/lib/rubocop/cop/rails/safe_navigation.rb +89 -0
- data/lib/rubocop/cop/rails/save_bang.rb +78 -9
- data/lib/rubocop/cop/rails/scope_args.rb +3 -1
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +2 -3
- data/lib/rubocop/cop/rails/validation.rb +1 -1
- data/lib/rubocop/cop/security/json_load.rb +36 -0
- data/lib/rubocop/cop/style/alias.rb +1 -1
- data/lib/rubocop/cop/style/align_hash.rb +25 -14
- data/lib/rubocop/cop/style/and_or.rb +13 -3
- data/lib/rubocop/cop/style/array_join.rb +3 -3
- data/lib/rubocop/cop/style/ascii_comments.rb +1 -2
- data/lib/rubocop/cop/style/ascii_identifiers.rb +1 -2
- data/lib/rubocop/cop/style/attr.rb +1 -3
- data/lib/rubocop/cop/style/block_comments.rb +2 -6
- data/lib/rubocop/cop/style/block_delimiters.rb +35 -21
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +4 -4
- data/lib/rubocop/cop/style/case_indentation.rb +1 -3
- data/lib/rubocop/cop/style/class_methods.rb +3 -4
- data/lib/rubocop/cop/style/collection_methods.rb +1 -1
- data/lib/rubocop/cop/style/command_literal.rb +15 -8
- data/lib/rubocop/cop/style/comment_annotation.rb +1 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +68 -36
- data/lib/rubocop/cop/style/copyright.rb +1 -5
- data/lib/rubocop/cop/style/def_with_parentheses.rb +3 -5
- data/lib/rubocop/cop/style/documentation.rb +28 -56
- data/lib/rubocop/cop/style/documentation_method.rb +80 -0
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +6 -5
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/else_alignment.rb +10 -9
- data/lib/rubocop/cop/style/empty_case_condition.rb +2 -4
- data/lib/rubocop/cop/style/empty_else.rb +1 -4
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -3
- data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +2 -5
- data/lib/rubocop/cop/style/encoding.rb +28 -14
- data/lib/rubocop/cop/style/even_odd.rb +28 -17
- data/lib/rubocop/cop/style/extra_spacing.rb +36 -25
- data/lib/rubocop/cop/style/file_name.rb +19 -10
- data/lib/rubocop/cop/style/first_parameter_indentation.rb +2 -3
- data/lib/rubocop/cop/style/for.rb +12 -8
- data/lib/rubocop/cop/style/format_string.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +22 -56
- data/lib/rubocop/cop/style/hash_syntax.rb +72 -7
- data/lib/rubocop/cop/style/if_unless_modifier.rb +23 -19
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +3 -3
- data/lib/rubocop/cop/style/indentation_width.rb +30 -16
- data/lib/rubocop/cop/style/infinite_loop.rb +16 -13
- data/lib/rubocop/cop/style/initial_indentation.rb +23 -18
- data/lib/rubocop/cop/style/inline_comment.rb +16 -3
- data/lib/rubocop/cop/style/lambda.rb +22 -10
- data/lib/rubocop/cop/style/leading_comment_space.rb +12 -1
- data/lib/rubocop/cop/style/line_end_concatenation.rb +24 -6
- data/lib/rubocop/cop/style/method_call_parentheses.rb +18 -9
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
- data/lib/rubocop/cop/style/method_def_parentheses.rb +3 -4
- data/lib/rubocop/cop/style/method_missing.rb +10 -2
- data/lib/rubocop/cop/style/module_function.rb +14 -6
- data/lib/rubocop/cop/style/multiline_assignment_layout.rb +2 -5
- data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -5
- data/lib/rubocop/cop/style/multiline_block_layout.rb +22 -15
- data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +9 -0
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +41 -20
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +6 -6
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +3 -5
- data/lib/rubocop/cop/style/mutable_constant.rb +21 -13
- data/lib/rubocop/cop/style/negated_if.rb +1 -1
- data/lib/rubocop/cop/style/negated_while.rb +3 -3
- data/lib/rubocop/cop/style/nested_modifier.rb +2 -4
- data/lib/rubocop/cop/style/next.rb +4 -4
- data/lib/rubocop/cop/style/non_nil_check.rb +18 -10
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +8 -0
- data/lib/rubocop/cop/style/numeric_predicate.rb +9 -9
- data/lib/rubocop/cop/style/one_line_conditional.rb +11 -1
- data/lib/rubocop/cop/style/op_method.rb +1 -1
- data/lib/rubocop/cop/style/option_hash.rb +8 -8
- data/lib/rubocop/cop/style/optional_arguments.rb +21 -8
- data/lib/rubocop/cop/style/parallel_assignment.rb +51 -35
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +2 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +26 -15
- data/lib/rubocop/cop/style/redundant_return.rb +5 -5
- data/lib/rubocop/cop/style/redundant_self.rb +20 -11
- data/lib/rubocop/cop/style/regexp_literal.rb +16 -10
- data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +8 -6
- data/lib/rubocop/cop/style/safe_navigation.rb +125 -0
- data/lib/rubocop/cop/style/self_assignment.rb +2 -2
- data/lib/rubocop/cop/style/semicolon.rb +9 -10
- data/lib/rubocop/cop/style/signal_exception.rb +2 -4
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +18 -11
- data/lib/rubocop/cop/style/space_after_method_name.rb +2 -3
- data/lib/rubocop/cop/style/space_after_not.rb +4 -6
- data/lib/rubocop/cop/style/space_around_block_parameters.rb +1 -2
- data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +1 -3
- data/lib/rubocop/cop/style/space_around_operators.rb +21 -16
- data/lib/rubocop/cop/style/space_before_block_braces.rb +2 -12
- data/lib/rubocop/cop/style/space_before_first_arg.rb +1 -3
- data/lib/rubocop/cop/style/space_inside_array_percent_literal.rb +1 -1
- data/lib/rubocop/cop/style/space_inside_block_braces.rb +33 -40
- data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +38 -23
- data/lib/rubocop/cop/style/space_inside_percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +26 -12
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/symbol_array.rb +10 -10
- data/lib/rubocop/cop/style/symbol_proc.rb +28 -13
- data/lib/rubocop/cop/style/ternary_parentheses.rb +35 -5
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +2 -4
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +29 -17
- data/lib/rubocop/cop/style/trivial_accessors.rb +6 -6
- data/lib/rubocop/cop/style/unless_else.rb +2 -6
- data/lib/rubocop/cop/style/unneeded_capital_w.rb +8 -4
- data/lib/rubocop/cop/style/unneeded_interpolation.rb +4 -5
- data/lib/rubocop/cop/style/unneeded_percent_q.rb +13 -7
- data/lib/rubocop/cop/style/variable_number.rb +79 -0
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +25 -15
- data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -0
- data/lib/rubocop/cop/util.rb +23 -4
- data/lib/rubocop/cop/variable_force.rb +59 -25
- data/lib/rubocop/cop/variable_force/locatable.rb +8 -6
- data/lib/rubocop/cop/variable_force/variable.rb +2 -2
- data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
- data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -11
- data/lib/rubocop/formatter/formatter_set.rb +12 -10
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +4 -4
- data/lib/rubocop/node_pattern.rb +79 -35
- data/lib/rubocop/options.rb +4 -4
- data/lib/rubocop/processed_source.rb +9 -5
- data/lib/rubocop/remote_config.rb +14 -10
- data/lib/rubocop/result_cache.rb +14 -6
- data/lib/rubocop/runner.rb +55 -34
- data/lib/rubocop/string_util.rb +9 -5
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/token.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +15 -4
- data/lib/rubocop/cop/lint/useless_array_splat.rb +0 -56
- data/lib/rubocop/cop/performance/push_splat.rb +0 -47
@@ -72,15 +72,15 @@ module RuboCop
|
|
72
72
|
def on_method_def(_node, _method_name, _args, body)
|
73
73
|
return unless body
|
74
74
|
|
75
|
-
if body.
|
75
|
+
if body.return_type?
|
76
76
|
check_return_node(body)
|
77
|
-
elsif body.
|
77
|
+
elsif body.begin_type?
|
78
78
|
expressions = *body
|
79
79
|
last_expr = expressions.last
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
return unless last_expr && last_expr.return_type?
|
82
|
+
|
83
|
+
check_return_node(last_expr)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
49
49
|
def initialize(config = nil, options = nil)
|
50
50
|
super
|
51
51
|
@allowed_send_nodes = []
|
52
|
-
@
|
52
|
+
@local_variables_scopes = Hash.new { |hash, key| hash[key] = [] }
|
53
53
|
end
|
54
54
|
|
55
55
|
# Assignment of self.x
|
@@ -68,12 +68,12 @@ module RuboCop
|
|
68
68
|
|
69
69
|
# Using self.x to distinguish from local variable x
|
70
70
|
|
71
|
-
def on_def(
|
72
|
-
|
71
|
+
def on_def(node)
|
72
|
+
add_scope(node)
|
73
73
|
end
|
74
74
|
|
75
|
-
def on_defs(
|
76
|
-
|
75
|
+
def on_defs(node)
|
76
|
+
add_scope(node)
|
77
77
|
end
|
78
78
|
|
79
79
|
def on_args(node)
|
@@ -86,7 +86,7 @@ module RuboCop
|
|
86
86
|
|
87
87
|
def on_lvasgn(node)
|
88
88
|
lhs, _rhs = *node
|
89
|
-
@
|
89
|
+
@local_variables_scopes[node] << lhs
|
90
90
|
end
|
91
91
|
|
92
92
|
# Detect offenses
|
@@ -97,8 +97,7 @@ module RuboCop
|
|
97
97
|
return unless regular_method_call?(node)
|
98
98
|
|
99
99
|
return if @allowed_send_nodes.include?(node) ||
|
100
|
-
@
|
101
|
-
|
100
|
+
@local_variables_scopes[node].include?(method_name)
|
102
101
|
add_offense(node, :expression)
|
103
102
|
end
|
104
103
|
|
@@ -112,6 +111,13 @@ module RuboCop
|
|
112
111
|
|
113
112
|
private
|
114
113
|
|
114
|
+
def add_scope(node)
|
115
|
+
local_variables = []
|
116
|
+
node.descendants.each do |child_node|
|
117
|
+
@local_variables_scopes[child_node] = local_variables
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
115
121
|
def regular_method_call?(node)
|
116
122
|
_receiver, method_name, *_args = *node
|
117
123
|
|
@@ -123,7 +129,7 @@ module RuboCop
|
|
123
129
|
|
124
130
|
def on_argument(node)
|
125
131
|
name, = *node
|
126
|
-
@
|
132
|
+
@local_variables_scopes[node] << name
|
127
133
|
end
|
128
134
|
|
129
135
|
def keyword?(method_name)
|
@@ -139,10 +145,13 @@ module RuboCop
|
|
139
145
|
end
|
140
146
|
|
141
147
|
def allow_self(node)
|
142
|
-
return unless node.
|
148
|
+
return unless node.send_type?
|
143
149
|
|
144
150
|
receiver, _method_name, *_args = *node
|
145
|
-
|
151
|
+
|
152
|
+
return unless receiver && receiver.self_type?
|
153
|
+
|
154
|
+
@allowed_send_nodes << node
|
146
155
|
end
|
147
156
|
end
|
148
157
|
end
|
@@ -46,23 +46,30 @@ module RuboCop
|
|
46
46
|
private
|
47
47
|
|
48
48
|
def check_slash_literal(node)
|
49
|
-
return if
|
50
|
-
return if style == :mixed &&
|
51
|
-
node.single_line? &&
|
52
|
-
!contains_disallowed_slash?(node)
|
49
|
+
return if allowed_slash_literal?(node)
|
53
50
|
|
54
51
|
add_offense(node, :expression, MSG_USE_PERCENT_R)
|
55
52
|
end
|
56
53
|
|
57
54
|
def check_percent_r_literal(node)
|
58
|
-
return if
|
59
|
-
return if style == :percent_r
|
60
|
-
return if style == :mixed && node.multiline?
|
61
|
-
return if style == :mixed && contains_disallowed_slash?(node)
|
55
|
+
return if allowed_percent_r_literal?(node)
|
62
56
|
|
63
57
|
add_offense(node, :expression, MSG_USE_SLASHES)
|
64
58
|
end
|
65
59
|
|
60
|
+
def allowed_slash_literal?(node)
|
61
|
+
style == :slashes && !contains_disallowed_slash?(node) ||
|
62
|
+
style == :mixed && node.single_line? &&
|
63
|
+
!contains_disallowed_slash?(node)
|
64
|
+
end
|
65
|
+
|
66
|
+
def allowed_percent_r_literal?(node)
|
67
|
+
style == :slashes && contains_disallowed_slash?(node) ||
|
68
|
+
style == :percent_r ||
|
69
|
+
style == :mixed && node.multiline? ||
|
70
|
+
style == :mixed && contains_disallowed_slash?(node)
|
71
|
+
end
|
72
|
+
|
66
73
|
def contains_disallowed_slash?(node)
|
67
74
|
!allow_inner_slashes? && contains_slash?(node)
|
68
75
|
end
|
@@ -76,8 +83,7 @@ module RuboCop
|
|
76
83
|
end
|
77
84
|
|
78
85
|
def node_body(node)
|
79
|
-
|
80
|
-
string_parts.map(&:source).join
|
86
|
+
node.each_child_node(:str).map(&:source).join
|
81
87
|
end
|
82
88
|
|
83
89
|
def slash_literal?(node)
|
@@ -42,12 +42,7 @@ module RuboCop
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def autocorrect(node)
|
45
|
-
|
46
|
-
begin_pos = node.loc.keyword.begin_pos
|
47
|
-
current_column = node.loc.keyword.column
|
48
|
-
whitespace = Parser::Source::Range.new(source_buffer,
|
49
|
-
begin_pos - current_column,
|
50
|
-
begin_pos)
|
45
|
+
whitespace = whitespace_range(node)
|
51
46
|
return false unless whitespace.source.strip.empty?
|
52
47
|
|
53
48
|
new_column = ancestor_node(node).loc.end.column
|
@@ -76,6 +71,13 @@ module RuboCop
|
|
76
71
|
@modifier_locations.include?(node.loc.keyword)
|
77
72
|
end
|
78
73
|
|
74
|
+
def whitespace_range(node)
|
75
|
+
begin_pos = node.loc.keyword.begin_pos
|
76
|
+
current_column = node.loc.keyword.column
|
77
|
+
|
78
|
+
range_between(begin_pos - current_column, begin_pos)
|
79
|
+
end
|
80
|
+
|
79
81
|
def ancestor_node(node)
|
80
82
|
node.each_ancestor(:kwbegin, :def, :defs, :class, :module).first
|
81
83
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
module Style
|
7
|
+
# This cop transforms usages of a method call safeguarded by a non `nil`
|
8
|
+
# check for the variable whose method is being called to
|
9
|
+
# safe navigation (`&.`).
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# foo.bar if foo
|
14
|
+
# foo.bar(param1, param2) if foo
|
15
|
+
# foo.bar { |e| e.something } if foo
|
16
|
+
# foo.bar(param) { |e| e.something } if foo
|
17
|
+
#
|
18
|
+
# foo.bar if !foo.nil?
|
19
|
+
# foo.bar unless !foo
|
20
|
+
# foo.bar unless foo.nil?
|
21
|
+
#
|
22
|
+
# foo && foo.bar
|
23
|
+
# foo && foo.bar(param1, param2)
|
24
|
+
# foo && foo.bar { |e| e.something }
|
25
|
+
# foo && foo.bar(param) { |e| e.something }
|
26
|
+
#
|
27
|
+
# foo.nil? || foo.bar
|
28
|
+
# !foo || foo.bar
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
# foo&.bar
|
32
|
+
# foo&.bar(param1, param2)
|
33
|
+
# foo&.bar { |e| e.something }
|
34
|
+
# foo&.bar(param) { |e| e.something }
|
35
|
+
#
|
36
|
+
# # Methods that `nil` will `respond_to?` should not be converted to
|
37
|
+
# # use safe navigation
|
38
|
+
# foo.to_i if foo
|
39
|
+
class SafeNavigation < Cop
|
40
|
+
MSG = 'Use safe navigation (`&.`) instead of checking if an object ' \
|
41
|
+
'exists before calling the method.'.freeze
|
42
|
+
NIL_METHODS = nil.methods.freeze
|
43
|
+
|
44
|
+
def_node_matcher :safe_navigation_candidate, <<-PATTERN
|
45
|
+
{
|
46
|
+
(if
|
47
|
+
{(send (send $_ :nil?) :!) $_}
|
48
|
+
{(send $_ $_ ...) (block (send $_ $_ ...) ...)}
|
49
|
+
...)
|
50
|
+
(if
|
51
|
+
(send $_ {:nil? :!}) nil
|
52
|
+
{(send $_ $_ ...) (block (send $_ $_ ...) ...)}
|
53
|
+
...)
|
54
|
+
(and
|
55
|
+
{(send (send $_ :nil?) :!) $_}
|
56
|
+
{(send $_ $_ ...) (block (send $_ $_ ...) ...)}
|
57
|
+
...)
|
58
|
+
(or
|
59
|
+
(send $_ {:nil? :!})
|
60
|
+
{(send $_ $_ ...) (block (send $_ $_ ...) ...)}
|
61
|
+
...)
|
62
|
+
}
|
63
|
+
PATTERN
|
64
|
+
|
65
|
+
def on_if(node)
|
66
|
+
check_node(node)
|
67
|
+
end
|
68
|
+
|
69
|
+
def on_and(node)
|
70
|
+
check_node(node)
|
71
|
+
end
|
72
|
+
|
73
|
+
def on_or(node)
|
74
|
+
check_node(node)
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_node(node)
|
78
|
+
return if target_ruby_version < 2.3
|
79
|
+
checked_variable, receiver, method = safe_navigation_candidate(node)
|
80
|
+
return unless receiver == checked_variable
|
81
|
+
return if NIL_METHODS.include?(method)
|
82
|
+
return unless method =~ /\w+[=!?]?/
|
83
|
+
add_offense(node, :expression)
|
84
|
+
end
|
85
|
+
|
86
|
+
def autocorrect(node)
|
87
|
+
lambda do |corrector|
|
88
|
+
if node.loc.respond_to?(:keyword) && node.loc.keyword.is?('unless')
|
89
|
+
_variable_check, _else, method_call = *node
|
90
|
+
else
|
91
|
+
_variable_check, method_call = *node
|
92
|
+
end
|
93
|
+
|
94
|
+
if method_call.block_type?
|
95
|
+
method, = *method_call
|
96
|
+
corrector.insert_before(method.loc.dot, '&')
|
97
|
+
else
|
98
|
+
corrector.insert_before(method_call.loc.dot, '&')
|
99
|
+
end
|
100
|
+
|
101
|
+
corrector.remove(range(node, method_call))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def range(node, method_call)
|
108
|
+
source_buffer = node.loc.expression.source_buffer
|
109
|
+
node_expression = node.loc.expression
|
110
|
+
method_expression = method_call.loc.expression
|
111
|
+
|
112
|
+
if node.and_type? || node.or_type?
|
113
|
+
Parser::Source::Range.new(source_buffer,
|
114
|
+
node_expression.begin_pos,
|
115
|
+
method_expression.begin_pos)
|
116
|
+
else
|
117
|
+
Parser::Source::Range.new(source_buffer,
|
118
|
+
method_expression.end_pos,
|
119
|
+
node_expression.end_pos)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
var_name, rhs = *node
|
36
36
|
return unless rhs
|
37
37
|
|
38
|
-
if rhs.
|
38
|
+
if rhs.send_type?
|
39
39
|
check_send_node(node, rhs, var_name, var_type)
|
40
40
|
elsif [:and, :or].include?(rhs.type)
|
41
41
|
check_boolean_node(node, rhs, var_name, var_type)
|
@@ -65,7 +65,7 @@ module RuboCop
|
|
65
65
|
def autocorrect(node)
|
66
66
|
_var_name, rhs = *node
|
67
67
|
|
68
|
-
if rhs.
|
68
|
+
if rhs.send_type?
|
69
69
|
autocorrect_send_node(node, rhs)
|
70
70
|
elsif [:and, :or].include?(rhs.type)
|
71
71
|
autocorrect_boolean_node(node, rhs)
|
@@ -40,21 +40,20 @@ module RuboCop
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def check_for_line_terminator_or_opener
|
43
|
-
|
44
|
-
|
45
|
-
end
|
43
|
+
each_semicolon { |line, column| convention_on(line, column, true) }
|
44
|
+
end
|
46
45
|
|
46
|
+
def each_semicolon
|
47
47
|
tokens_for_lines.each do |line, tokens|
|
48
|
-
if tokens.last.type == :tSEMI
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
if tokens.first.type == :tSEMI
|
53
|
-
convention_on(line, tokens.first.pos.column, true)
|
54
|
-
end
|
48
|
+
yield line, tokens.last.pos.column if tokens.last.type == :tSEMI
|
49
|
+
yield line, tokens.first.pos.column if tokens.first.type == :tSEMI
|
55
50
|
end
|
56
51
|
end
|
57
52
|
|
53
|
+
def tokens_for_lines
|
54
|
+
@processed_source.tokens.group_by { |token| token.pos.line }
|
55
|
+
end
|
56
|
+
|
58
57
|
def convention_on(line, column, autocorrect)
|
59
58
|
range = source_range(@processed_source.buffer, line, column)
|
60
59
|
# Don't attempt to autocorrect if semicolon is separating statements
|
@@ -84,11 +84,9 @@ module RuboCop
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def check_send(method_name, node)
|
87
|
-
return unless node
|
87
|
+
return unless node && command_or_kernel_call?(method_name, node)
|
88
88
|
|
89
|
-
|
90
|
-
add_offense(node, :selector, message(method_name))
|
91
|
-
end
|
89
|
+
add_offense(node, :selector, message(method_name))
|
92
90
|
end
|
93
91
|
|
94
92
|
def command_or_kernel_call?(name, node)
|
@@ -25,7 +25,7 @@ module RuboCop
|
|
25
25
|
|
26
26
|
return if args.empty?
|
27
27
|
# discard cases with argument destructuring
|
28
|
-
return true unless args.all?
|
28
|
+
return true unless args.all?(&:arg_type?)
|
29
29
|
return if args_match?(method_name, args)
|
30
30
|
|
31
31
|
add_offense(args_node, :expression, message(method_name))
|
@@ -31,26 +31,33 @@ module RuboCop
|
|
31
31
|
|
32
32
|
def autocorrect(node)
|
33
33
|
body = @body
|
34
|
-
|
35
|
-
c.loc.line == node.source_range.line
|
36
|
-
end
|
34
|
+
|
37
35
|
lambda do |corrector|
|
38
|
-
|
39
|
-
|
40
|
-
body.children.each do |part|
|
41
|
-
break_line_before(part.source_range, node, corrector, 1)
|
42
|
-
end
|
43
|
-
else
|
44
|
-
break_line_before(body.source_range, node, corrector, 1)
|
45
|
-
end
|
36
|
+
each_part(body) do |part|
|
37
|
+
break_line_before(part, node, corrector, 1)
|
46
38
|
end
|
47
39
|
|
48
40
|
break_line_before(node.loc.end, node, corrector, 0)
|
49
41
|
|
42
|
+
eol_comment = end_of_line_comment(node.source_range.line)
|
50
43
|
move_comment(eol_comment, node, corrector) if eol_comment
|
51
44
|
end
|
52
45
|
end
|
53
46
|
|
47
|
+
def end_of_line_comment(line)
|
48
|
+
processed_source.comments.find { |c| c.loc.line == line }
|
49
|
+
end
|
50
|
+
|
51
|
+
def each_part(body)
|
52
|
+
return unless body
|
53
|
+
|
54
|
+
if body.begin_type?
|
55
|
+
body.each_child_node { |part| yield part.source_range }
|
56
|
+
else
|
57
|
+
yield body.source_range
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
54
61
|
def break_line_before(range, node, corrector, indent_steps)
|
55
62
|
corrector.insert_before(
|
56
63
|
range,
|
@@ -22,9 +22,8 @@ module RuboCop
|
|
22
22
|
def on_method_def(_node, _method_name, args, _body)
|
23
23
|
return unless args.loc.begin && args.loc.begin.is?('(')
|
24
24
|
expr = args.source_range
|
25
|
-
pos_before_left_paren =
|
26
|
-
|
27
|
-
expr.begin_pos)
|
25
|
+
pos_before_left_paren = range_between(expr.begin_pos - 1,
|
26
|
+
expr.begin_pos)
|
28
27
|
return unless pos_before_left_paren.source =~ /\s/
|
29
28
|
|
30
29
|
add_offense(pos_before_left_paren, pos_before_left_paren)
|
@@ -16,9 +16,9 @@ module RuboCop
|
|
16
16
|
MSG = 'Do not leave space between `!` and its argument.'.freeze
|
17
17
|
|
18
18
|
def on_send(node)
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
return unless node.keyword_bang? && whitespace_after_bang_op?(node)
|
20
|
+
|
21
|
+
add_offense(node, :expression)
|
22
22
|
end
|
23
23
|
|
24
24
|
def whitespace_after_bang_op?(node)
|
@@ -29,9 +29,7 @@ module RuboCop
|
|
29
29
|
def autocorrect(node)
|
30
30
|
lambda do |corrector|
|
31
31
|
receiver, _method_name, *_args = *node
|
32
|
-
space_range =
|
33
|
-
Parser::Source::Range.new(node.loc.selector.source_buffer,
|
34
|
-
node.loc.selector.end_pos,
|
32
|
+
space_range = range_between(node.loc.selector.end_pos,
|
35
33
|
receiver.source_range.begin_pos)
|
36
34
|
corrector.remove(space_range)
|
37
35
|
end
|