rubocop 1.87.0 → 1.88.2
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/config/default.yml +80 -72
- data/config/obsoletion.yml +21 -1
- data/lib/rubocop/cli/command/auto_generate_config.rb +6 -0
- data/lib/rubocop/cop/base.rb +30 -10
- data/lib/rubocop/cop/bundler/gem_comment.rb +5 -3
- data/lib/rubocop/cop/commissioner.rb +13 -11
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -1
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +12 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -1
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
- data/lib/rubocop/cop/layout/block_alignment.rb +58 -4
- data/lib/rubocop/cop/layout/class_structure.rb +7 -3
- data/lib/rubocop/cop/layout/comment_indentation.rb +9 -2
- data/lib/rubocop/cop/layout/condition_position.rb +13 -3
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -14
- data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +14 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +13 -14
- data/lib/rubocop/cop/layout/indentation_width.rb +28 -0
- data/lib/rubocop/cop/layout/line_length.rb +10 -5
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +6 -2
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +1 -11
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +1 -10
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +13 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +1 -3
- data/lib/rubocop/cop/lint/debugger.rb +13 -2
- data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -7
- data/lib/rubocop/cop/lint/empty_block.rb +3 -3
- data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -0
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +18 -3
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +8 -11
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +4 -4
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +16 -0
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +13 -4
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +10 -0
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
- data/lib/rubocop/cop/lint/raise_exception.rb +1 -1
- data/lib/rubocop/cop/lint/rand_one.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +4 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +4 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +15 -4
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +14 -7
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +7 -0
- data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_with_object.rb +5 -0
- data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
- data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +2 -1
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +5 -5
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -0
- data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
- data/lib/rubocop/cop/lint/script_permission.rb +5 -1
- data/lib/rubocop/cop/lint/self_assignment.rb +24 -1
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +14 -0
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -1
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +12 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +21 -4
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +35 -2
- data/lib/rubocop/cop/lint/to_json.rb +8 -1
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +4 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +35 -9
- data/lib/rubocop/cop/lint/unreachable_code.rb +9 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +10 -5
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +10 -10
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +7 -3
- data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -1
- data/lib/rubocop/cop/lint/useless_times.rb +22 -1
- data/lib/rubocop/cop/lint/void.rb +2 -2
- data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +38 -7
- data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/hash_subset.rb +8 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +4 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +4 -3
- data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +9 -0
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +9 -3
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/security/marshal_load.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +11 -1
- data/lib/rubocop/cop/style/alias.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -1
- data/lib/rubocop/cop/style/array_first_last.rb +12 -1
- data/lib/rubocop/cop/style/array_intersect.rb +8 -4
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +3 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +16 -2
- data/lib/rubocop/cop/style/case_equality.rb +14 -2
- data/lib/rubocop/cop/style/class_equality_comparison.rb +21 -13
- data/lib/rubocop/cop/style/class_methods_definitions.rb +11 -5
- data/lib/rubocop/cop/style/collection_compact.rb +1 -1
- data/lib/rubocop/cop/style/colon_method_call.rb +13 -6
- data/lib/rubocop/cop/style/combinable_loops.rb +5 -0
- data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +5 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +6 -1
- data/lib/rubocop/cop/style/constant_visibility.rb +4 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +4 -0
- data/lib/rubocop/cop/style/date_time.rb +2 -2
- data/lib/rubocop/cop/style/def_with_parentheses.rb +6 -2
- data/lib/rubocop/cop/style/dig_chain.rb +5 -0
- data/lib/rubocop/cop/style/dir_empty.rb +4 -0
- data/lib/rubocop/cop/style/documentation_method.rb +5 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +12 -2
- data/lib/rubocop/cop/style/empty_class_definition.rb +8 -1
- data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
- data/lib/rubocop/cop/style/empty_literal.rb +7 -2
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +30 -20
- data/lib/rubocop/cop/style/env_home.rb +4 -0
- data/lib/rubocop/cop/style/even_odd.rb +11 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -1
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- data/lib/rubocop/cop/style/file_null.rb +4 -2
- data/lib/rubocop/cop/style/file_write.rb +17 -14
- data/lib/rubocop/cop/style/format_string.rb +13 -1
- data/lib/rubocop/cop/style/hash_conversion.rb +14 -6
- data/lib/rubocop/cop/style/hash_lookup_method.rb +2 -6
- data/lib/rubocop/cop/style/hash_slice.rb +16 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +2 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -4
- data/lib/rubocop/cop/style/if_unless_modifier.rb +5 -5
- data/lib/rubocop/cop/style/if_with_semicolon.rb +9 -1
- data/lib/rubocop/cop/style/inline_comment.rb +1 -1
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +25 -5
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +7 -3
- data/lib/rubocop/cop/style/lambda.rb +7 -1
- data/lib/rubocop/cop/style/lambda_call.rb +11 -0
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
- data/lib/rubocop/cop/style/map_into_array.rb +1 -1
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -5
- data/lib/rubocop/cop/style/method_def_parentheses.rb +5 -1
- data/lib/rubocop/cop/style/min_max_comparison.rb +3 -0
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +10 -7
- data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
- data/lib/rubocop/cop/style/module_function.rb +4 -2
- data/lib/rubocop/cop/style/multiline_if_then.rb +1 -1
- data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +11 -4
- data/lib/rubocop/cop/style/mutable_constant.rb +105 -11
- data/lib/rubocop/cop/style/nil_lambda.rb +8 -0
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/option_hash.rb +1 -1
- data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +19 -3
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
- data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +13 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +6 -0
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +29 -0
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +11 -3
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -4
- data/lib/rubocop/cop/style/redundant_self.rb +9 -0
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +23 -4
- data/lib/rubocop/cop/style/semicolon.rb +20 -5
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +17 -4
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +3 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +11 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +7 -8
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/while_until_do.rb +7 -0
- data/lib/rubocop/cop/style/word_array.rb +1 -0
- data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
- data/lib/rubocop/cop/team.rb +18 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +14 -7
- data/lib/rubocop/runner.rb +55 -13
- data/lib/rubocop/server/core.rb +6 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +3 -3
|
@@ -96,13 +96,25 @@ module RuboCop
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
def const_replacement(lhs, rhs)
|
|
99
|
-
"#{rhs
|
|
99
|
+
"#{parenthesize_if_needed(rhs)}.is_a?(#{lhs.source})"
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
def send_replacement(lhs, rhs)
|
|
103
103
|
return unless self_class?(lhs)
|
|
104
104
|
|
|
105
|
-
"#{rhs
|
|
105
|
+
"#{parenthesize_if_needed(rhs)}.is_a?(#{lhs.source})"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# `Array === a + b` must become `(a + b).is_a?(Array)`, not
|
|
109
|
+
# `a + b.is_a?(Array)` (which parses as `a + (b.is_a?(Array))`).
|
|
110
|
+
def parenthesize_if_needed(node)
|
|
111
|
+
requires_parentheses?(node) ? "(#{node.source})" : node.source
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def requires_parentheses?(node)
|
|
115
|
+
return true if node.type?(:and, :or, :if, :range) || node.assignment?
|
|
116
|
+
|
|
117
|
+
node.send_type? && (node.operator_method? || node.unary_operation?)
|
|
106
118
|
end
|
|
107
119
|
end
|
|
108
120
|
end
|
|
@@ -90,25 +90,33 @@ module RuboCop
|
|
|
90
90
|
private
|
|
91
91
|
|
|
92
92
|
def class_name(class_node, node)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
unless class_name_method?(node.children.first.method_name)
|
|
94
|
+
# `var.class == 'Foo'` compares a `Class` to a `String` (always false) and
|
|
95
|
+
# has no valid `instance_of?` rewrite, so don't suggest one.
|
|
96
|
+
return if class_node.str_type?
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# When a variable or return value of a method is used, it returns nil
|
|
104
|
-
# because the type is not known and cannot be suggested.
|
|
105
|
-
return
|
|
106
|
-
end
|
|
98
|
+
return class_node.source
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if (receiver = class_node.receiver) && class_name_method?(class_node.method_name)
|
|
102
|
+
return receiver.source
|
|
107
103
|
end
|
|
108
104
|
|
|
105
|
+
return string_class_name(class_node) if class_node.str_type?
|
|
106
|
+
# When a variable or return value of a method is used, the type is not known
|
|
107
|
+
# and cannot be suggested.
|
|
108
|
+
return if unable_to_determine_type?(class_node)
|
|
109
|
+
|
|
109
110
|
class_node.source
|
|
110
111
|
end
|
|
111
112
|
|
|
113
|
+
def string_class_name(class_node)
|
|
114
|
+
value = trim_string_quotes(class_node)
|
|
115
|
+
# Avoid `::::Foo` when the name is already fully qualified.
|
|
116
|
+
value.prepend('::') if require_cbase?(class_node) && !value.start_with?('::')
|
|
117
|
+
value
|
|
118
|
+
end
|
|
119
|
+
|
|
112
120
|
def class_name_method?(method_name)
|
|
113
121
|
CLASS_NAME_METHODS.include?(method_name)
|
|
114
122
|
end
|
|
@@ -140,15 +140,21 @@ module RuboCop
|
|
|
140
140
|
|
|
141
141
|
def extract_def_from_sclass(def_node, sclass_node)
|
|
142
142
|
range = source_range_with_comment(def_node)
|
|
143
|
-
source = range
|
|
144
|
-
"def #{def_node.method_name}",
|
|
145
|
-
"def self.#{def_node.method_name}"
|
|
146
|
-
)
|
|
147
|
-
|
|
143
|
+
source = prefix_def_with_self(range, def_node)
|
|
148
144
|
source = source.gsub(/^ {#{indentation_diff(def_node, sclass_node)}}/, '')
|
|
149
145
|
[range, source.chomp]
|
|
150
146
|
end
|
|
151
147
|
|
|
148
|
+
# Splice in `self.` at the actual `def` keyword rather than substituting the
|
|
149
|
+
# first textual `def <name>`, which may appear inside a preceding comment.
|
|
150
|
+
def prefix_def_with_self(range, def_node)
|
|
151
|
+
keyword_offset = def_node.loc.keyword.begin_pos - range.begin_pos
|
|
152
|
+
name_end_offset = def_node.loc.name.end_pos - range.begin_pos
|
|
153
|
+
source = range.source.dup
|
|
154
|
+
source[keyword_offset...name_end_offset] = "def self.#{def_node.method_name}"
|
|
155
|
+
source
|
|
156
|
+
end
|
|
157
|
+
|
|
152
158
|
def indentation_diff(node1, node2)
|
|
153
159
|
node1.loc.column - node2.loc.column
|
|
154
160
|
end
|
|
@@ -96,7 +96,7 @@ module RuboCop
|
|
|
96
96
|
|
|
97
97
|
# @!method grep_v_with_nil?(node)
|
|
98
98
|
def_node_matcher :grep_v_with_nil?, <<~PATTERN
|
|
99
|
-
(
|
|
99
|
+
(call _ :grep_v {(nil) (const {nil? cbase} :NilClass)})
|
|
100
100
|
PATTERN
|
|
101
101
|
|
|
102
102
|
def on_send(node)
|
|
@@ -24,10 +24,9 @@ module RuboCop
|
|
|
24
24
|
|
|
25
25
|
MSG = 'Do not use `::` for method calls.'
|
|
26
26
|
|
|
27
|
-
# @!method
|
|
28
|
-
def_node_matcher :
|
|
29
|
-
(
|
|
30
|
-
(const nil? :Java) _)
|
|
27
|
+
# @!method java_root?(node)
|
|
28
|
+
def_node_matcher :java_root?, <<~PATTERN
|
|
29
|
+
(const nil? :Java)
|
|
31
30
|
PATTERN
|
|
32
31
|
|
|
33
32
|
def self.autocorrect_incompatible_with
|
|
@@ -37,11 +36,19 @@ module RuboCop
|
|
|
37
36
|
def on_send(node)
|
|
38
37
|
return unless node.receiver && node.double_colon?
|
|
39
38
|
return if node.camel_case_method?
|
|
40
|
-
# ignore Java interop code like Java::int
|
|
41
|
-
return if
|
|
39
|
+
# ignore Java interop code like `Java::int` or `Java::com::method`
|
|
40
|
+
return if java_interop?(node)
|
|
42
41
|
|
|
43
42
|
add_offense(node.loc.dot) { |corrector| corrector.replace(node.loc.dot, '.') }
|
|
44
43
|
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def java_interop?(node)
|
|
48
|
+
receiver = node.receiver
|
|
49
|
+
receiver = receiver.receiver while receiver.respond_to?(:receiver) && receiver.receiver
|
|
50
|
+
java_root?(receiver)
|
|
51
|
+
end
|
|
45
52
|
end
|
|
46
53
|
end
|
|
47
54
|
end
|
|
@@ -85,8 +85,13 @@ module RuboCop
|
|
|
85
85
|
def on_for(node)
|
|
86
86
|
return unless node.parent&.begin_type?
|
|
87
87
|
return unless same_collection_looping_for?(node, node.left_sibling)
|
|
88
|
+
return unless node.body && node.left_sibling.body
|
|
88
89
|
|
|
89
90
|
add_offense(node) do |corrector|
|
|
91
|
+
# Combining loops with different iteration variables would leave the second
|
|
92
|
+
# body referencing an undefined variable, so only autocorrect when they match.
|
|
93
|
+
next unless node.variable == node.left_sibling.variable
|
|
94
|
+
|
|
90
95
|
combine_with_left_sibling(corrector, node)
|
|
91
96
|
end
|
|
92
97
|
end
|
|
@@ -90,7 +90,7 @@ module RuboCop
|
|
|
90
90
|
max = if_body.source
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
prefer = "#{
|
|
93
|
+
prefer = "#{parenthesize_if_needed(else_body)}.clamp(#{min}, #{max})"
|
|
94
94
|
|
|
95
95
|
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
|
96
96
|
autocorrect(corrector, node, prefer)
|
|
@@ -119,6 +119,17 @@ module RuboCop
|
|
|
119
119
|
|
|
120
120
|
(lhs.source == else_body && op == :<) || (rhs.source == else_body && op == :>)
|
|
121
121
|
end
|
|
122
|
+
|
|
123
|
+
# `a + b` must become `(a + b).clamp(low, high)`, not `a + b.clamp(low, high)`
|
|
124
|
+
# (which parses as `a + (b.clamp(low, high))`).
|
|
125
|
+
def parenthesize_if_needed(node)
|
|
126
|
+
if node.type?(:and, :or, :if, :range) || node.assignment? ||
|
|
127
|
+
(node.send_type? && (node.operator_method? || node.unary_operation?))
|
|
128
|
+
"(#{node.source})"
|
|
129
|
+
else
|
|
130
|
+
node.source
|
|
131
|
+
end
|
|
132
|
+
end
|
|
122
133
|
end
|
|
123
134
|
end
|
|
124
135
|
end
|
|
@@ -55,6 +55,10 @@ module RuboCop
|
|
|
55
55
|
next unless prefer
|
|
56
56
|
|
|
57
57
|
corrector.replace(offense, prefer)
|
|
58
|
+
elsif node.arguments.any? { |argument| argument.children.empty? }
|
|
59
|
+
# In-place bracket removal would leave dangling commas (e.g.
|
|
60
|
+
# `concat([], [b])` -> `push(, b)`), so rebuild the call instead.
|
|
61
|
+
corrector.replace(offense, preferred_method(node))
|
|
58
62
|
else
|
|
59
63
|
corrector.replace(node.loc.selector, 'push')
|
|
60
64
|
node.arguments.each do |argument|
|
|
@@ -75,7 +79,7 @@ module RuboCop
|
|
|
75
79
|
|
|
76
80
|
def preferred_method(node)
|
|
77
81
|
new_arguments =
|
|
78
|
-
node.arguments.
|
|
82
|
+
node.arguments.flat_map do |arg|
|
|
79
83
|
if arg.percent_literal?
|
|
80
84
|
arg.children.map { |child| child.value.inspect }
|
|
81
85
|
else
|
|
@@ -283,7 +283,10 @@ module RuboCop
|
|
|
283
283
|
|
|
284
284
|
_condition, *branches, else_branch = *assignment
|
|
285
285
|
|
|
286
|
-
|
|
286
|
+
# Use the node accessor rather than the raw destructured branch: for
|
|
287
|
+
# `x = unless cond; body; end` (no `else`) the parser puts `body` in the
|
|
288
|
+
# else slot, but `else_branch` correctly reports there is no `else` clause.
|
|
289
|
+
return unless assignment.else_branch
|
|
287
290
|
return if allowed_single_line?([*branches, else_branch])
|
|
288
291
|
|
|
289
292
|
add_offense(node, message: ASSIGN_TO_CONDITION_MSG) do |corrector|
|
|
@@ -657,6 +660,8 @@ module RuboCop
|
|
|
657
660
|
remove_whitespace_in_branches(corrector, branch, condition, column)
|
|
658
661
|
|
|
659
662
|
parent_keyword = branch.parent.loc.keyword
|
|
663
|
+
return if same_line?(parent_keyword, condition)
|
|
664
|
+
|
|
660
665
|
corrector.remove_preceding(parent_keyword, parent_keyword.column - column)
|
|
661
666
|
end
|
|
662
667
|
end
|
|
@@ -89,7 +89,10 @@ module RuboCop
|
|
|
89
89
|
|
|
90
90
|
arguments = arguments.first.children.first.to_a if arguments.first&.splat_type?
|
|
91
91
|
constant_values = arguments.map do |argument|
|
|
92
|
-
|
|
92
|
+
# `respond_to?(:value)` is too broad: `int`/`float` nodes respond to it
|
|
93
|
+
# but their value is a `Numeric`, which has no `to_sym` (e.g.
|
|
94
|
+
# `private_constant 42`). Only symbol/string arguments are real names.
|
|
95
|
+
argument.value.to_sym if argument.type?(:sym, :str)
|
|
93
96
|
end
|
|
94
97
|
|
|
95
98
|
constant_values.include?(node.name)
|
|
@@ -61,6 +61,10 @@ module RuboCop
|
|
|
61
61
|
|
|
62
62
|
def correct_parent(parent, corrector)
|
|
63
63
|
if parent.block_type?
|
|
64
|
+
# Convert a brace block to `do`, so the class's own `end` closes it
|
|
65
|
+
# once the closing delimiter is removed; otherwise a dangling `{` is
|
|
66
|
+
# left behind, producing invalid Ruby.
|
|
67
|
+
corrector.replace(parent.loc.begin, 'do') if parent.braces?
|
|
64
68
|
corrector.remove(range_with_surrounding_space(parent.loc.end, newlines: false))
|
|
65
69
|
elsif (class_node = parent.parent).body.nil?
|
|
66
70
|
corrector.remove(range_for_empty_class_body(class_node, parent))
|
|
@@ -59,12 +59,12 @@ module RuboCop
|
|
|
59
59
|
|
|
60
60
|
# @!method historic_date?(node)
|
|
61
61
|
def_node_matcher :historic_date?, <<~PATTERN
|
|
62
|
-
(
|
|
62
|
+
(call _ _ _ (const (const {nil? (cbase)} :Date) _))
|
|
63
63
|
PATTERN
|
|
64
64
|
|
|
65
65
|
# @!method to_datetime?(node)
|
|
66
66
|
def_node_matcher :to_datetime?, <<~PATTERN
|
|
67
|
-
(call
|
|
67
|
+
(call !nil? :to_datetime)
|
|
68
68
|
PATTERN
|
|
69
69
|
|
|
70
70
|
def on_send(node)
|
|
@@ -57,11 +57,15 @@ module RuboCop
|
|
|
57
57
|
private
|
|
58
58
|
|
|
59
59
|
def parentheses_required?(node, arguments_range)
|
|
60
|
-
return true if node.single_line? && !node.endless?
|
|
61
|
-
|
|
62
60
|
end_pos = arguments_range.end.end_pos
|
|
63
61
|
token_after_argument = range_between(end_pos, end_pos + 1).source
|
|
64
62
|
|
|
63
|
+
# A `;` after the parentheses (e.g. `def foo(); end`) already separates the
|
|
64
|
+
# signature from the body, so the parentheses can be removed (`def foo; end`).
|
|
65
|
+
return false if token_after_argument == ';'
|
|
66
|
+
|
|
67
|
+
return true if node.single_line? && !node.endless?
|
|
68
|
+
|
|
65
69
|
token_after_argument == '='
|
|
66
70
|
end
|
|
67
71
|
end
|
|
@@ -79,6 +79,11 @@ module RuboCop
|
|
|
79
79
|
corrector.replace(range, replacement)
|
|
80
80
|
|
|
81
81
|
comments_in_range(node).reverse_each do |comment|
|
|
82
|
+
# Only relocate comments that the replacement destroys. A trailing
|
|
83
|
+
# comment after the chain survives in place, so moving it would
|
|
84
|
+
# duplicate it (and splitting the line drops the indentation).
|
|
85
|
+
next if comment.source_range.begin_pos >= range.end_pos
|
|
86
|
+
|
|
82
87
|
corrector.insert_before(node, "#{comment.source}\n")
|
|
83
88
|
end
|
|
84
89
|
end
|
|
@@ -35,6 +35,10 @@ module RuboCop
|
|
|
35
35
|
PATTERN
|
|
36
36
|
|
|
37
37
|
def on_send(node)
|
|
38
|
+
# A trailing block (e.g. `Dir.each_child(path).none? { ... }`) changes
|
|
39
|
+
# the meaning and is not equivalent to `Dir.empty?`.
|
|
40
|
+
return if node.block_literal?
|
|
41
|
+
|
|
38
42
|
offensive?(node) do |const_node, arg_node|
|
|
39
43
|
replacement = "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})"
|
|
40
44
|
add_offense(node, message: format(MSG, replacement: replacement)) do |corrector|
|
|
@@ -140,7 +140,11 @@ module RuboCop
|
|
|
140
140
|
end
|
|
141
141
|
|
|
142
142
|
def method_allowed?(node)
|
|
143
|
-
|
|
143
|
+
# For a modifier form like `module_function def foo; end`, `node` is the
|
|
144
|
+
# `module_function`/`ruby2_keywords` send; the real method name is on its
|
|
145
|
+
# `def`/`defs` argument, not the modifier itself.
|
|
146
|
+
method_name = node.send_type? ? node.first_argument.method_name : node.method_name
|
|
147
|
+
allowed_methods.include?(method_name)
|
|
144
148
|
end
|
|
145
149
|
|
|
146
150
|
def allowed_methods
|
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
|
40
40
|
extend AutoCorrector
|
|
41
41
|
|
|
42
42
|
MSG = 'Do not use empty `case` condition, instead use an `if` expression.'
|
|
43
|
-
NOT_SUPPORTED_PARENT_TYPES = %i[return break next send csend].freeze
|
|
43
|
+
NOT_SUPPORTED_PARENT_TYPES = %i[return break next send csend yield super].freeze
|
|
44
44
|
|
|
45
45
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
46
46
|
def on_case(case_node)
|
|
@@ -90,7 +90,17 @@ module RuboCop
|
|
|
90
90
|
range = range_between(conditions.first.source_range.begin_pos,
|
|
91
91
|
conditions.last.source_range.end_pos)
|
|
92
92
|
|
|
93
|
-
corrector.replace(range, conditions.map(
|
|
93
|
+
corrector.replace(range, conditions.map { |c| parenthesize_condition(c) }.join(' || '))
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# A condition that binds looser than `||` (e.g. a ternary, range, or
|
|
98
|
+
# assignment) must be parenthesized so the joined `||` keeps its meaning.
|
|
99
|
+
def parenthesize_condition(condition)
|
|
100
|
+
if condition.assignment? || condition.type?(:if, :and, :or, :range)
|
|
101
|
+
"(#{condition.source})"
|
|
102
|
+
else
|
|
103
|
+
condition.source
|
|
94
104
|
end
|
|
95
105
|
end
|
|
96
106
|
|
|
@@ -101,12 +101,19 @@ module RuboCop
|
|
|
101
101
|
|
|
102
102
|
def autocorrect_class_new(corrector, node, class_new_node)
|
|
103
103
|
indent = ' ' * node.loc.column
|
|
104
|
-
class_name = node
|
|
104
|
+
class_name = constant_name(node)
|
|
105
105
|
parent_class_name = class_new_node.first_argument.source
|
|
106
106
|
|
|
107
107
|
corrector.replace(node, "class #{class_name} < #{parent_class_name}\n#{indent}end")
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
+
# Preserve any namespace on the assigned constant (e.g. `Foo::Bar`),
|
|
111
|
+
# which `node.name` drops.
|
|
112
|
+
def constant_name(node)
|
|
113
|
+
namespace = node.namespace
|
|
114
|
+
namespace ? "#{namespace.source}::#{node.name}" : node.name
|
|
115
|
+
end
|
|
116
|
+
|
|
110
117
|
def autocorrect_class_definition(corrector, node)
|
|
111
118
|
class_name = node.identifier.source
|
|
112
119
|
parent_class_name = node.parent_class.source
|
|
@@ -42,6 +42,10 @@ module RuboCop
|
|
|
42
42
|
MSG = 'Use an empty string literal instead of heredoc.'
|
|
43
43
|
|
|
44
44
|
def on_heredoc(node)
|
|
45
|
+
# A backtick heredoc (`<<~`CMD``) executes a command, so it cannot be
|
|
46
|
+
# replaced with an empty string literal.
|
|
47
|
+
return if node.xstr_type?
|
|
48
|
+
|
|
45
49
|
heredoc_body = node.loc.heredoc_body
|
|
46
50
|
|
|
47
51
|
return unless heredoc_body.source.empty?
|
|
@@ -44,13 +44,18 @@ module RuboCop
|
|
|
44
44
|
def_node_matcher :str_node, '(send (const {nil? cbase} :String) :new)'
|
|
45
45
|
|
|
46
46
|
# @!method array_with_block(node)
|
|
47
|
-
def_node_matcher :array_with_block,
|
|
47
|
+
def_node_matcher :array_with_block, <<~PATTERN
|
|
48
|
+
{
|
|
49
|
+
(block (send (const {nil? cbase} :Array) :new) args _)
|
|
50
|
+
({numblock itblock} (send (const {nil? cbase} :Array) :new) ...)
|
|
51
|
+
}
|
|
52
|
+
PATTERN
|
|
48
53
|
|
|
49
54
|
# @!method hash_with_block(node)
|
|
50
55
|
def_node_matcher :hash_with_block, <<~PATTERN
|
|
51
56
|
{
|
|
52
57
|
(block (send (const {nil? cbase} :Hash) :new) args _)
|
|
53
|
-
(numblock (send (const {nil? cbase} :Hash) :new) ...)
|
|
58
|
+
({numblock itblock} (send (const {nil? cbase} :Hash) :new) ...)
|
|
54
59
|
}
|
|
55
60
|
PATTERN
|
|
56
61
|
|
|
@@ -45,36 +45,46 @@ module RuboCop
|
|
|
45
45
|
MSG_TRAILING_CONDITIONAL = 'Do not use trailing conditionals in string interpolation.'
|
|
46
46
|
MSG_TERNARY = 'Do not return empty strings in string interpolation.'
|
|
47
47
|
|
|
48
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
49
48
|
def on_interpolation(node)
|
|
50
49
|
node.each_child_node(:if) do |child_node|
|
|
51
50
|
if style == :trailing_conditional
|
|
52
|
-
|
|
53
|
-
ternary_style_autocorrect(child_node, child_node.else_branch.source, 'unless')
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
if empty_else_outcome?(child_node)
|
|
57
|
-
ternary_style_autocorrect(child_node, child_node.if_branch.source, 'if')
|
|
58
|
-
end
|
|
51
|
+
trailing_conditional_correction(child_node)
|
|
59
52
|
elsif style == :ternary
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
ternary_component = if child_node.unless?
|
|
63
|
-
"'' : #{child_node.if_branch.source}"
|
|
64
|
-
else
|
|
65
|
-
"#{child_node.if_branch.source} : ''"
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
add_offense(node, message: MSG_TRAILING_CONDITIONAL) do |corrector|
|
|
69
|
-
corrector.replace(node, "\#{#{child_node.condition.source} ? #{ternary_component}}")
|
|
70
|
-
end
|
|
53
|
+
ternary_correction(node, child_node)
|
|
71
54
|
end
|
|
72
55
|
end
|
|
73
56
|
end
|
|
74
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
75
57
|
|
|
76
58
|
private
|
|
77
59
|
|
|
60
|
+
def trailing_conditional_correction(child_node)
|
|
61
|
+
# A modifier `if`/`unless` is already a trailing conditional and has
|
|
62
|
+
# no `else` branch, so the ternary-to-trailing rewrite does not apply.
|
|
63
|
+
return if child_node.modifier_form?
|
|
64
|
+
|
|
65
|
+
if empty_if_outcome?(child_node)
|
|
66
|
+
ternary_style_autocorrect(child_node, child_node.else_branch.source, 'unless')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
return unless empty_else_outcome?(child_node)
|
|
70
|
+
|
|
71
|
+
ternary_style_autocorrect(child_node, child_node.if_branch.source, 'if')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def ternary_correction(node, child_node)
|
|
75
|
+
return unless child_node.modifier_form?
|
|
76
|
+
|
|
77
|
+
ternary_component = if child_node.unless?
|
|
78
|
+
"'' : #{child_node.if_branch.source}"
|
|
79
|
+
else
|
|
80
|
+
"#{child_node.if_branch.source} : ''"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
add_offense(node, message: MSG_TRAILING_CONDITIONAL) do |corrector|
|
|
84
|
+
corrector.replace(node, "\#{#{child_node.condition.source} ? #{ternary_component}}")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
78
88
|
def empty_if_outcome?(node)
|
|
79
89
|
empty_branch_outcome?(node.if_branch)
|
|
80
90
|
end
|
|
@@ -45,6 +45,10 @@ module RuboCop
|
|
|
45
45
|
def on_send(node)
|
|
46
46
|
return unless env_home?(node)
|
|
47
47
|
return if node.arguments.count == 2 && !node.arguments[1].nil_type?
|
|
48
|
+
# `ENV.fetch('HOME') { default }` supplies a fallback, just like
|
|
49
|
+
# `ENV.fetch('HOME', default)`. `Dir.home` ignores the block, so
|
|
50
|
+
# converting would silently drop it.
|
|
51
|
+
return if node.block_node
|
|
48
52
|
|
|
49
53
|
add_offense(node) do |corrector|
|
|
50
54
|
corrector.replace(node, 'Dir.home')
|
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
|
34
34
|
even_odd_candidate?(node) do |base_number, method, arg|
|
|
35
35
|
replacement_method = replacement_method(arg, method)
|
|
36
36
|
add_offense(node, message: format(MSG, method: replacement_method)) do |corrector|
|
|
37
|
-
correction = "#{base_number
|
|
37
|
+
correction = "#{receiver_source(base_number)}.#{replacement_method}?"
|
|
38
38
|
corrector.replace(node, correction)
|
|
39
39
|
end
|
|
40
40
|
end
|
|
@@ -42,6 +42,16 @@ module RuboCop
|
|
|
42
42
|
|
|
43
43
|
private
|
|
44
44
|
|
|
45
|
+
def receiver_source(node)
|
|
46
|
+
# A binary or unary operator receiver (e.g. `a * b`, `-a`) binds looser
|
|
47
|
+
# than the appended method call, so it must be wrapped in parentheses.
|
|
48
|
+
if node.send_type? && node.operator_method? && !node.method?(:[])
|
|
49
|
+
"(#{node.source})"
|
|
50
|
+
else
|
|
51
|
+
node.source
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
45
55
|
def replacement_method(arg, method)
|
|
46
56
|
case arg
|
|
47
57
|
when 0
|
|
@@ -43,7 +43,8 @@ module RuboCop
|
|
|
43
43
|
return unless (parsed_regexp = parse_regexp(regexp))
|
|
44
44
|
return unless exact_match_pattern?(parsed_regexp)
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
string = escape_single_quotes(parsed_regexp[1].text)
|
|
47
|
+
prefer = "#{receiver.source} #{new_method(node)} '#{string}'"
|
|
47
48
|
|
|
48
49
|
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
|
49
50
|
corrector.replace(node, prefer)
|
|
@@ -53,6 +54,12 @@ module RuboCop
|
|
|
53
54
|
|
|
54
55
|
private
|
|
55
56
|
|
|
57
|
+
# Escape characters that are special inside a single-quoted string so the
|
|
58
|
+
# generated literal (e.g. for `/\Afoo'bar\z/`) stays valid Ruby.
|
|
59
|
+
def escape_single_quotes(text)
|
|
60
|
+
text.gsub(/['\\]/) { |char| "\\#{char}" }
|
|
61
|
+
end
|
|
62
|
+
|
|
56
63
|
def exact_match_pattern?(parsed_regexp)
|
|
57
64
|
tokens = parsed_regexp.map(&:token)
|
|
58
65
|
return false unless tokens[0] == :bos && tokens[1] == :literal && tokens[2] == :eos
|
|
@@ -70,7 +70,7 @@ module RuboCop
|
|
|
70
70
|
|
|
71
71
|
def allowed_var?(node)
|
|
72
72
|
env_key_node = node.children.last
|
|
73
|
-
env_key_node.str_type? && cop_config['
|
|
73
|
+
env_key_node.str_type? && cop_config['AllowedVariables'].include?(env_key_node.value)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def used_as_flag?(node)
|
|
@@ -78,10 +78,12 @@ module RuboCop
|
|
|
78
78
|
|
|
79
79
|
def acceptable?(node)
|
|
80
80
|
# Using a hardcoded null device is acceptable when inside an array or
|
|
81
|
-
# inside a hash to ensure behavior doesn't change.
|
|
81
|
+
# inside a hash to ensure behavior doesn't change. A `str` that is part of
|
|
82
|
+
# an interpolated or concatenated string (`dstr`) is not a standalone null
|
|
83
|
+
# device either, and replacing it would corrupt the surrounding string.
|
|
82
84
|
return false unless node.parent
|
|
83
85
|
|
|
84
|
-
node.parent.type?(:array, :pair)
|
|
86
|
+
node.parent.type?(:array, :pair, :dstr)
|
|
85
87
|
end
|
|
86
88
|
end
|
|
87
89
|
end
|
|
@@ -104,30 +104,33 @@ module RuboCop
|
|
|
104
104
|
|
|
105
105
|
def replacement(mode, filename, content, write_node)
|
|
106
106
|
replacement = "#{write_method(mode)}(#{filename.source}, #{content.source})"
|
|
107
|
-
|
|
108
|
-
return replacement
|
|
107
|
+
heredocs = removed_heredocs(filename, content, write_node)
|
|
108
|
+
return replacement if heredocs.empty?
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
#{replacement}
|
|
112
|
-
#{heredoc_range(heredoc).source}
|
|
113
|
-
REPLACEMENT
|
|
110
|
+
[replacement, *heredocs.map { |heredoc| heredoc_range(heredoc).source }].join("\n")
|
|
114
111
|
end
|
|
115
112
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
# Heredocs opened in the arguments keep working in the replacement, but their
|
|
114
|
+
# bodies are lost when they lie within the replaced range, so they need to be
|
|
115
|
+
# restored after the replacement.
|
|
116
|
+
def removed_heredocs(filename, content, write_node)
|
|
117
|
+
[filename, content].flat_map { |argument| find_heredocs(argument) }
|
|
118
|
+
.select { |heredoc| removed?(heredoc, write_node) }
|
|
119
|
+
.sort_by { |heredoc| heredoc.loc.heredoc_body.begin_pos }
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
def heredoc_range(heredoc)
|
|
123
123
|
range_between(heredoc.loc.heredoc_body.begin_pos, heredoc.loc.heredoc_end.end_pos)
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
-
def
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
def find_heredocs(node)
|
|
127
|
+
[node, *node.each_descendant(:any_str)].select do |child|
|
|
128
|
+
child.respond_to?(:heredoc?) && child.heredoc?
|
|
129
|
+
end
|
|
130
|
+
end
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
def removed?(heredoc, write_node)
|
|
133
|
+
heredoc.loc.heredoc_end.end_pos <= write_node.source_range.end_pos
|
|
131
134
|
end
|
|
132
135
|
end
|
|
133
136
|
end
|
|
@@ -144,10 +144,22 @@ module RuboCop
|
|
|
144
144
|
end
|
|
145
145
|
|
|
146
146
|
def format_single_parameter(arg)
|
|
147
|
+
# `format(fmt, *args)` is equivalent to `fmt % args`, so unwrap the splat
|
|
148
|
+
# and render the argument it splats.
|
|
149
|
+
return format_single_parameter(arg.children.first) if arg.splat_type?
|
|
150
|
+
|
|
147
151
|
source = arg.source
|
|
148
152
|
return "{ #{source} }" if arg.hash_type?
|
|
149
153
|
|
|
150
|
-
|
|
154
|
+
requires_parentheses?(arg) ? "(#{source})" : source
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# An argument that binds looser than `%` (a ternary, range, assignment, or
|
|
158
|
+
# operator call) must be parenthesized to keep its meaning.
|
|
159
|
+
def requires_parentheses?(arg)
|
|
160
|
+
return true if arg.assignment? || arg.type?(:if, :and, :or, :range)
|
|
161
|
+
|
|
162
|
+
arg.send_type? && arg.operator_method? && !arg.parenthesized?
|
|
151
163
|
end
|
|
152
164
|
end
|
|
153
165
|
end
|