rubocop 0.46.0 → 0.47.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/LICENSE.txt +1 -1
- data/README.md +77 -2
- data/config/default.yml +151 -74
- data/config/disabled.yml +9 -0
- data/config/enabled.yml +49 -9
- data/lib/rubocop.rb +36 -8
- data/lib/rubocop/ast/builder.rb +59 -0
- data/lib/rubocop/ast/node.rb +607 -0
- data/lib/rubocop/ast/node/array_node.rb +45 -0
- data/lib/rubocop/ast/node/case_node.rb +63 -0
- data/lib/rubocop/ast/node/for_node.rb +53 -0
- data/lib/rubocop/ast/node/hash_node.rb +102 -0
- data/lib/rubocop/ast/node/if_node.rb +136 -0
- data/lib/rubocop/ast/node/keyword_splat_node.rb +45 -0
- data/lib/rubocop/ast/node/mixin/conditional_node.rb +45 -0
- data/lib/rubocop/ast/node/mixin/hash_element_node.rb +125 -0
- data/lib/rubocop/ast/node/mixin/modifier_node.rb +17 -0
- data/lib/rubocop/ast/node/pair_node.rb +64 -0
- data/lib/rubocop/ast/node/until_node.rb +43 -0
- data/lib/rubocop/ast/node/when_node.rb +61 -0
- data/lib/rubocop/ast/node/while_node.rb +43 -0
- data/lib/rubocop/ast/sexp.rb +16 -0
- data/lib/rubocop/{ast_node → ast}/traversal.rb +1 -1
- data/lib/rubocop/cli.rb +18 -14
- data/lib/rubocop/comment_config.rb +1 -3
- data/lib/rubocop/config.rb +93 -35
- data/lib/rubocop/config_loader.rb +1 -1
- data/lib/rubocop/cop/badge.rb +73 -0
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
- data/lib/rubocop/cop/bundler/ordered_gems.rb +43 -3
- data/lib/rubocop/cop/commissioner.rb +17 -6
- data/lib/rubocop/cop/cop.rb +25 -112
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +9 -4
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +7 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +18 -4
- data/lib/rubocop/cop/lint/block_alignment.rb +40 -9
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +14 -0
- data/lib/rubocop/cop/lint/condition_position.rb +14 -16
- data/lib/rubocop/cop/lint/debugger.rb +28 -0
- data/lib/rubocop/cop/lint/def_end_alignment.rb +21 -1
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +13 -1
- data/lib/rubocop/cop/lint/duplicate_case_condition.rb +26 -22
- data/lib/rubocop/cop/lint/duplicate_methods.rb +15 -1
- data/lib/rubocop/cop/lint/duplicated_key.rb +16 -8
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +9 -0
- data/lib/rubocop/cop/lint/else_layout.rb +26 -29
- data/lib/rubocop/cop/lint/empty_ensure.rb +38 -0
- data/lib/rubocop/cop/lint/empty_expression.rb +11 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +8 -0
- data/lib/rubocop/cop/lint/empty_when.rb +14 -16
- data/lib/rubocop/cop/lint/end_alignment.rb +48 -28
- data/lib/rubocop/cop/lint/end_in_method.rb +23 -0
- data/lib/rubocop/cop/lint/ensure_return.rb +21 -0
- data/lib/rubocop/cop/lint/float_out_of_range.rb +5 -0
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +29 -4
- data/lib/rubocop/cop/lint/handle_exceptions.rb +40 -0
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +7 -2
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +11 -2
- data/lib/rubocop/cop/lint/invalid_character_literal.rb +3 -0
- data/lib/rubocop/cop/lint/literal_in_condition.rb +34 -36
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +8 -0
- data/lib/rubocop/cop/lint/loop.rb +36 -0
- data/lib/rubocop/cop/lint/multiple_compare.rb +46 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +22 -0
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +5 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -0
- data/lib/rubocop/cop/lint/percent_string_array.rb +27 -13
- data/lib/rubocop/cop/lint/percent_symbol_array.rb +14 -4
- data/lib/rubocop/cop/lint/rand_one.rb +7 -3
- data/lib/rubocop/cop/lint/require_parentheses.rb +20 -19
- data/lib/rubocop/cop/lint/rescue_exception.rb +20 -0
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +66 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +24 -0
- data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +8 -0
- data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +24 -0
- data/lib/rubocop/cop/lint/unified_integer.rb +5 -0
- data/lib/rubocop/cop/lint/unneeded_disable.rb +2 -2
- data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +5 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +17 -0
- data/lib/rubocop/cop/lint/unused_block_argument.rb +2 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +28 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +18 -0
- data/lib/rubocop/cop/lint/useless_comparison.rb +3 -1
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +16 -1
- data/lib/rubocop/cop/lint/useless_setter_call.rb +16 -4
- data/lib/rubocop/cop/lint/void.rb +52 -0
- data/lib/rubocop/cop/message_annotator.rb +102 -0
- data/lib/rubocop/cop/metrics/block_length.rb +6 -0
- data/lib/rubocop/cop/metrics/block_nesting.rb +17 -5
- data/lib/rubocop/cop/metrics/line_length.rb +11 -4
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
- data/lib/rubocop/cop/mixin/array_syntax.rb +2 -11
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +12 -5
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +48 -0
- data/lib/rubocop/cop/mixin/configurable_max.rb +3 -3
- data/lib/rubocop/cop/mixin/configurable_naming.rb +5 -33
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +6 -47
- data/lib/rubocop/cop/mixin/documentation_comment.rb +7 -1
- data/lib/rubocop/cop/mixin/duplication.rb +46 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +14 -11
- data/lib/rubocop/cop/mixin/hash_alignment.rb +114 -0
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -3
- data/lib/rubocop/cop/mixin/negative_conditional.rb +21 -7
- data/lib/rubocop/cop/mixin/on_method_def.rb +14 -0
- data/lib/rubocop/cop/mixin/on_normal_if_unless.rb +1 -24
- data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -13
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +16 -0
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -3
- data/lib/rubocop/cop/offense.rb +1 -1
- data/lib/rubocop/cop/performance/case_when_splat.rb +56 -59
- data/lib/rubocop/cop/performance/detect.rb +2 -2
- data/lib/rubocop/cop/performance/flat_map.rb +3 -3
- data/lib/rubocop/cop/performance/redundant_merge.rb +3 -6
- data/lib/rubocop/cop/performance/regexp_match.rb +201 -0
- data/lib/rubocop/cop/rails/delegate.rb +2 -2
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +10 -19
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +12 -40
- data/lib/rubocop/cop/rails/file_path.rb +80 -0
- data/lib/rubocop/cop/rails/find_each.rb +5 -14
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +30 -24
- data/lib/rubocop/cop/rails/not_null_column.rb +23 -0
- data/lib/rubocop/cop/rails/reversible_migration.rb +217 -0
- data/lib/rubocop/cop/rails/safe_navigation.rb +4 -2
- data/lib/rubocop/cop/rails/skips_model_validations.rb +46 -0
- data/lib/rubocop/cop/rails/time_zone.rb +1 -1
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +7 -5
- data/lib/rubocop/cop/registry.rb +170 -0
- data/lib/rubocop/cop/{lint → security}/eval.rb +7 -1
- data/lib/rubocop/cop/security/marshal_load.rb +33 -0
- data/lib/rubocop/cop/security/yaml_load.rb +37 -0
- data/lib/rubocop/cop/style/align_hash.rb +138 -169
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +10 -15
- data/lib/rubocop/cop/style/case_indentation.rb +36 -27
- data/lib/rubocop/cop/style/conditional_assignment.rb +64 -47
- data/lib/rubocop/cop/style/each_with_object.rb +4 -1
- data/lib/rubocop/cop/style/else_alignment.rb +14 -20
- data/lib/rubocop/cop/style/empty_case_condition.rb +16 -25
- data/lib/rubocop/cop/style/empty_else.rb +20 -22
- data/lib/rubocop/cop/style/empty_literal.rb +4 -4
- data/lib/rubocop/cop/style/empty_method.rb +12 -6
- data/lib/rubocop/cop/style/encoding.rb +1 -1
- data/lib/rubocop/cop/style/file_name.rb +24 -4
- data/lib/rubocop/cop/style/first_method_argument_line_break.rb +1 -1
- data/lib/rubocop/cop/style/format_string.rb +17 -48
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +40 -11
- data/lib/rubocop/cop/style/guard_clause.rb +11 -17
- data/lib/rubocop/cop/style/hash_syntax.rb +24 -42
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +40 -28
- data/lib/rubocop/cop/style/if_inside_else.rb +6 -9
- data/lib/rubocop/cop/style/if_unless_modifier.rb +16 -25
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +3 -9
- data/lib/rubocop/cop/style/indent_array.rb +1 -1
- data/lib/rubocop/cop/style/indentation_width.rb +29 -60
- data/lib/rubocop/cop/style/infinite_loop.rb +21 -22
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +86 -0
- data/lib/rubocop/cop/style/{method_call_parentheses.rb → method_call_without_args_parentheses.rb} +8 -1
- data/lib/rubocop/cop/style/missing_else.rb +40 -14
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +5 -15
- data/lib/rubocop/cop/style/multiline_if_then.rb +14 -8
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +3 -3
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -5
- data/lib/rubocop/cop/style/mutable_constant.rb +3 -2
- data/lib/rubocop/cop/style/negated_if.rb +3 -19
- data/lib/rubocop/cop/style/negated_while.rb +2 -17
- data/lib/rubocop/cop/style/nested_modifier.rb +16 -43
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -5
- data/lib/rubocop/cop/style/next.rb +23 -21
- data/lib/rubocop/cop/style/non_nil_check.rb +2 -3
- data/lib/rubocop/cop/style/not.rb +1 -3
- data/lib/rubocop/cop/style/numeric_literals.rb +2 -2
- data/lib/rubocop/cop/style/one_line_conditional.rb +12 -22
- data/lib/rubocop/cop/style/option_hash.rb +4 -15
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -12
- data/lib/rubocop/cop/style/percent_q_literals.rb +15 -12
- data/lib/rubocop/cop/style/redundant_freeze.rb +3 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +27 -4
- data/lib/rubocop/cop/style/redundant_return.rb +4 -8
- data/lib/rubocop/cop/style/safe_navigation.rb +13 -6
- data/lib/rubocop/cop/style/space_after_colon.rb +2 -4
- data/lib/rubocop/cop/style/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/style/space_around_operators.rb +15 -13
- data/lib/rubocop/cop/style/string_methods.rb +1 -3
- data/lib/rubocop/cop/style/symbol_array.rb +1 -5
- data/lib/rubocop/cop/style/ternary_parentheses.rb +5 -6
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +2 -5
- data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -1
- data/lib/rubocop/cop/style/unless_else.rb +1 -5
- data/lib/rubocop/cop/style/when_then.rb +4 -2
- data/lib/rubocop/cop/style/while_until_do.rb +9 -13
- data/lib/rubocop/cop/style/while_until_modifier.rb +12 -11
- data/lib/rubocop/cop/style/word_array.rb +5 -9
- data/lib/rubocop/cop/team.rb +16 -15
- data/lib/rubocop/cop/util.rb +13 -3
- data/lib/rubocop/formatter/clang_style_formatter.rb +2 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
- data/lib/rubocop/magic_comment.rb +196 -0
- data/lib/rubocop/options.rb +5 -4
- data/lib/rubocop/processed_source.rb +1 -1
- data/lib/rubocop/rspec/cop_helper.rb +9 -0
- data/lib/rubocop/rspec/shared_examples.rb +1 -1
- data/lib/rubocop/runner.rb +7 -2
- data/lib/rubocop/version.rb +1 -1
- metadata +41 -14
- data/lib/rubocop/ast_node.rb +0 -624
- data/lib/rubocop/ast_node/builder.rb +0 -30
- data/lib/rubocop/ast_node/sexp.rb +0 -13
- data/lib/rubocop/cop/mixin/hash_node.rb +0 -14
- data/lib/rubocop/cop/mixin/if_node.rb +0 -42
@@ -101,9 +101,9 @@ module RuboCop
|
|
101
101
|
next unless a.loc.respond_to?(:keyword)
|
102
102
|
|
103
103
|
case a.type
|
104
|
-
when :
|
105
|
-
when :
|
106
|
-
when
|
104
|
+
when :for then _, expression, = *a
|
105
|
+
when :return then expression, = *a
|
106
|
+
when *Util::MODIFIER_NODES then expression, = *a
|
107
107
|
end
|
108
108
|
|
109
109
|
within_node?(node, expression) if expression
|
@@ -2,28 +2,42 @@
|
|
2
2
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
|
-
# Some common code shared between
|
6
|
-
#
|
5
|
+
# Some common code shared between `NegatedIf` and
|
6
|
+
# `NegatedWhile` cops.
|
7
7
|
module NegativeConditional
|
8
8
|
extend NodePattern::Macros
|
9
|
-
include IfNode
|
10
9
|
|
11
10
|
def_node_matcher :single_negative?, '(send !(send _ :!) :!)'
|
12
11
|
def_node_matcher :empty_condition?, '(begin)'
|
13
12
|
|
14
13
|
def check_negative_conditional(node)
|
15
|
-
condition
|
14
|
+
condition = node.condition
|
16
15
|
|
17
16
|
return if empty_condition?(condition)
|
18
17
|
|
19
|
-
# Look at last expression of contents if there are parentheses
|
20
|
-
# around condition.
|
21
18
|
condition = condition.children.last while condition.begin_type?
|
22
19
|
|
23
|
-
return unless single_negative?(condition)
|
20
|
+
return unless single_negative?(condition)
|
21
|
+
return if node.if_type? && node.else?
|
24
22
|
|
25
23
|
add_offense(node, :expression)
|
26
24
|
end
|
25
|
+
|
26
|
+
def negative_conditional_corrector(node)
|
27
|
+
condition = negated_condition(node)
|
28
|
+
|
29
|
+
lambda do |corrector|
|
30
|
+
corrector.replace(node.loc.keyword, node.inverse_keyword)
|
31
|
+
corrector.replace(condition.source_range,
|
32
|
+
condition.children.first.source)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def negated_condition(node)
|
37
|
+
condition = node.condition
|
38
|
+
condition = condition.children.first while condition.begin_type?
|
39
|
+
condition
|
40
|
+
end
|
27
41
|
end
|
28
42
|
end
|
29
43
|
end
|
@@ -14,6 +14,20 @@ module RuboCop
|
|
14
14
|
on_method_def(node, method_name, args, body)
|
15
15
|
end
|
16
16
|
|
17
|
+
# This method provides scope agnostic method node destructuring by moving
|
18
|
+
# the scope to the end where it can easily be ignored.
|
19
|
+
def method_def_node_parts(node)
|
20
|
+
if node.def_type?
|
21
|
+
method_name, args, body = *node
|
22
|
+
elsif node.defs_type?
|
23
|
+
scope, method_name, args, body = *node
|
24
|
+
else
|
25
|
+
return []
|
26
|
+
end
|
27
|
+
|
28
|
+
[method_name, args, body, scope]
|
29
|
+
end
|
30
|
+
|
17
31
|
private
|
18
32
|
|
19
33
|
# Returns true for constructs such as
|
@@ -4,34 +4,11 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common functionality for cops checking if and unless expressions.
|
6
6
|
module OnNormalIfUnless
|
7
|
-
include IfNode
|
8
|
-
|
9
7
|
def on_if(node)
|
10
|
-
|
11
|
-
end
|
8
|
+
return if node.modifier_form? || node.ternary?
|
12
9
|
|
13
|
-
def invoke_hook_for_normal_if_unless(node)
|
14
|
-
# We won't check modifier or ternary conditionals.
|
15
|
-
return if modifier_if?(node) || ternary?(node)
|
16
10
|
on_normal_if_unless(node)
|
17
11
|
end
|
18
|
-
|
19
|
-
def if_else_clause(node)
|
20
|
-
return unless node.if_type?
|
21
|
-
|
22
|
-
keyword = node.loc.keyword
|
23
|
-
if keyword.is?('if')
|
24
|
-
node.children.last
|
25
|
-
elsif keyword.is?('elsif')
|
26
|
-
node.children.last
|
27
|
-
elsif keyword.is?('unless')
|
28
|
-
node.children[1]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def case_else_clause(node)
|
33
|
-
node.children.last if node.case_type?
|
34
|
-
end
|
35
12
|
end
|
36
13
|
end
|
37
14
|
end
|
@@ -4,13 +4,10 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common functionality for modifier cops.
|
6
6
|
module StatementModifier
|
7
|
-
include IfNode
|
8
|
-
|
9
7
|
def single_line_as_modifier?(node)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
non_eligible_condition?(cond)
|
8
|
+
return false if non_eligible_node?(node) ||
|
9
|
+
non_eligible_body?(node.body) ||
|
10
|
+
non_eligible_condition?(node.condition)
|
14
11
|
|
15
12
|
modifier_fits_on_single_line?(node)
|
16
13
|
end
|
@@ -20,9 +17,7 @@ module RuboCop
|
|
20
17
|
end
|
21
18
|
|
22
19
|
def non_eligible_body?(body)
|
23
|
-
|
24
|
-
|
25
|
-
body.begin_type? || empty_body?(body) || commented?(body.source_range)
|
20
|
+
empty_body?(body) || body.begin_type? || commented?(body.source_range)
|
26
21
|
end
|
27
22
|
|
28
23
|
def non_eligible_condition?(condition)
|
@@ -30,10 +25,10 @@ module RuboCop
|
|
30
25
|
end
|
31
26
|
|
32
27
|
def modifier_fits_on_single_line?(node)
|
33
|
-
|
34
|
-
|
28
|
+
modifier_length = length_in_modifier_form(node, node.condition,
|
29
|
+
body_length(node.body))
|
35
30
|
|
36
|
-
|
31
|
+
modifier_length <= max_line_length
|
37
32
|
end
|
38
33
|
|
39
34
|
def length_in_modifier_form(node, cond, body_length)
|
@@ -54,7 +49,7 @@ module RuboCop
|
|
54
49
|
end
|
55
50
|
|
56
51
|
def empty_body?(body)
|
57
|
-
body_length(body).zero?
|
52
|
+
!body || body_length(body).zero?
|
58
53
|
end
|
59
54
|
|
60
55
|
def body_length(body)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for checking target ruby version.
|
6
|
+
module TargetRubyVersion
|
7
|
+
def minimum_target_ruby_version(version)
|
8
|
+
@minimum_target_ruby_version = version
|
9
|
+
end
|
10
|
+
|
11
|
+
def support_target_ruby_version?(version)
|
12
|
+
@minimum_target_ruby_version <= version
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
|
10
10
|
MSG = '%s comma after the last %s'.freeze
|
11
11
|
|
12
|
-
def
|
12
|
+
def style_parameter_name
|
13
13
|
'EnforcedStyleForMultiline'
|
14
14
|
end
|
15
15
|
|
@@ -95,8 +95,7 @@ module RuboCop
|
|
95
95
|
# For each argument, if it is a multi-line hash without braces,
|
96
96
|
# then promote the hash elements to method arguments
|
97
97
|
# for the purpose of determining multi-line-ness.
|
98
|
-
if a.hash_type? && a.
|
99
|
-
!brackets?(a)
|
98
|
+
if a.hash_type? && a.multiline? && !a.braces?
|
100
99
|
a.children
|
101
100
|
else
|
102
101
|
a
|
data/lib/rubocop/cop/offense.rb
CHANGED
@@ -61,13 +61,8 @@ module RuboCop
|
|
61
61
|
PERCENT_I = '%i'.freeze
|
62
62
|
PERCENT_CAPITAL_I = '%I'.freeze
|
63
63
|
|
64
|
-
def on_case(
|
65
|
-
|
66
|
-
when_conditions =
|
67
|
-
when_branches.each_with_object([]) do |branch, conditions|
|
68
|
-
*condition, _ = *branch
|
69
|
-
condition.each { |c| conditions << c }
|
70
|
-
end
|
64
|
+
def on_case(case_node)
|
65
|
+
when_conditions = case_node.when_branches.flat_map(&:conditions)
|
71
66
|
|
72
67
|
splat_offenses(when_conditions).reverse_each do |condition|
|
73
68
|
range = condition.parent.loc.keyword.join(condition.source_range)
|
@@ -77,99 +72,101 @@ module RuboCop
|
|
77
72
|
end
|
78
73
|
end
|
79
74
|
|
80
|
-
|
81
|
-
*conditions, _body = *node
|
75
|
+
private
|
82
76
|
|
77
|
+
def autocorrect(when_node)
|
83
78
|
lambda do |corrector|
|
84
|
-
if needs_reorder?(
|
85
|
-
reorder_condition(corrector,
|
79
|
+
if needs_reorder?(when_node)
|
80
|
+
reorder_condition(corrector, when_node)
|
86
81
|
else
|
87
|
-
inline_fix_branch(corrector,
|
88
|
-
replacement(conditions))
|
82
|
+
inline_fix_branch(corrector, when_node)
|
89
83
|
end
|
90
84
|
end
|
91
85
|
end
|
92
86
|
|
93
|
-
private
|
94
|
-
|
95
87
|
def replacement(conditions)
|
96
|
-
|
97
|
-
|
98
|
-
ordered_conditions.map!(&:source)
|
99
|
-
ordered_conditions.join(', ')
|
88
|
+
reordered = conditions.partition(&:splat_type?).reverse
|
89
|
+
reordered.flatten.map(&:source).join(', ')
|
100
90
|
end
|
101
91
|
|
102
|
-
def inline_fix_branch(corrector,
|
92
|
+
def inline_fix_branch(corrector, when_node)
|
93
|
+
conditions = when_node.conditions
|
103
94
|
range = range_between(conditions[0].loc.expression.begin_pos,
|
104
95
|
conditions[-1].loc.expression.end_pos)
|
105
|
-
|
96
|
+
|
97
|
+
corrector.replace(range, replacement(conditions))
|
106
98
|
end
|
107
99
|
|
108
|
-
def reorder_condition(corrector,
|
109
|
-
|
110
|
-
|
111
|
-
return if when_branches.
|
100
|
+
def reorder_condition(corrector, when_node)
|
101
|
+
when_branches = when_node.parent.when_branches
|
102
|
+
|
103
|
+
return if when_branches.one?
|
112
104
|
|
113
|
-
corrector.remove(when_branch_range(
|
105
|
+
corrector.remove(when_branch_range(when_node))
|
106
|
+
corrector.insert_after(when_branches.last.source_range,
|
107
|
+
reordering_correction(when_node))
|
108
|
+
end
|
114
109
|
|
115
|
-
|
116
|
-
|
117
|
-
else
|
118
|
-
new_branch_without_then(node, body, new_condition)
|
119
|
-
end
|
110
|
+
def reordering_correction(when_node)
|
111
|
+
new_condition = replacement(when_node.conditions)
|
120
112
|
|
121
|
-
|
113
|
+
if same_line?(when_node, when_node.body)
|
114
|
+
new_condition_with_then(when_node, new_condition)
|
115
|
+
else
|
116
|
+
new_branch_without_then(when_node, new_condition)
|
117
|
+
end
|
122
118
|
end
|
123
119
|
|
124
|
-
def when_branch_range(
|
125
|
-
|
126
|
-
|
120
|
+
def when_branch_range(when_node)
|
121
|
+
next_branch =
|
122
|
+
when_node.parent.when_branches[when_node.branch_index + 1]
|
127
123
|
|
128
|
-
range_between(
|
124
|
+
range_between(when_node.source_range.begin_pos,
|
129
125
|
next_branch.source_range.begin_pos)
|
130
126
|
end
|
131
127
|
|
132
|
-
def
|
133
|
-
node
|
128
|
+
def new_condition_with_then(node, new_condition)
|
129
|
+
"\n#{indent_for(node)}when " \
|
130
|
+
"#{new_condition} then #{node.body.source}"
|
134
131
|
end
|
135
132
|
|
136
|
-
def
|
137
|
-
"\n#{
|
138
|
-
"#{
|
133
|
+
def new_branch_without_then(node, new_condition)
|
134
|
+
"\n#{indent_for(node)}when #{new_condition}" \
|
135
|
+
"\n#{indent_for(node.body)}#{node.body.source}"
|
139
136
|
end
|
140
137
|
|
141
|
-
def
|
142
|
-
|
143
|
-
"#{' ' * body.loc.column}#{node.children.last.source}"
|
138
|
+
def indent_for(node)
|
139
|
+
' ' * node.loc.column
|
144
140
|
end
|
145
141
|
|
146
142
|
def splat_offenses(when_conditions)
|
147
143
|
found_non_splat = false
|
148
|
-
when_conditions.reverse.each_with_object([]) do |condition, result|
|
149
|
-
found_non_splat ||= error_condition?(condition)
|
150
144
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
145
|
+
offenses = when_conditions.reverse.map do |condition|
|
146
|
+
found_non_splat ||= non_splat?(condition)
|
147
|
+
|
148
|
+
next if non_splat?(condition)
|
149
|
+
|
150
|
+
condition if found_non_splat
|
155
151
|
end
|
152
|
+
|
153
|
+
offenses.compact
|
156
154
|
end
|
157
155
|
|
158
|
-
def
|
156
|
+
def non_splat?(condition)
|
159
157
|
variable, = *condition
|
160
158
|
|
161
159
|
(condition.splat_type? && variable.array_type?) ||
|
162
160
|
!condition.splat_type?
|
163
161
|
end
|
164
162
|
|
165
|
-
def needs_reorder?(
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
conditions.
|
171
|
-
|
172
|
-
condition.splat_type? && !(variable && variable.array_type?)
|
163
|
+
def needs_reorder?(when_node)
|
164
|
+
following_branches =
|
165
|
+
when_node.parent.when_branches[(when_node.branch_index + 1)..-1]
|
166
|
+
|
167
|
+
following_branches.any? do |when_branch|
|
168
|
+
when_branch.conditions.any? do |condition|
|
169
|
+
non_splat?(condition)
|
173
170
|
end
|
174
171
|
end
|
175
172
|
end
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
receiver, _args, body = *receiver if receiver.block_type?
|
46
46
|
return if accept_first_call?(receiver, body)
|
47
47
|
|
48
|
-
|
48
|
+
register_offense(node, receiver, second_method)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -79,7 +79,7 @@ module RuboCop
|
|
79
79
|
lazy?(caller)
|
80
80
|
end
|
81
81
|
|
82
|
-
def
|
82
|
+
def register_offense(node, receiver, second_method)
|
83
83
|
_caller, first_method, _args = *receiver
|
84
84
|
range = receiver.loc.selector.join(node.loc.selector)
|
85
85
|
|
@@ -54,14 +54,14 @@ module RuboCop
|
|
54
54
|
|
55
55
|
def offense_for_levels(node, map_node, first_method, flatten)
|
56
56
|
message = MSG + FLATTEN_MULTIPLE_LEVELS
|
57
|
-
|
57
|
+
register_offense(node, map_node, first_method, flatten, message)
|
58
58
|
end
|
59
59
|
|
60
60
|
def offense_for_method(node, map_node, first_method, flatten)
|
61
|
-
|
61
|
+
register_offense(node, map_node, first_method, flatten, MSG)
|
62
62
|
end
|
63
63
|
|
64
|
-
def
|
64
|
+
def register_offense(node, map_node, first_method, flatten, message)
|
65
65
|
range = range_between(map_node.loc.selector.begin_pos,
|
66
66
|
node.loc.expression.end_pos)
|
67
67
|
|
@@ -73,13 +73,10 @@ module RuboCop
|
|
73
73
|
def to_assignments(receiver, pairs)
|
74
74
|
pairs.map do |pair|
|
75
75
|
key, value = *pair
|
76
|
-
key_src = if key.sym_type? && !key.source.start_with?(':')
|
77
|
-
":#{key.source}"
|
78
|
-
else
|
79
|
-
key.source
|
80
|
-
end
|
81
76
|
|
82
|
-
|
77
|
+
key = key.sym_type? && pair.colon? ? ":#{key.source}" : key.source
|
78
|
+
|
79
|
+
format(AREF_ASGN, receiver.source, key, value.source)
|
83
80
|
end
|
84
81
|
end
|
85
82
|
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# In Ruby 2.4, `String#match?`, `Regexp#match?` and `Symbol#match?`
|
7
|
+
# have been added. The methods are faster than `match`.
|
8
|
+
# Because the methods avoid creating a `MatchData` object or saving
|
9
|
+
# backref.
|
10
|
+
# So, when `MatchData` is not used, use `match?` instead of `match`.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# def foo
|
15
|
+
# if x =~ /re/
|
16
|
+
# do_something
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# def foo
|
22
|
+
# if x.match(/re/)
|
23
|
+
# do_something
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # bad
|
28
|
+
# def foo
|
29
|
+
# if /re/ === x
|
30
|
+
# do_something
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# def foo
|
36
|
+
# if x.match?(/re/)
|
37
|
+
# do_something
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# # good
|
42
|
+
# def foo
|
43
|
+
# if x =~ /re/
|
44
|
+
# do_something(Regexp.last_match)
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# # good
|
49
|
+
# def foo
|
50
|
+
# if x.match(/re/)
|
51
|
+
# do_something($~)
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# # good
|
56
|
+
# def foo
|
57
|
+
# if /re/ === x
|
58
|
+
# do_something($~)
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
class RegexpMatch < Cop
|
62
|
+
extend TargetRubyVersion
|
63
|
+
|
64
|
+
minimum_target_ruby_version 2.4
|
65
|
+
|
66
|
+
MSG =
|
67
|
+
'Use `match?` instead of `%s` when `MatchData` is not used.'.freeze
|
68
|
+
|
69
|
+
def_node_matcher :match_method?, <<-PATTERN
|
70
|
+
{
|
71
|
+
(send _recv :match _)
|
72
|
+
(send _recv :match _ (:int ...))
|
73
|
+
}
|
74
|
+
PATTERN
|
75
|
+
|
76
|
+
def_node_matcher :match_operator?, <<-PATTERN
|
77
|
+
(send !nil :=~ !nil)
|
78
|
+
PATTERN
|
79
|
+
|
80
|
+
def_node_matcher :match_threequals?, <<-PATTERN
|
81
|
+
(send (regexp (str _) {(regopt) (regopt _)}) :=== !nil)
|
82
|
+
PATTERN
|
83
|
+
|
84
|
+
def_node_matcher :match_with_lvasgn?, <<-PATTERN
|
85
|
+
(match_with_lvasgn !nil !nil)
|
86
|
+
PATTERN
|
87
|
+
|
88
|
+
MATCH_NODE_PATTERN = <<-PATTERN.freeze
|
89
|
+
{
|
90
|
+
#match_method?
|
91
|
+
#match_operator?
|
92
|
+
#match_threequals?
|
93
|
+
#match_with_lvasgn?
|
94
|
+
}
|
95
|
+
PATTERN
|
96
|
+
|
97
|
+
def_node_matcher :match_node?, MATCH_NODE_PATTERN
|
98
|
+
def_node_search :search_match_nodes, MATCH_NODE_PATTERN
|
99
|
+
|
100
|
+
def_node_search :last_matches, <<-PATTERN
|
101
|
+
{
|
102
|
+
(send (const nil :Regexp) :last_match)
|
103
|
+
(send (const nil :Regexp) :last_match _)
|
104
|
+
({back_ref nth_ref} _)
|
105
|
+
(gvar #dollar_tilde)
|
106
|
+
}
|
107
|
+
PATTERN
|
108
|
+
|
109
|
+
def on_if(node)
|
110
|
+
check_condition(node.condition)
|
111
|
+
end
|
112
|
+
|
113
|
+
def on_case(node)
|
114
|
+
return if node.condition
|
115
|
+
|
116
|
+
node.each_when do |when_node|
|
117
|
+
when_node.each_condition do |condition|
|
118
|
+
check_condition(condition)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def autocorrect(node)
|
124
|
+
lambda do |corrector|
|
125
|
+
if match_method?(node)
|
126
|
+
corrector.replace(node.loc.selector, 'match?')
|
127
|
+
elsif match_operator?(node) || match_threequals?(node)
|
128
|
+
recv, _, arg = *node
|
129
|
+
correct_operator(corrector, recv, arg)
|
130
|
+
elsif match_with_lvasgn?(node)
|
131
|
+
recv, arg = *node
|
132
|
+
correct_operator(corrector, recv, arg)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def check_condition(cond)
|
140
|
+
match_node?(cond) do
|
141
|
+
return if last_match_used?(cond)
|
142
|
+
add_offense(cond, :expression,
|
143
|
+
format(MSG, cond.loc.selector.source))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def last_match_used?(match_node)
|
148
|
+
scope_root = scope_root(match_node)
|
149
|
+
body = scope_root ? scope_body(scope_root) : match_node.ancestors.last
|
150
|
+
match_node_pos = match_node.loc.expression.begin_pos
|
151
|
+
|
152
|
+
next_match_pos = next_match_pos(body, match_node_pos, scope_root)
|
153
|
+
range = match_node_pos..next_match_pos
|
154
|
+
|
155
|
+
find_last_match(body, range, scope_root)
|
156
|
+
end
|
157
|
+
|
158
|
+
def next_match_pos(body, match_node_pos, scope_root)
|
159
|
+
node = search_match_nodes(body).find do |match|
|
160
|
+
match.loc.expression.begin_pos > match_node_pos &&
|
161
|
+
scope_root(match) == scope_root
|
162
|
+
end
|
163
|
+
node ? node.loc.expression.begin_pos : Float::INFINITY
|
164
|
+
end
|
165
|
+
|
166
|
+
def find_last_match(body, range, scope_root)
|
167
|
+
last_matches(body).find do |ref|
|
168
|
+
ref_pos = ref.loc.expression.begin_pos
|
169
|
+
range.cover?(ref_pos) &&
|
170
|
+
scope_root(ref) == scope_root
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def scope_body(node)
|
175
|
+
node.children[2]
|
176
|
+
end
|
177
|
+
|
178
|
+
def scope_root(node)
|
179
|
+
node.each_ancestor.find do |ancestor|
|
180
|
+
ancestor.def_type? ||
|
181
|
+
ancestor.class_type? ||
|
182
|
+
ancestor.module_type?
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def dollar_tilde(sym)
|
187
|
+
sym == :$~
|
188
|
+
end
|
189
|
+
|
190
|
+
def correct_operator(corrector, recv, arg)
|
191
|
+
buffer = processed_source.buffer
|
192
|
+
op_begin_pos = recv.loc.expression.end_pos
|
193
|
+
op_end_pos = arg.loc.expression.begin_pos
|
194
|
+
op_range = Parser::Source::Range.new(buffer, op_begin_pos, op_end_pos)
|
195
|
+
corrector.replace(op_range, '.match?(')
|
196
|
+
corrector.insert_after(arg.loc.expression, ')')
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|