rubocop 0.76.0 → 0.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/config/default.yml +290 -264
- data/lib/rubocop/ast/builder.rb +43 -42
- data/lib/rubocop/ast/node/block_node.rb +2 -0
- data/lib/rubocop/ast/node/def_node.rb +11 -0
- data/lib/rubocop/ast/node/forward_args_node.rb +18 -0
- data/lib/rubocop/ast/node.rb +1 -1
- data/lib/rubocop/ast/traversal.rb +11 -3
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +105 -0
- data/lib/rubocop/cli/command/base.rb +33 -0
- data/lib/rubocop/cli/command/execute_runner.rb +76 -0
- data/lib/rubocop/cli/command/init_dotfile.rb +45 -0
- data/lib/rubocop/cli/command/show_cops.rb +80 -0
- data/lib/rubocop/cli/command/version.rb +17 -0
- data/lib/rubocop/cli/command.rb +21 -0
- data/lib/rubocop/cli/environment.rb +21 -0
- data/lib/rubocop/cli.rb +11 -230
- data/lib/rubocop/config.rb +1 -1
- data/lib/rubocop/config_loader.rb +19 -19
- data/lib/rubocop/config_obsoletion.rb +65 -12
- data/lib/rubocop/config_validator.rb +56 -98
- data/lib/rubocop/cop/autocorrect_logic.rb +7 -4
- data/lib/rubocop/cop/bundler/gem_comment.rb +4 -4
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +2 -2
- data/lib/rubocop/cop/cop.rb +21 -0
- data/lib/rubocop/cop/correctors/space_corrector.rb +1 -2
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
- data/lib/rubocop/cop/generator.rb +3 -4
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +59 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/{align_arguments.rb → argument_alignment.rb} +1 -1
- data/lib/rubocop/cop/layout/{align_array.rb → array_alignment.rb} +1 -1
- data/lib/rubocop/cop/layout/{indent_assignment.rb → assignment_indentation.rb} +1 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/{indent_first_argument.rb → first_argument_indentation.rb} +5 -5
- data/lib/rubocop/cop/layout/{indent_first_array_element.rb → first_array_element_indentation.rb} +4 -4
- data/lib/rubocop/cop/layout/{indent_first_hash_element.rb → first_hash_element_indentation.rb} +3 -3
- data/lib/rubocop/cop/layout/{indent_first_parameter.rb → first_parameter_indentation.rb} +3 -3
- data/lib/rubocop/cop/layout/{align_hash.rb → hash_alignment.rb} +10 -6
- data/lib/rubocop/cop/layout/{indent_heredoc.rb → heredoc_indentation.rb} +5 -5
- data/lib/rubocop/cop/layout/{leading_blank_lines.rb → leading_empty_lines.rb} +1 -1
- data/lib/rubocop/cop/{metrics → layout}/line_length.rb +40 -110
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +14 -5
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/{align_parameters.rb → parameter_alignment.rb} +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +12 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +32 -7
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +17 -0
- data/lib/rubocop/cop/layout/{trailing_blank_lines.rb → trailing_empty_lines.rb} +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +2 -2
- data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +1 -1
- data/lib/rubocop/cop/lint/{duplicated_key.rb → duplicate_hash_key.rb} +1 -1
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
- data/lib/rubocop/cop/lint/{multiple_compare.rb → multiple_comparison.rb} +1 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +89 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -3
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +4 -4
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
- data/lib/rubocop/cop/lint/{string_conversion_in_interpolation.rb → redundant_string_coercion.rb} +1 -1
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/{handle_exceptions.rb → suppressed_exception.rb} +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +57 -23
- data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +16 -1
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -7
- data/lib/rubocop/cop/mixin/{hash_alignment.rb → hash_alignment_styles.rb} +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +88 -0
- data/lib/rubocop/cop/mixin/nil_methods.rb +4 -4
- data/lib/rubocop/cop/mixin/rational_literal.rb +18 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +6 -3
- data/lib/rubocop/cop/naming/{uncommunicative_block_param_name.rb → block_parameter_name.rb} +3 -3
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -5
- data/lib/rubocop/cop/naming/{uncommunicative_method_param_name.rb → method_parameter_name.rb} +4 -4
- data/lib/rubocop/cop/naming/predicate_name.rb +6 -6
- data/lib/rubocop/cop/offense.rb +11 -0
- data/lib/rubocop/cop/registry.rb +7 -2
- data/lib/rubocop/cop/style/alias.rb +1 -1
- data/lib/rubocop/cop/style/array_join.rb +1 -1
- data/lib/rubocop/cop/style/attr.rb +8 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/even_odd.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +3 -2
- data/lib/rubocop/cop/style/if_unless_modifier.rb +38 -3
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/ip_addresses.rb +4 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +168 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +54 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +4 -207
- data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +5 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +5 -5
- data/lib/rubocop/cop/style/next.rb +5 -5
- data/lib/rubocop/cop/style/numeric_literals.rb +7 -3
- data/lib/rubocop/cop/style/numeric_predicate.rb +4 -3
- data/lib/rubocop/cop/style/option_hash.rb +3 -3
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +7 -7
- data/lib/rubocop/cop/style/redundant_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/redundant_return.rb +2 -8
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +7 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +5 -5
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +16 -1
- data/lib/rubocop/cop/team.rb +5 -0
- data/lib/rubocop/formatter/base_formatter.rb +2 -2
- data/lib/rubocop/formatter/clang_style_formatter.rb +1 -3
- data/lib/rubocop/formatter/json_formatter.rb +6 -5
- data/lib/rubocop/formatter/tap_formatter.rb +1 -3
- data/lib/rubocop/node_pattern.rb +1 -1
- data/lib/rubocop/options.rb +8 -8
- data/lib/rubocop/processed_source.rb +1 -1
- data/lib/rubocop/rake_task.rb +1 -0
- data/lib/rubocop/result_cache.rb +23 -7
- data/lib/rubocop/rspec/shared_contexts.rb +5 -0
- data/lib/rubocop/runner.rb +18 -2
- data/lib/rubocop/target_ruby.rb +151 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +38 -22
- metadata +40 -25
- data/lib/rubocop/cop/mixin/safe_mode.rb +0 -24
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# This cop checks for uses of "
|
6
|
+
# This cop checks for uses of "\*" as a substitute for *join*.
|
7
7
|
#
|
8
8
|
# Not all cases can reliably checked, due to Ruby's dynamic
|
9
9
|
# types, so we consider only cases when the first argument is an
|
@@ -21,6 +21,10 @@ module RuboCop
|
|
21
21
|
|
22
22
|
def on_send(node)
|
23
23
|
return unless node.command?(:attr) && node.arguments?
|
24
|
+
# check only for method definitions in class/module body
|
25
|
+
return if node.parent &&
|
26
|
+
!node.parent.class_type? &&
|
27
|
+
!class_eval?(node.parent)
|
24
28
|
|
25
29
|
add_offense(node, location: :selector)
|
26
30
|
end
|
@@ -56,6 +60,10 @@ module RuboCop
|
|
56
60
|
'attr_reader'
|
57
61
|
end
|
58
62
|
end
|
63
|
+
|
64
|
+
def_node_matcher :class_eval?, <<~PATTERN
|
65
|
+
(block (send _ {:class_eval :module_eval}) ...)
|
66
|
+
PATTERN
|
59
67
|
end
|
60
68
|
end
|
61
69
|
end
|
@@ -212,7 +212,7 @@ module RuboCop
|
|
212
212
|
%i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
|
213
213
|
ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES +
|
214
214
|
%i[and_asgn or_asgn op_asgn masgn].freeze
|
215
|
-
LINE_LENGTH = '
|
215
|
+
LINE_LENGTH = 'Layout/LineLength'
|
216
216
|
INDENTATION_WIDTH = 'Layout/IndentationWidth'
|
217
217
|
ENABLED = 'Enabled'
|
218
218
|
MAX = 'Max'
|
@@ -376,7 +376,7 @@ module RuboCop
|
|
376
376
|
assignment_types_match?(*statements)
|
377
377
|
end
|
378
378
|
|
379
|
-
# If `
|
379
|
+
# If `Layout/LineLength` is enabled, we do not want to introduce an
|
380
380
|
# offense by auto-correcting this cop. Find the max configured line
|
381
381
|
# length. Find the longest line of condition. Remove the assignment
|
382
382
|
# from lines that contain the offending assignment because after
|
@@ -85,7 +85,7 @@ module RuboCop
|
|
85
85
|
# FIXME: It's a Style/ConditionalAssignment's false positive.
|
86
86
|
# rubocop:disable Style/ConditionalAssignment
|
87
87
|
def with_lineno?(node)
|
88
|
-
if node.
|
88
|
+
if node.method?(:eval)
|
89
89
|
node.arguments.size == 4
|
90
90
|
else
|
91
91
|
node.arguments.size == 3
|
@@ -49,8 +49,9 @@ module RuboCop
|
|
49
49
|
|
50
50
|
if body.if_type?
|
51
51
|
check_ending_if(body)
|
52
|
-
elsif body.begin_type?
|
53
|
-
|
52
|
+
elsif body.begin_type?
|
53
|
+
final_expression = body.children.last
|
54
|
+
check_ending_if(final_expression) if final_expression&.if_type?
|
54
55
|
end
|
55
56
|
end
|
56
57
|
alias on_defs on_def
|
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
# written as modifier `if`/`unless`. The cop also checks for modifier
|
8
8
|
# `if`/`unless` lines that exceed the maximum line length.
|
9
9
|
#
|
10
|
-
# The maximum line length is configured in the `
|
10
|
+
# The maximum line length is configured in the `Layout/LineLength`
|
11
11
|
# cop. The tab size is configured in the `IndentationWidth` of the
|
12
12
|
# `Layout/Tab` cop.
|
13
13
|
#
|
@@ -32,6 +32,8 @@ module RuboCop
|
|
32
32
|
# end
|
33
33
|
class IfUnlessModifier < Cop
|
34
34
|
include StatementModifier
|
35
|
+
include LineLengthHelp
|
36
|
+
include IgnoredPattern
|
35
37
|
|
36
38
|
MSG_USE_MODIFIER = 'Favor modifier `%<keyword>s` usage when having a ' \
|
37
39
|
'single-line body. Another good alternative is ' \
|
@@ -66,6 +68,10 @@ module RuboCop
|
|
66
68
|
|
67
69
|
private
|
68
70
|
|
71
|
+
def ignored_patterns
|
72
|
+
config.for_cop('Layout/LineLength')['IgnoredPatterns'] || []
|
73
|
+
end
|
74
|
+
|
69
75
|
def too_long_single_line?(node)
|
70
76
|
return false unless max_line_length
|
71
77
|
|
@@ -73,12 +79,41 @@ module RuboCop
|
|
73
79
|
return false unless range.first_line == range.last_line
|
74
80
|
return false unless line_length_enabled_at_line?(range.first_line)
|
75
81
|
|
76
|
-
range.
|
82
|
+
line = range.source_line
|
83
|
+
return false if line_length(line) <= max_line_length
|
84
|
+
|
85
|
+
too_long_line_based_on_config?(range, line)
|
86
|
+
end
|
87
|
+
|
88
|
+
def too_long_line_based_on_config?(range, line)
|
89
|
+
return false if matches_ignored_pattern?(line)
|
90
|
+
|
91
|
+
too_long = too_long_line_based_on_ignore_cop_directives?(range, line)
|
92
|
+
return too_long unless too_long == :undetermined
|
93
|
+
|
94
|
+
too_long_line_based_on_allow_uri?(line)
|
95
|
+
end
|
96
|
+
|
97
|
+
def too_long_line_based_on_ignore_cop_directives?(range, line)
|
98
|
+
if ignore_cop_directives? && directive_on_source_line?(range.line - 1)
|
99
|
+
return line_length_without_directive(line) > max_line_length
|
100
|
+
end
|
101
|
+
|
102
|
+
:undetermined
|
103
|
+
end
|
104
|
+
|
105
|
+
def too_long_line_based_on_allow_uri?(line)
|
106
|
+
if allow_uri?
|
107
|
+
uri_range = find_excessive_uri_range(line)
|
108
|
+
return false if uri_range && allowed_uri_position?(line, uri_range)
|
109
|
+
end
|
110
|
+
|
111
|
+
true
|
77
112
|
end
|
78
113
|
|
79
114
|
def line_length_enabled_at_line?(line)
|
80
115
|
processed_source.comment_config
|
81
|
-
.cop_enabled_at_line?('
|
116
|
+
.cop_enabled_at_line?('Layout/LineLength', line)
|
82
117
|
end
|
83
118
|
|
84
119
|
def named_capture_in_condition?(node)
|
@@ -58,7 +58,7 @@ module RuboCop
|
|
58
58
|
# `loop do` without further modification. The reason is that a
|
59
59
|
# variable that's introduced inside a while/until loop is in scope
|
60
60
|
# outside of that loop too, but a variable that's assigned for the
|
61
|
-
# first time inside a block
|
61
|
+
# first time inside a block cannot be accessed after the block. In
|
62
62
|
# those more complicated cases we don't report an offense.
|
63
63
|
return if @variables.any? do |var|
|
64
64
|
assigned_inside_loop?(var, range) &&
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
contents = node.source[1...-1]
|
29
29
|
return false if contents.empty?
|
30
30
|
|
31
|
-
return false if
|
31
|
+
return false if allowed_addresses.include?(contents.downcase)
|
32
32
|
|
33
33
|
# To try to avoid doing two regex checks on every string,
|
34
34
|
# shortcut out if the string does not look like an IP address
|
@@ -47,9 +47,9 @@ module RuboCop
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
def
|
51
|
-
|
52
|
-
Array(
|
50
|
+
def allowed_addresses
|
51
|
+
allowed_addresses = cop_config['AllowedAddresses']
|
52
|
+
Array(allowed_addresses).map(&:downcase)
|
53
53
|
end
|
54
54
|
|
55
55
|
def could_be_ip?(str)
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
class MethodCallWithArgsParentheses
|
7
|
+
# Style omit_parentheses
|
8
|
+
module OmitParentheses
|
9
|
+
TRAILING_WHITESPACE_REGEX = /\s+\Z/.freeze
|
10
|
+
|
11
|
+
def on_send(node)
|
12
|
+
return unless node.parenthesized?
|
13
|
+
return if node.implicit_call?
|
14
|
+
return if super_call_without_arguments?(node)
|
15
|
+
return if allowed_camel_case_method_call?(node)
|
16
|
+
return if legitimate_call_with_parentheses?(node)
|
17
|
+
|
18
|
+
add_offense(node, location: node.loc.begin.join(node.loc.end))
|
19
|
+
end
|
20
|
+
alias on_csend on_send
|
21
|
+
alias on_super on_send
|
22
|
+
alias on_yield on_send
|
23
|
+
|
24
|
+
def autocorrect(node)
|
25
|
+
lambda do |corrector|
|
26
|
+
if parentheses_at_the_end_of_multiline_call?(node)
|
27
|
+
corrector.replace(args_begin(node), ' \\')
|
28
|
+
else
|
29
|
+
corrector.replace(args_begin(node), ' ')
|
30
|
+
end
|
31
|
+
corrector.remove(node.loc.end)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def message(_node = nil)
|
36
|
+
'Omit parentheses for method calls with arguments.'
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def super_call_without_arguments?(node)
|
42
|
+
node.super_type? && node.arguments.none?
|
43
|
+
end
|
44
|
+
|
45
|
+
def allowed_camel_case_method_call?(node)
|
46
|
+
node.camel_case_method? &&
|
47
|
+
(node.arguments.none? ||
|
48
|
+
cop_config['AllowParenthesesInCamelCaseMethod'])
|
49
|
+
end
|
50
|
+
|
51
|
+
def parentheses_at_the_end_of_multiline_call?(node)
|
52
|
+
node.multiline? &&
|
53
|
+
node.loc.begin.source_line
|
54
|
+
.gsub(TRAILING_WHITESPACE_REGEX, '')
|
55
|
+
.end_with?('(')
|
56
|
+
end
|
57
|
+
|
58
|
+
def legitimate_call_with_parentheses?(node)
|
59
|
+
call_in_literals?(node) ||
|
60
|
+
call_with_ambiguous_arguments?(node) ||
|
61
|
+
call_in_logical_operators?(node) ||
|
62
|
+
call_in_optional_arguments?(node) ||
|
63
|
+
allowed_multiline_call_with_parentheses?(node) ||
|
64
|
+
allowed_chained_call_with_parentheses?(node)
|
65
|
+
end
|
66
|
+
|
67
|
+
def call_in_literals?(node)
|
68
|
+
node.parent &&
|
69
|
+
(node.parent.pair_type? ||
|
70
|
+
node.parent.array_type? ||
|
71
|
+
node.parent.range_type? ||
|
72
|
+
splat?(node.parent) ||
|
73
|
+
ternary_if?(node.parent))
|
74
|
+
end
|
75
|
+
|
76
|
+
def call_in_logical_operators?(node)
|
77
|
+
node.parent &&
|
78
|
+
(logical_operator?(node.parent) ||
|
79
|
+
node.parent.send_type? &&
|
80
|
+
node.parent.arguments.any?(&method(:logical_operator?)))
|
81
|
+
end
|
82
|
+
|
83
|
+
def call_in_optional_arguments?(node)
|
84
|
+
node.parent &&
|
85
|
+
(node.parent.optarg_type? || node.parent.kwoptarg_type?)
|
86
|
+
end
|
87
|
+
|
88
|
+
def call_with_ambiguous_arguments?(node)
|
89
|
+
call_with_braced_block?(node) ||
|
90
|
+
call_as_argument_or_chain?(node) ||
|
91
|
+
hash_literal_in_arguments?(node) ||
|
92
|
+
node.descendants.any? do |n|
|
93
|
+
ambigious_literal?(n) || logical_operator?(n) ||
|
94
|
+
call_with_braced_block?(n)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def call_with_braced_block?(node)
|
99
|
+
(node.send_type? || node.super_type?) &&
|
100
|
+
node.block_node && node.block_node.braces?
|
101
|
+
end
|
102
|
+
|
103
|
+
def call_as_argument_or_chain?(node)
|
104
|
+
node.parent &&
|
105
|
+
(node.parent.send_type? && !assigned_before?(node.parent, node) ||
|
106
|
+
node.parent.csend_type? || node.parent.super_type?)
|
107
|
+
end
|
108
|
+
|
109
|
+
def hash_literal_in_arguments?(node)
|
110
|
+
node.arguments.any? do |n|
|
111
|
+
hash_literal?(n) ||
|
112
|
+
n.send_type? && node.descendants.any?(&method(:hash_literal?))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def allowed_multiline_call_with_parentheses?(node)
|
117
|
+
cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
|
118
|
+
end
|
119
|
+
|
120
|
+
def allowed_chained_call_with_parentheses?(node)
|
121
|
+
return false unless cop_config['AllowParenthesesInChaining']
|
122
|
+
|
123
|
+
previous = node.descendants.first
|
124
|
+
return false unless previous&.send_type?
|
125
|
+
|
126
|
+
previous.parenthesized? ||
|
127
|
+
allowed_chained_call_with_parentheses?(previous)
|
128
|
+
end
|
129
|
+
|
130
|
+
def ambigious_literal?(node)
|
131
|
+
splat?(node) || ternary_if?(node) || regexp_slash_literal?(node) ||
|
132
|
+
unary_literal?(node)
|
133
|
+
end
|
134
|
+
|
135
|
+
def splat?(node)
|
136
|
+
node.splat_type? || node.kwsplat_type? || node.block_pass_type?
|
137
|
+
end
|
138
|
+
|
139
|
+
def ternary_if?(node)
|
140
|
+
node.if_type? && node.ternary?
|
141
|
+
end
|
142
|
+
|
143
|
+
def logical_operator?(node)
|
144
|
+
(node.and_type? || node.or_type?) && node.logical_operator?
|
145
|
+
end
|
146
|
+
|
147
|
+
def hash_literal?(node)
|
148
|
+
node.hash_type? && node.braces?
|
149
|
+
end
|
150
|
+
|
151
|
+
def regexp_slash_literal?(node)
|
152
|
+
node.regexp_type? && node.loc.begin.source == '/'
|
153
|
+
end
|
154
|
+
|
155
|
+
def unary_literal?(node)
|
156
|
+
node.numeric_type? && node.sign? ||
|
157
|
+
node.parent&.send_type? && node.parent&.unary_operation?
|
158
|
+
end
|
159
|
+
|
160
|
+
def assigned_before?(node, target)
|
161
|
+
node.assignment? &&
|
162
|
+
node.loc.operator.begin < target.loc.begin
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
class MethodCallWithArgsParentheses
|
7
|
+
# Style require_parentheses
|
8
|
+
module RequireParentheses
|
9
|
+
def on_send(node)
|
10
|
+
return if ignored_method?(node.method_name)
|
11
|
+
return if matches_ignored_pattern?(node.method_name)
|
12
|
+
return if eligible_for_parentheses_omission?(node)
|
13
|
+
return unless node.arguments? && !node.parenthesized?
|
14
|
+
|
15
|
+
add_offense(node)
|
16
|
+
end
|
17
|
+
alias on_csend on_send
|
18
|
+
alias on_super on_send
|
19
|
+
alias on_yield on_send
|
20
|
+
|
21
|
+
def autocorrect(node)
|
22
|
+
lambda do |corrector|
|
23
|
+
corrector.replace(args_begin(node), '(')
|
24
|
+
|
25
|
+
unless args_parenthesized?(node)
|
26
|
+
corrector.insert_after(args_end(node), ')')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def message(_node = nil)
|
32
|
+
'Use parentheses for method calls with arguments.'
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def eligible_for_parentheses_omission?(node)
|
38
|
+
node.operator_method? || node.setter_method? || ignored_macro?(node)
|
39
|
+
end
|
40
|
+
|
41
|
+
def included_macros_list
|
42
|
+
cop_config.fetch('IncludedMacros', []).map(&:to_sym)
|
43
|
+
end
|
44
|
+
|
45
|
+
def ignored_macro?(node)
|
46
|
+
cop_config['IgnoreMacros'] &&
|
47
|
+
node.macro? &&
|
48
|
+
!included_macros_list.include?(node.method_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# rubocop:disable Metrics/ClassLength
|
4
3
|
module RuboCop
|
5
4
|
module Cop
|
6
5
|
module Style
|
@@ -43,7 +42,6 @@ module RuboCop
|
|
43
42
|
#
|
44
43
|
# @example EnforcedStyle: require_parentheses (default)
|
45
44
|
#
|
46
|
-
#
|
47
45
|
# # bad
|
48
46
|
# array.delete e
|
49
47
|
#
|
@@ -150,94 +148,18 @@ module RuboCop
|
|
150
148
|
include IgnoredMethods
|
151
149
|
include IgnoredPattern
|
152
150
|
|
153
|
-
|
154
|
-
|
155
|
-
def on_send(node)
|
156
|
-
case style
|
157
|
-
when :require_parentheses
|
158
|
-
add_offense_for_require_parentheses(node)
|
159
|
-
when :omit_parentheses
|
160
|
-
add_offense_for_omit_parentheses(node)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
alias on_csend on_send
|
164
|
-
alias on_super on_send
|
165
|
-
alias on_yield on_send
|
166
|
-
|
167
|
-
def autocorrect(node)
|
168
|
-
case style
|
169
|
-
when :require_parentheses
|
170
|
-
autocorrect_for_require_parentheses(node)
|
171
|
-
when :omit_parentheses
|
172
|
-
autocorrect_for_omit_parentheses(node)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def message(_node = nil)
|
151
|
+
def initialize(*)
|
152
|
+
super
|
177
153
|
case style
|
178
154
|
when :require_parentheses
|
179
|
-
|
155
|
+
extend RequireParentheses
|
180
156
|
when :omit_parentheses
|
181
|
-
|
157
|
+
extend OmitParentheses
|
182
158
|
end
|
183
159
|
end
|
184
160
|
|
185
161
|
private
|
186
162
|
|
187
|
-
def add_offense_for_require_parentheses(node)
|
188
|
-
return if ignored_method?(node.method_name)
|
189
|
-
return if matches_ignored_pattern?(node.method_name)
|
190
|
-
return if eligible_for_parentheses_omission?(node)
|
191
|
-
return unless node.arguments? && !node.parenthesized?
|
192
|
-
|
193
|
-
add_offense(node)
|
194
|
-
end
|
195
|
-
|
196
|
-
def add_offense_for_omit_parentheses(node)
|
197
|
-
return unless node.parenthesized?
|
198
|
-
return if node.implicit_call?
|
199
|
-
return if super_call_without_arguments?(node)
|
200
|
-
return if allowed_camel_case_method_call?(node)
|
201
|
-
return if legitimate_call_with_parentheses?(node)
|
202
|
-
|
203
|
-
add_offense(node, location: node.loc.begin.join(node.loc.end))
|
204
|
-
end
|
205
|
-
|
206
|
-
def autocorrect_for_require_parentheses(node)
|
207
|
-
lambda do |corrector|
|
208
|
-
corrector.replace(args_begin(node), '(')
|
209
|
-
|
210
|
-
unless args_parenthesized?(node)
|
211
|
-
corrector.insert_after(args_end(node), ')')
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def autocorrect_for_omit_parentheses(node)
|
217
|
-
lambda do |corrector|
|
218
|
-
if parentheses_at_the_end_of_multiline_call?(node)
|
219
|
-
corrector.replace(args_begin(node), ' \\')
|
220
|
-
else
|
221
|
-
corrector.replace(args_begin(node), ' ')
|
222
|
-
end
|
223
|
-
corrector.remove(node.loc.end)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def eligible_for_parentheses_omission?(node)
|
228
|
-
node.operator_method? || node.setter_method? || ignored_macro?(node)
|
229
|
-
end
|
230
|
-
|
231
|
-
def included_macros_list
|
232
|
-
cop_config.fetch('IncludedMacros', []).map(&:to_sym)
|
233
|
-
end
|
234
|
-
|
235
|
-
def ignored_macro?(node)
|
236
|
-
cop_config['IgnoreMacros'] &&
|
237
|
-
node.macro? &&
|
238
|
-
!included_macros_list.include?(node.method_name)
|
239
|
-
end
|
240
|
-
|
241
163
|
def args_begin(node)
|
242
164
|
loc = node.loc
|
243
165
|
selector =
|
@@ -257,132 +179,7 @@ module RuboCop
|
|
257
179
|
first_node = node.arguments.first
|
258
180
|
first_node.begin_type? && first_node.parenthesized_call?
|
259
181
|
end
|
260
|
-
|
261
|
-
def parentheses_at_the_end_of_multiline_call?(node)
|
262
|
-
node.multiline? &&
|
263
|
-
node.loc.begin.source_line
|
264
|
-
.gsub(TRAILING_WHITESPACE_REGEX, '')
|
265
|
-
.end_with?('(')
|
266
|
-
end
|
267
|
-
|
268
|
-
def super_call_without_arguments?(node)
|
269
|
-
node.super_type? && node.arguments.none?
|
270
|
-
end
|
271
|
-
|
272
|
-
def allowed_camel_case_method_call?(node)
|
273
|
-
node.camel_case_method? &&
|
274
|
-
(node.arguments.none? ||
|
275
|
-
cop_config['AllowParenthesesInCamelCaseMethod'])
|
276
|
-
end
|
277
|
-
|
278
|
-
def legitimate_call_with_parentheses?(node)
|
279
|
-
call_in_literals?(node) ||
|
280
|
-
call_with_ambiguous_arguments?(node) ||
|
281
|
-
call_in_logical_operators?(node) ||
|
282
|
-
call_in_optional_arguments?(node) ||
|
283
|
-
allowed_multiline_call_with_parentheses?(node) ||
|
284
|
-
allowed_chained_call_with_parentheses?(node)
|
285
|
-
end
|
286
|
-
|
287
|
-
def call_in_literals?(node)
|
288
|
-
node.parent &&
|
289
|
-
(node.parent.pair_type? ||
|
290
|
-
node.parent.array_type? ||
|
291
|
-
node.parent.range_type? ||
|
292
|
-
splat?(node.parent) ||
|
293
|
-
ternary_if?(node.parent))
|
294
|
-
end
|
295
|
-
|
296
|
-
def call_in_logical_operators?(node)
|
297
|
-
node.parent &&
|
298
|
-
(logical_operator?(node.parent) ||
|
299
|
-
node.parent.send_type? &&
|
300
|
-
node.parent.arguments.any?(&method(:logical_operator?)))
|
301
|
-
end
|
302
|
-
|
303
|
-
def call_in_optional_arguments?(node)
|
304
|
-
node.parent &&
|
305
|
-
(node.parent.optarg_type? || node.parent.kwoptarg_type?)
|
306
|
-
end
|
307
|
-
|
308
|
-
def call_with_ambiguous_arguments?(node)
|
309
|
-
call_with_braced_block?(node) ||
|
310
|
-
call_as_argument_or_chain?(node) ||
|
311
|
-
hash_literal_in_arguments?(node) ||
|
312
|
-
node.descendants.any? do |n|
|
313
|
-
ambigious_literal?(n) || logical_operator?(n) ||
|
314
|
-
call_with_braced_block?(n)
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
def call_with_braced_block?(node)
|
319
|
-
(node.send_type? || node.super_type?) &&
|
320
|
-
node.block_node && node.block_node.braces?
|
321
|
-
end
|
322
|
-
|
323
|
-
def call_as_argument_or_chain?(node)
|
324
|
-
node.parent &&
|
325
|
-
(node.parent.send_type? && !assigned_before?(node.parent, node) ||
|
326
|
-
node.parent.csend_type? || node.parent.super_type?)
|
327
|
-
end
|
328
|
-
|
329
|
-
def hash_literal_in_arguments?(node)
|
330
|
-
node.arguments.any? do |n|
|
331
|
-
hash_literal?(n) ||
|
332
|
-
n.send_type? && node.descendants.any?(&method(:hash_literal?))
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
def allowed_multiline_call_with_parentheses?(node)
|
337
|
-
cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
|
338
|
-
end
|
339
|
-
|
340
|
-
def allowed_chained_call_with_parentheses?(node)
|
341
|
-
return false unless cop_config['AllowParenthesesInChaining']
|
342
|
-
|
343
|
-
previous = node.descendants.first
|
344
|
-
return false unless previous&.send_type?
|
345
|
-
|
346
|
-
previous.parenthesized? ||
|
347
|
-
allowed_chained_call_with_parentheses?(previous)
|
348
|
-
end
|
349
|
-
|
350
|
-
def ambigious_literal?(node)
|
351
|
-
splat?(node) || ternary_if?(node) || regexp_slash_literal?(node) ||
|
352
|
-
unary_literal?(node)
|
353
|
-
end
|
354
|
-
|
355
|
-
def splat?(node)
|
356
|
-
node.splat_type? || node.kwsplat_type? || node.block_pass_type?
|
357
|
-
end
|
358
|
-
|
359
|
-
def ternary_if?(node)
|
360
|
-
node.if_type? && node.ternary?
|
361
|
-
end
|
362
|
-
|
363
|
-
def logical_operator?(node)
|
364
|
-
(node.and_type? || node.or_type?) && node.logical_operator?
|
365
|
-
end
|
366
|
-
|
367
|
-
def hash_literal?(node)
|
368
|
-
node.hash_type? && node.braces?
|
369
|
-
end
|
370
|
-
|
371
|
-
def regexp_slash_literal?(node)
|
372
|
-
node.regexp_type? && node.loc.begin.source == '/'
|
373
|
-
end
|
374
|
-
|
375
|
-
def unary_literal?(node)
|
376
|
-
node.numeric_type? && node.sign? ||
|
377
|
-
node.parent&.send_type? && node.parent&.unary_operation?
|
378
|
-
end
|
379
|
-
|
380
|
-
def assigned_before?(node, target)
|
381
|
-
node.assignment? &&
|
382
|
-
node.loc.operator.begin < target.loc.begin
|
383
|
-
end
|
384
182
|
end
|
385
183
|
end
|
386
184
|
end
|
387
185
|
end
|
388
|
-
# rubocop:enable Metrics/ClassLength
|