rubocop 1.88.0 → 1.89.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/config/default.yml +72 -12
- data/lib/rubocop/comment_config.rb +35 -19
- data/lib/rubocop/config.rb +53 -0
- data/lib/rubocop/config_validator.rb +38 -1
- data/lib/rubocop/cop/badge.rb +8 -0
- data/lib/rubocop/cop/base.rb +19 -12
- data/lib/rubocop/cop/bundler/gem_comment.rb +3 -1
- data/lib/rubocop/cop/bundler.rb +19 -0
- data/lib/rubocop/cop/commissioner.rb +13 -11
- data/lib/rubocop/cop/corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +55 -5
- 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/gemspec.rb +22 -0
- data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
- data/lib/rubocop/cop/generator.rb +4 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +17 -0
- data/lib/rubocop/cop/layout/class_structure.rb +14 -4
- 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_array_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +13 -14
- data/lib/rubocop/cop/layout/indentation_width.rb +31 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +27 -0
- data/lib/rubocop/cop/layout/line_length.rb +95 -17
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
- data/lib/rubocop/cop/layout/redundant_line_break.rb +77 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +6 -2
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +33 -34
- data/lib/rubocop/cop/layout.rb +114 -0
- data/lib/rubocop/cop/lazy_loader.rb +41 -0
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -7
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +71 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +13 -1
- data/lib/rubocop/cop/lint/constant_reassignment.rb +1 -10
- data/lib/rubocop/cop/lint/constant_resolution.rb +25 -0
- data/lib/rubocop/cop/lint/debugger.rb +13 -1
- data/lib/rubocop/cop/lint/deprecated_reference.rb +185 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +202 -22
- data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
- data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +31 -1
- data/lib/rubocop/cop/lint/name_typo.rb +223 -0
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +7 -0
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +0 -4
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +7 -0
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +44 -2
- data/lib/rubocop/cop/lint/to_json.rb +8 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +32 -8
- data/lib/rubocop/cop/lint/unreachable_code.rb +9 -4
- data/lib/rubocop/cop/lint/unused_private_method.rb +157 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +10 -10
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -0
- data/lib/rubocop/cop/lint/void.rb +19 -8
- data/lib/rubocop/cop/lint.rb +176 -0
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +38 -7
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics.rb +31 -0
- data/lib/rubocop/cop/migration/department_name.rb +0 -4
- data/lib/rubocop/cop/migration.rb +13 -0
- 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/check_line_breakable.rb +23 -5
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +23 -6
- 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/project_index_help.rb +140 -0
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +171 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +43 -7
- data/lib/rubocop/cop/mixin.rb +78 -77
- data/lib/rubocop/cop/naming/accessor_method_name.rb +24 -0
- 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/predicate_prefix.rb +33 -5
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +9 -3
- data/lib/rubocop/cop/naming/variable_number.rb +3 -1
- data/lib/rubocop/cop/naming.rb +31 -0
- data/lib/rubocop/cop/offense.rb +10 -6
- data/lib/rubocop/cop/registry.rb +153 -43
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/security/marshal_load.rb +1 -1
- data/lib/rubocop/cop/security.rb +19 -0
- data/lib/rubocop/cop/style/accessor_grouping.rb +11 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -1
- data/lib/rubocop/cop/style/array_intersect.rb +24 -5
- data/lib/rubocop/cop/style/class_and_module_children.rb +78 -18
- data/lib/rubocop/cop/style/collection_compact.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +22 -0
- data/lib/rubocop/cop/style/copyright.rb +6 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +4 -0
- data/lib/rubocop/cop/style/def_with_parentheses.rb +6 -2
- data/lib/rubocop/cop/style/dir_empty.rb +4 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +41 -3
- data/lib/rubocop/cop/style/documentation.rb +47 -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/endless_method.rb +0 -10
- 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/file_null.rb +4 -2
- 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_syntax.rb +2 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -4
- data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -52
- 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 +11 -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_with_args_parentheses/omit_parentheses.rb +20 -3
- 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 +40 -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 +7 -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/multiple_comparison.rb +33 -22
- data/lib/rubocop/cop/style/mutable_constant.rb +5 -0
- data/lib/rubocop/cop/style/negative_array_index.rb +3 -1
- 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 +11 -2
- 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_assignment.rb +11 -0
- data/lib/rubocop/cop/style/redundant_constant_base.rb +37 -1
- 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_file_extension_in_require.rb +9 -0
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +40 -3
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +80 -129
- data/lib/rubocop/cop/style/redundant_parentheses.rb +63 -63
- 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/safe_navigation.rb +10 -0
- data/lib/rubocop/cop/style/semicolon.rb +4 -4
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +17 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +20 -3
- data/lib/rubocop/cop/style/static_class.rb +21 -0
- 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.rb +310 -0
- data/lib/rubocop/cop/team.rb +66 -7
- data/lib/rubocop/cop/variable_force/variable.rb +18 -6
- data/lib/rubocop/cops_documentation_generator.rb +1 -1
- data/lib/rubocop/directive_comment.rb +2 -0
- data/lib/rubocop/feature_loader.rb +0 -6
- data/lib/rubocop/lsp/routes.rb +41 -3
- data/lib/rubocop/lsp/runtime.rb +4 -0
- data/lib/rubocop/lsp/server.rb +4 -0
- data/lib/rubocop/lsp/stdin_runner.rb +20 -0
- data/lib/rubocop/pending_cops_reporter.rb +1 -6
- data/lib/rubocop/project_index_loader.rb +16 -0
- data/lib/rubocop/result_cache.rb +6 -4
- data/lib/rubocop/rspec/shared_contexts.rb +14 -2
- data/lib/rubocop/runner.rb +100 -33
- data/lib/rubocop/server/cache.rb +10 -5
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +17 -626
- metadata +18 -3
|
@@ -28,10 +28,10 @@ module RuboCop
|
|
|
28
28
|
# # bad
|
|
29
29
|
# hash = {
|
|
30
30
|
# key: :value
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
31
|
+
# }
|
|
32
|
+
# in_a_method_call({
|
|
33
|
+
# foo: :bar
|
|
34
|
+
# })
|
|
35
35
|
# takes_multi_pairs_hash(x: {
|
|
36
36
|
# a: 1,
|
|
37
37
|
# b: 2
|
|
@@ -42,13 +42,12 @@ module RuboCop
|
|
|
42
42
|
# })
|
|
43
43
|
#
|
|
44
44
|
# # good
|
|
45
|
-
# special_inside_parentheses
|
|
46
45
|
# hash = {
|
|
47
46
|
# key: :value
|
|
48
47
|
# }
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
48
|
+
# in_a_method_call({
|
|
49
|
+
# foo: :bar
|
|
50
|
+
# })
|
|
52
51
|
# takes_multi_pairs_hash(x: {
|
|
53
52
|
# a: 1,
|
|
54
53
|
# b: 2
|
|
@@ -67,17 +66,17 @@ module RuboCop
|
|
|
67
66
|
# # bad
|
|
68
67
|
# hash = {
|
|
69
68
|
# key: :value
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
69
|
+
# }
|
|
70
|
+
# in_a_method_call({
|
|
71
|
+
# foo: :bar
|
|
72
|
+
# })
|
|
74
73
|
#
|
|
75
74
|
# # good
|
|
76
75
|
# hash = {
|
|
77
76
|
# key: :value
|
|
78
77
|
# }
|
|
79
|
-
#
|
|
80
|
-
#
|
|
78
|
+
# in_a_method_call({
|
|
79
|
+
# foo: :bar
|
|
81
80
|
# })
|
|
82
81
|
#
|
|
83
82
|
#
|
|
@@ -25,6 +25,17 @@ module RuboCop
|
|
|
25
25
|
# end
|
|
26
26
|
# end
|
|
27
27
|
#
|
|
28
|
+
# @example
|
|
29
|
+
# # bad
|
|
30
|
+
# value = (
|
|
31
|
+
# foo - bar
|
|
32
|
+
# )
|
|
33
|
+
#
|
|
34
|
+
# # good
|
|
35
|
+
# value = (
|
|
36
|
+
# foo - bar
|
|
37
|
+
# )
|
|
38
|
+
#
|
|
28
39
|
# @example AllowedPatterns: ['^\s*module']
|
|
29
40
|
# # bad
|
|
30
41
|
# module A
|
|
@@ -95,6 +106,16 @@ module RuboCop
|
|
|
95
106
|
check_indentation(node.loc.end, node.children.first)
|
|
96
107
|
end
|
|
97
108
|
|
|
109
|
+
def on_begin(node)
|
|
110
|
+
# Only a parenthesized grouping expression (e.g. `(\n foo\n)`) has
|
|
111
|
+
# explicit delimiters. Indent the body one step from the line
|
|
112
|
+
# the opening parenthesis is on, but only when the closing parenthesis is
|
|
113
|
+
# first on its line (a body on the opening line is skipped downstream).
|
|
114
|
+
return unless parentheses?(node) && begins_its_line?(node.loc.end)
|
|
115
|
+
|
|
116
|
+
check_indentation(opening_line_start(node.loc.begin), node.children.first)
|
|
117
|
+
end
|
|
118
|
+
|
|
98
119
|
def on_block(node)
|
|
99
120
|
end_loc = node.loc.end
|
|
100
121
|
|
|
@@ -185,7 +206,16 @@ module RuboCop
|
|
|
185
206
|
def autocorrect(corrector, node)
|
|
186
207
|
return unless node
|
|
187
208
|
|
|
188
|
-
AlignmentCorrector.correct(
|
|
209
|
+
AlignmentCorrector.correct(
|
|
210
|
+
corrector, processed_source, node, @column_delta, tab_indentation: true
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Returns a range at the first non-space column of the line the opening parenthesis is on,
|
|
215
|
+
# used as the base to indent the body from.
|
|
216
|
+
def opening_line_start(begin_loc)
|
|
217
|
+
column = begin_loc.source_line =~ /\S/
|
|
218
|
+
source_range(processed_source.buffer, begin_loc.line, column)
|
|
189
219
|
end
|
|
190
220
|
|
|
191
221
|
def check_members(base, members)
|
|
@@ -98,6 +98,24 @@ module RuboCop
|
|
|
98
98
|
#
|
|
99
99
|
# name = 'John' #: String
|
|
100
100
|
#
|
|
101
|
+
# @example AllowYARDCommentBlockSeparator: false (default)
|
|
102
|
+
#
|
|
103
|
+
# # bad
|
|
104
|
+
#
|
|
105
|
+
# # Copyright (c) Example Corp
|
|
106
|
+
# #-
|
|
107
|
+
# class Client
|
|
108
|
+
# end
|
|
109
|
+
#
|
|
110
|
+
# @example AllowYARDCommentBlockSeparator: true
|
|
111
|
+
#
|
|
112
|
+
# # good
|
|
113
|
+
#
|
|
114
|
+
# # Copyright (c) Example Corp
|
|
115
|
+
# #-
|
|
116
|
+
# class Client
|
|
117
|
+
# end
|
|
118
|
+
#
|
|
101
119
|
class LeadingCommentSpace < Base
|
|
102
120
|
include RangeHelp
|
|
103
121
|
extend AutoCorrector
|
|
@@ -113,6 +131,7 @@ module RuboCop
|
|
|
113
131
|
next if gemfile_ruby_comment?(comment)
|
|
114
132
|
next if rbs_inline_annotation?(comment)
|
|
115
133
|
next if steep_annotation?(comment)
|
|
134
|
+
next if yard_comment_block_separator?(comment)
|
|
116
135
|
|
|
117
136
|
add_offense(comment) do |corrector|
|
|
118
137
|
expr = comment.source_range
|
|
@@ -197,6 +216,14 @@ module RuboCop
|
|
|
197
216
|
def steep_annotation?(comment)
|
|
198
217
|
allow_steep_annotation? && comment.text.start_with?(/#[$:]/)
|
|
199
218
|
end
|
|
219
|
+
|
|
220
|
+
def allow_yard_comment_block_separator?
|
|
221
|
+
cop_config['AllowYARDCommentBlockSeparator']
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def yard_comment_block_separator?(comment)
|
|
225
|
+
allow_yard_comment_block_separator? && comment.text.match?(/\A#-\s*\z/)
|
|
226
|
+
end
|
|
200
227
|
end
|
|
201
228
|
end
|
|
202
229
|
end
|
|
@@ -65,6 +65,7 @@ module RuboCop
|
|
|
65
65
|
include AllowedPattern
|
|
66
66
|
include RangeHelp
|
|
67
67
|
include LineLengthHelp
|
|
68
|
+
include EndlessMethodRewriter
|
|
68
69
|
extend AutoCorrector
|
|
69
70
|
|
|
70
71
|
exclude_limit 'Max'
|
|
@@ -92,8 +93,15 @@ module RuboCop
|
|
|
92
93
|
alias on_hash on_potential_breakable_node
|
|
93
94
|
alias on_send on_potential_breakable_node
|
|
94
95
|
alias on_csend on_potential_breakable_node
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
|
|
97
|
+
def on_def(node)
|
|
98
|
+
if node.endless?
|
|
99
|
+
track_endless_method(node)
|
|
100
|
+
else
|
|
101
|
+
check_for_breakable_node(node)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
alias on_defs on_def
|
|
97
105
|
|
|
98
106
|
def on_new_investigation
|
|
99
107
|
return unless processed_source.raw_source.include?(';')
|
|
@@ -111,6 +119,70 @@ module RuboCop
|
|
|
111
119
|
|
|
112
120
|
attr_accessor :breakable_range
|
|
113
121
|
|
|
122
|
+
def track_endless_method(node)
|
|
123
|
+
line_index = node.first_line - processed_source.buffer.first_line
|
|
124
|
+
endless_methods_by_line[line_index] = node
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def handle_endless_method_line(line, line_index)
|
|
128
|
+
if require_endless_methods?
|
|
129
|
+
return register_required_endless_method_offense(line, line_index)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
register_endless_method_offense(line, line_index)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def require_endless_methods?
|
|
136
|
+
config.cop_enabled?('Style/EndlessMethod') &&
|
|
137
|
+
config.for_cop('Style/EndlessMethod')['EnforcedStyle'] == 'require_always'
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def register_endless_method_offense(line, line_index)
|
|
141
|
+
message = format(MSG, length: line_length(line), max: max)
|
|
142
|
+
loc = excess_range(nil, line, line_index)
|
|
143
|
+
|
|
144
|
+
add_offense(loc, message: message) do |corrector|
|
|
145
|
+
self.max = line_length(line)
|
|
146
|
+
|
|
147
|
+
correct_to_multiline(corrector, endless_methods_by_line[line_index])
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def register_required_endless_method_offense(line, line_index)
|
|
152
|
+
node = endless_methods_by_line[line_index]
|
|
153
|
+
loc = excess_range(nil, line, line_index)
|
|
154
|
+
|
|
155
|
+
add_offense(loc, message: format(MSG, length: line_length(line), max: max)) do |corrector|
|
|
156
|
+
self.max = line_length(line)
|
|
157
|
+
|
|
158
|
+
if correctable_endless_method_block?(node)
|
|
159
|
+
correct_endless_method_block_to_multiline(corrector, node)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def correctable_endless_method_block?(node)
|
|
165
|
+
block_node = node.body
|
|
166
|
+
|
|
167
|
+
block_node&.type?(:any_block) &&
|
|
168
|
+
block_node.braces? &&
|
|
169
|
+
block_node.single_line? &&
|
|
170
|
+
block_node.body &&
|
|
171
|
+
!receiver_contains_heredoc?(block_node)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def correct_endless_method_block_to_multiline(corrector, node)
|
|
175
|
+
block_node = node.body
|
|
176
|
+
block_arguments = block_node.arguments? ? " #{block_node.arguments.source}" : ''
|
|
177
|
+
replacement = [
|
|
178
|
+
"#{block_node.send_node.source} do#{block_arguments}",
|
|
179
|
+
"#{indent(node, offset: 2)}#{block_node.body.source}",
|
|
180
|
+
"#{indent(node)}end"
|
|
181
|
+
].join("\n")
|
|
182
|
+
|
|
183
|
+
corrector.replace(block_node, replacement)
|
|
184
|
+
end
|
|
185
|
+
|
|
114
186
|
def check_for_breakable_node(node)
|
|
115
187
|
breakable_node = extract_breakable_node(node, max)
|
|
116
188
|
return if breakable_node.nil?
|
|
@@ -237,6 +309,10 @@ module RuboCop
|
|
|
237
309
|
@breakable_range_by_line_index ||= {}
|
|
238
310
|
end
|
|
239
311
|
|
|
312
|
+
def endless_methods_by_line
|
|
313
|
+
@endless_methods_by_line ||= {}
|
|
314
|
+
end
|
|
315
|
+
|
|
240
316
|
def breakable_string_delimiters
|
|
241
317
|
@breakable_string_delimiters ||= {}
|
|
242
318
|
end
|
|
@@ -252,10 +328,15 @@ module RuboCop
|
|
|
252
328
|
[max - indentation_difference(line), 0].max
|
|
253
329
|
end
|
|
254
330
|
|
|
255
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
331
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
256
332
|
def check_line(line, line_index)
|
|
257
333
|
return if line_length(line) <= max
|
|
258
334
|
return if allowed_line?(line, line_index)
|
|
335
|
+
|
|
336
|
+
if endless_methods_by_line.key?(line_index)
|
|
337
|
+
return handle_endless_method_line(line, line_index)
|
|
338
|
+
end
|
|
339
|
+
|
|
259
340
|
if allow_rbs_inline_annotation? && rbs_inline_annotation_on_source_line?(line_index)
|
|
260
341
|
return
|
|
261
342
|
end
|
|
@@ -267,7 +348,7 @@ module RuboCop
|
|
|
267
348
|
|
|
268
349
|
register_offense(excess_range(nil, line, line_index), line, line_index)
|
|
269
350
|
end
|
|
270
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
351
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
271
352
|
|
|
272
353
|
def allowed_line?(line, line_index)
|
|
273
354
|
matches_allowed_pattern?(line) ||
|
|
@@ -313,10 +394,6 @@ module RuboCop
|
|
|
313
394
|
end
|
|
314
395
|
alias max_line_length max
|
|
315
396
|
|
|
316
|
-
def allow_heredoc?
|
|
317
|
-
allowed_heredoc
|
|
318
|
-
end
|
|
319
|
-
|
|
320
397
|
def allowed_heredoc
|
|
321
398
|
cop_config['AllowHeredoc']
|
|
322
399
|
end
|
|
@@ -344,10 +421,6 @@ module RuboCop
|
|
|
344
421
|
end
|
|
345
422
|
end
|
|
346
423
|
|
|
347
|
-
def line_in_heredoc?(line_number)
|
|
348
|
-
heredocs.any? { |range, _delimiter| range.cover?(line_number) }
|
|
349
|
-
end
|
|
350
|
-
|
|
351
424
|
def receiver_contains_heredoc?(node)
|
|
352
425
|
return false unless (receiver = node.receiver)
|
|
353
426
|
return true if receiver.any_str_type? && receiver.heredoc?
|
|
@@ -420,11 +493,16 @@ module RuboCop
|
|
|
420
493
|
# The maximum allowed length of a string value is:
|
|
421
494
|
# `Max` - end delimiter (quote) - continuation characters (space and slash)
|
|
422
495
|
max_length = max - 3
|
|
423
|
-
#
|
|
424
|
-
#
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
496
|
+
# Offset by the string's starting column so the broken line actually fits
|
|
497
|
+
# within `Max`. When on the same line as its parent, use the column difference;
|
|
498
|
+
# otherwise the string is indented on its own line, so subtract that indentation.
|
|
499
|
+
# (Without this, an indented string under a multi-line parent never shortens
|
|
500
|
+
# below `Max` and the autocorrect loops, inserting empty `"" \` fragments.)
|
|
501
|
+
max_length -= if same_line?(node, node.parent)
|
|
502
|
+
column_offset_between(node.loc, node.parent.loc)
|
|
503
|
+
else
|
|
504
|
+
node.loc.column
|
|
505
|
+
end
|
|
428
506
|
node.source[0...(max_length)]
|
|
429
507
|
end
|
|
430
508
|
end
|
|
@@ -73,7 +73,12 @@ module RuboCop
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def find_pair_ancestor(node)
|
|
76
|
-
node.each_ancestor
|
|
76
|
+
node.each_ancestor do |ancestor|
|
|
77
|
+
return ancestor if ancestor.pair_type?
|
|
78
|
+
break if grouped_expression?(ancestor) || inside_arg_list_parentheses?(node, ancestor)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
nil
|
|
77
82
|
end
|
|
78
83
|
|
|
79
84
|
def unwrap_block_node(node)
|
|
@@ -405,7 +410,7 @@ module RuboCop
|
|
|
405
410
|
|
|
406
411
|
def find_continuation_node(node)
|
|
407
412
|
receiver = node.receiver
|
|
408
|
-
return receiver
|
|
413
|
+
return leftmost_call_on_same_line(receiver) if single_line_block_receiver?(receiver)
|
|
409
414
|
return unless receiver.call_type? && receiver.loc.dot
|
|
410
415
|
return receiver if receiver.receiver.begin_type? && node.block_node.single_line?
|
|
411
416
|
return unless receiver.loc.dot.line > receiver.receiver.last_line
|
|
@@ -417,9 +422,19 @@ module RuboCop
|
|
|
417
422
|
receiver.single_line? && receiver.any_block_type?
|
|
418
423
|
end
|
|
419
424
|
|
|
425
|
+
def leftmost_call_on_same_line(node)
|
|
426
|
+
current = node.any_block_type? ? node.send_node : node
|
|
427
|
+
while current.receiver&.call_type? &&
|
|
428
|
+
current.receiver.loc?(:dot) &&
|
|
429
|
+
current.receiver.loc.dot.line == current.loc.dot.line
|
|
430
|
+
current = current.receiver
|
|
431
|
+
end
|
|
432
|
+
current
|
|
433
|
+
end
|
|
434
|
+
|
|
420
435
|
def handle_descendant_block(node)
|
|
421
436
|
receiver = node.receiver
|
|
422
|
-
return receiver
|
|
437
|
+
return leftmost_call_on_same_line(receiver) if single_line_block_receiver?(receiver)
|
|
423
438
|
|
|
424
439
|
block_node = node.each_descendant(:any_block).first
|
|
425
440
|
return unless block_node&.multiline?
|
|
@@ -49,6 +49,7 @@ module RuboCop
|
|
|
49
49
|
class RedundantLineBreak < Base
|
|
50
50
|
include CheckAssignment
|
|
51
51
|
include CheckSingleLineSuitability
|
|
52
|
+
include ReparsedEquivalence
|
|
52
53
|
extend AutoCorrector
|
|
53
54
|
|
|
54
55
|
MSG = 'Redundant line break detected.'
|
|
@@ -82,12 +83,88 @@ module RuboCop
|
|
|
82
83
|
end
|
|
83
84
|
|
|
84
85
|
def register_offense(node)
|
|
86
|
+
# The exact single-line correction is verified to parse equivalently
|
|
87
|
+
# before the offense is registered, so a join that would change how
|
|
88
|
+
# the code parses is never reported or offered.
|
|
89
|
+
return if verified_by_reparse([node], oversized: :verify).empty?
|
|
90
|
+
|
|
85
91
|
add_offense(node) do |corrector|
|
|
86
92
|
corrector.replace(node, to_single_line(node.source).strip)
|
|
87
93
|
end
|
|
88
94
|
ignore_node(node)
|
|
89
95
|
end
|
|
90
96
|
|
|
97
|
+
def apply_reparse_correction(corrector, node)
|
|
98
|
+
corrector.replace(node, to_single_line(node.source).strip)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Joining lines shifts the value of any later `__LINE__`, exactly as
|
|
102
|
+
# any other line-removing correction does; neutralize it on both sides
|
|
103
|
+
# with an identifier, which stays valid in every position the keyword
|
|
104
|
+
# can appear in.
|
|
105
|
+
def preprocess_reparsed_source(source)
|
|
106
|
+
source.gsub(/\b__LINE__\b/, '__LINE0__')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def normalize_reparsed_ast(node)
|
|
110
|
+
fold_string_concatenation(node)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Joining lines merges split string literals (`"a" \<newline> "b"` into
|
|
114
|
+
# `"ab"`) and turns mixed-quote pairs into `+` concatenation, which
|
|
115
|
+
# changes the tree but not the resulting string. Normalize all string
|
|
116
|
+
# concatenation to a canonical form before comparing: nested
|
|
117
|
+
# concatenations are flattened and adjacent literal parts merged.
|
|
118
|
+
def fold_string_concatenation(node)
|
|
119
|
+
return node unless node.is_a?(::Parser::AST::Node)
|
|
120
|
+
|
|
121
|
+
children = node.children.map { |child| fold_string_concatenation(child) }
|
|
122
|
+
node = node.updated(nil, children)
|
|
123
|
+
|
|
124
|
+
parts = string_concatenation_parts(node)
|
|
125
|
+
return node unless parts
|
|
126
|
+
|
|
127
|
+
merged = merge_string_parts(parts)
|
|
128
|
+
if merged.one? && merged.first.str_type?
|
|
129
|
+
node.updated(:str, merged.first.children)
|
|
130
|
+
else
|
|
131
|
+
node.updated(:dstr, merged)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def string_concatenation_parts(node)
|
|
136
|
+
case node.type
|
|
137
|
+
when :dstr
|
|
138
|
+
node.children
|
|
139
|
+
when :send
|
|
140
|
+
parts = [node.receiver, *node.arguments]
|
|
141
|
+
parts if node.method?(:+) && parts.all? { |part| stringish?(part) }
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def merge_string_parts(parts)
|
|
146
|
+
flattened = parts.flat_map do |part|
|
|
147
|
+
part.is_a?(::Parser::AST::Node) && part.dstr_type? ? part.children : [part]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
flattened.chunk_while { |left, right| plain_string?(left) && plain_string?(right) }
|
|
151
|
+
.map { |chunk| merge_plain_strings(chunk) }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def merge_plain_strings(chunk)
|
|
155
|
+
return chunk.first if chunk.one?
|
|
156
|
+
|
|
157
|
+
chunk.first.updated(:str, [chunk.map { |part| part.children.first }.join])
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def stringish?(node)
|
|
161
|
+
node.is_a?(::Parser::AST::Node) && %i[str dstr].include?(node.type)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def plain_string?(node)
|
|
165
|
+
node.is_a?(::Parser::AST::Node) && node.str_type? && node.children.one?
|
|
166
|
+
end
|
|
167
|
+
|
|
91
168
|
def offense?(node)
|
|
92
169
|
return false unless node.multiline? && suitable_as_single_line?(node)
|
|
93
170
|
return require_backslash?(node) if node.operator_keyword?
|
|
@@ -204,10 +204,14 @@ module RuboCop
|
|
|
204
204
|
|
|
205
205
|
def autocorrect(corrector, range, right_operand)
|
|
206
206
|
range_source = range.source
|
|
207
|
+
# Match the operator exactly, not by substring, so compound assignments
|
|
208
|
+
# like `**=` and `/=` are not mistaken for `**` and `/` (which would drop
|
|
209
|
+
# the `=` and silently change the program's behavior).
|
|
210
|
+
operator = range_source.strip
|
|
207
211
|
|
|
208
|
-
if
|
|
212
|
+
if operator == '**' && !space_around_exponent_operator?
|
|
209
213
|
corrector.replace(range, '**')
|
|
210
|
-
elsif
|
|
214
|
+
elsif operator == '/' && !space_around_slash_operator?(right_operand)
|
|
211
215
|
corrector.replace(range, '/')
|
|
212
216
|
elsif range_source.end_with?("\n")
|
|
213
217
|
corrector.replace(range, " #{range_source.strip}\n")
|
|
@@ -94,10 +94,10 @@ module RuboCop
|
|
|
94
94
|
return empty_offenses(node, left, right, EMPTY_MSG)
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
-
start_ok = next_to_newline?(
|
|
97
|
+
start_ok = next_to_newline?(tokens, left)
|
|
98
98
|
end_ok = node.single_line? ? false : end_has_own_line?(right)
|
|
99
99
|
|
|
100
|
-
issue_offenses(node, left, right, start_ok, end_ok)
|
|
100
|
+
issue_offenses(node, tokens, left, right, start_ok, end_ok)
|
|
101
101
|
end
|
|
102
102
|
alias on_array_pattern on_array
|
|
103
103
|
|
|
@@ -117,7 +117,7 @@ module RuboCop
|
|
|
117
117
|
elsif style == :space
|
|
118
118
|
SpaceCorrector.add_space(processed_source, corrector, left, right)
|
|
119
119
|
else
|
|
120
|
-
compact_corrections(corrector,
|
|
120
|
+
compact_corrections(corrector, tokens, left, right)
|
|
121
121
|
end
|
|
122
122
|
end
|
|
123
123
|
|
|
@@ -134,8 +134,8 @@ module RuboCop
|
|
|
134
134
|
cop_config['EnforcedStyleForEmptyBrackets']
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
-
def next_to_newline?(
|
|
138
|
-
|
|
137
|
+
def next_to_newline?(tokens, token)
|
|
138
|
+
tokens[index_for(tokens, token) + 1].line != token.line
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
def end_has_own_line?(token)
|
|
@@ -145,68 +145,67 @@ module RuboCop
|
|
|
145
145
|
!/\S/.match?(processed_source.lines[line][0..col])
|
|
146
146
|
end
|
|
147
147
|
|
|
148
|
-
def index_for(
|
|
149
|
-
|
|
148
|
+
def index_for(tokens, token)
|
|
149
|
+
tokens.index(token)
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
def line_and_column_for(token)
|
|
153
153
|
[token.line - 1, token.column - 1]
|
|
154
154
|
end
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
# rubocop:disable Metrics/ParameterLists
|
|
157
|
+
def issue_offenses(node, tokens, left, right, start_ok, end_ok)
|
|
157
158
|
case style
|
|
158
159
|
when :no_space
|
|
159
|
-
start_ok = next_to_comment?(
|
|
160
|
+
start_ok = next_to_comment?(tokens, left)
|
|
160
161
|
no_space_offenses(node, left, right, MSG, start_ok: start_ok, end_ok: end_ok)
|
|
161
162
|
when :space
|
|
162
163
|
space_offenses(node, left, right, MSG, start_ok: start_ok, end_ok: end_ok)
|
|
163
164
|
else
|
|
164
|
-
compact_offenses(node, left, right, start_ok, end_ok)
|
|
165
|
+
compact_offenses(node, tokens, left, right, start_ok, end_ok)
|
|
165
166
|
end
|
|
166
167
|
end
|
|
168
|
+
# rubocop:enable Metrics/ParameterLists
|
|
167
169
|
|
|
168
|
-
def next_to_comment?(
|
|
169
|
-
|
|
170
|
+
def next_to_comment?(tokens, token)
|
|
171
|
+
tokens[index_for(tokens, token) + 1].comment?
|
|
170
172
|
end
|
|
171
173
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
+
# rubocop:disable Metrics/ParameterLists
|
|
175
|
+
def compact_offenses(node, tokens, left, right, start_ok, end_ok)
|
|
176
|
+
if qualifies_for_compact?(tokens, left, side: :left)
|
|
174
177
|
compact_offense(node, left, side: :left)
|
|
175
|
-
elsif !multi_dimensional_array?(
|
|
178
|
+
elsif !multi_dimensional_array?(tokens, left, side: :left)
|
|
176
179
|
space_offenses(node, left, nil, MSG, start_ok: start_ok, end_ok: true)
|
|
177
180
|
end
|
|
178
|
-
|
|
181
|
+
|
|
182
|
+
if qualifies_for_compact?(tokens, right)
|
|
179
183
|
compact_offense(node, right)
|
|
180
|
-
elsif !multi_dimensional_array?(
|
|
184
|
+
elsif !multi_dimensional_array?(tokens, right)
|
|
181
185
|
space_offenses(node, nil, right, MSG, start_ok: true, end_ok: end_ok)
|
|
182
186
|
end
|
|
183
187
|
end
|
|
188
|
+
# rubocop:enable Metrics/ParameterLists
|
|
184
189
|
|
|
185
|
-
def qualifies_for_compact?(
|
|
190
|
+
def qualifies_for_compact?(tokens, token, side: :right)
|
|
186
191
|
if side == :right
|
|
187
|
-
multi_dimensional_array?(
|
|
192
|
+
multi_dimensional_array?(tokens, token) && token.space_before?
|
|
188
193
|
else
|
|
189
|
-
multi_dimensional_array?(
|
|
194
|
+
multi_dimensional_array?(tokens, token, side: :left) && token.space_after?
|
|
190
195
|
end
|
|
191
196
|
end
|
|
192
197
|
|
|
193
|
-
def multi_dimensional_array?(
|
|
198
|
+
def multi_dimensional_array?(tokens, token, side: :right)
|
|
194
199
|
offset = side == :right ? -1 : +1
|
|
195
|
-
i = index_for(
|
|
196
|
-
i += offset while
|
|
200
|
+
i = index_for(tokens, token) + offset
|
|
201
|
+
i += offset while tokens[i].new_line?
|
|
197
202
|
if side == :right
|
|
198
|
-
|
|
203
|
+
tokens[i].right_bracket?
|
|
199
204
|
else
|
|
200
|
-
|
|
205
|
+
tokens[i].left_bracket?
|
|
201
206
|
end
|
|
202
207
|
end
|
|
203
208
|
|
|
204
|
-
def next_to_bracket?(token, side: :right)
|
|
205
|
-
line_index, col = line_and_column_for(token)
|
|
206
|
-
line = processed_source.lines[line_index]
|
|
207
|
-
side == :right ? line[col] == ']' : line[col + 2] == '['
|
|
208
|
-
end
|
|
209
|
-
|
|
210
209
|
def compact_offense(node, token, side: :right)
|
|
211
210
|
if side == :right
|
|
212
211
|
space_offense(node, token, :left, MSG, NO_SPACE_COMMAND)
|
|
@@ -215,14 +214,14 @@ module RuboCop
|
|
|
215
214
|
end
|
|
216
215
|
end
|
|
217
216
|
|
|
218
|
-
def compact_corrections(corrector,
|
|
219
|
-
if multi_dimensional_array?(
|
|
217
|
+
def compact_corrections(corrector, tokens, left, right)
|
|
218
|
+
if multi_dimensional_array?(tokens, left, side: :left)
|
|
220
219
|
compact(corrector, left, :right)
|
|
221
220
|
elsif !left.space_after?
|
|
222
221
|
corrector.insert_after(left.pos, ' ')
|
|
223
222
|
end
|
|
224
223
|
|
|
225
|
-
if multi_dimensional_array?(
|
|
224
|
+
if multi_dimensional_array?(tokens, right)
|
|
226
225
|
compact(corrector, right, :left)
|
|
227
226
|
elsif !right.space_before?
|
|
228
227
|
corrector.insert_before(right.pos, ' ')
|