rubocop 1.90.0 → 1.91.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 +238 -10
- data/config/obsoletion.yml +9 -0
- data/lib/rubocop/changed_files.rb +112 -0
- data/lib/rubocop/cli/command/execute_runner.rb +21 -1
- data/lib/rubocop/cli.rb +9 -3
- data/lib/rubocop/comment_config/directive_range.rb +3 -1
- data/lib/rubocop/comment_config/disable_next.rb +49 -3
- data/lib/rubocop/comment_config/push_pop.rb +55 -0
- data/lib/rubocop/comment_config.rb +21 -51
- data/lib/rubocop/config.rb +10 -0
- data/lib/rubocop/config_loader.rb +12 -4
- data/lib/rubocop/config_loader_resolver.rb +49 -7
- data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
- data/lib/rubocop/config_obsoletion/removed_cop.rb +8 -0
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_validator.rb +18 -3
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/base.rb +15 -3
- data/lib/rubocop/cop/correctors.rb +2 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +6 -5
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
- data/lib/rubocop/cop/layout/line_length.rb +19 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +14 -3
- data/lib/rubocop/cop/layout/space_around_operators.rb +5 -1
- data/lib/rubocop/cop/lint/argument_mismatch.rb +14 -4
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +88 -14
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +8 -2
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +185 -0
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +30 -16
- data/lib/rubocop/cop/lint.rb +1 -0
- data/lib/rubocop/cop/migration/department_name.rb +1 -1
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +11 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -2
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +12 -1
- data/lib/rubocop/cop/mixin.rb +2 -2
- data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/registry.rb +9 -1
- data/lib/rubocop/cop/severity.rb +12 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -2
- data/lib/rubocop/cop/style/case_like_if.rb +3 -3
- data/lib/rubocop/cop/style/constant_visibility.rb +6 -2
- data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/directive_scope.rb +154 -21
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +53 -9
- data/lib/rubocop/cop/style/documentation_method.rb +1 -9
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +12 -2
- data/lib/rubocop/cop/style/endless_method.rb +31 -12
- data/lib/rubocop/cop/style/file_null.rb +2 -2
- data/lib/rubocop/cop/style/float_division.rb +10 -16
- data/lib/rubocop/cop/style/for.rb +5 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +4 -0
- data/lib/rubocop/cop/style/hash_lookup_method.rb +3 -0
- data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +9 -4
- data/lib/rubocop/cop/style/nil_comparison.rb +36 -8
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
- data/lib/rubocop/cop/style/not.rb +3 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +4 -4
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +10 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +11 -1
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +6 -6
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style.rb +0 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +23 -2
- data/lib/rubocop/directive_comment.rb +37 -8
- data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
- data/lib/rubocop/formatter/formatter_set.rb +2 -1
- data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
- data/lib/rubocop/formatter/html_formatter.rb +2 -2
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/sarif_formatter.rb +181 -0
- data/lib/rubocop/formatter.rb +1 -0
- data/lib/rubocop/magic_comment.rb +27 -0
- data/lib/rubocop/options.rb +59 -1
- data/lib/rubocop/path_util.rb +1 -1
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +4 -4
- data/lib/rubocop/result_cache.rb +16 -5
- data/lib/rubocop/runner.rb +64 -21
- data/lib/rubocop/unified_diff.rb +257 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +4 -1
- metadata +8 -4
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
|
@@ -11,7 +11,7 @@ module RuboCop
|
|
|
11
11
|
COMMON_PARAMS = %w[Exclude Include Severity inherit_mode AutoCorrect StyleGuide Details
|
|
12
12
|
Enabled Reference References Safe SafeAutoCorrect].freeze
|
|
13
13
|
# @api private
|
|
14
|
-
INTERNAL_PARAMS = %w[Description StyleGuide
|
|
14
|
+
INTERNAL_PARAMS = %w[Description StyleGuide Preview
|
|
15
15
|
VersionAdded VersionChanged VersionRemoved
|
|
16
16
|
Reference References Safe SafeAutoCorrect].freeze
|
|
17
17
|
# @api private
|
|
@@ -21,7 +21,7 @@ module RuboCop
|
|
|
21
21
|
|
|
22
22
|
# @api private
|
|
23
23
|
CONFIG_CHECK_KEYS = %w[Enabled Safe SafeAutoCorrect AutoCorrect References].to_set.freeze
|
|
24
|
-
CONFIG_CHECK_DEPARTMENTS = %w[pending override_department].freeze
|
|
24
|
+
CONFIG_CHECK_DEPARTMENTS = %w[pending preview override_department].freeze
|
|
25
25
|
CONFIG_CHECK_AUTOCORRECTS = %w[always contextual disabled].freeze
|
|
26
26
|
private_constant :CONFIG_CHECK_KEYS, :CONFIG_CHECK_DEPARTMENTS
|
|
27
27
|
|
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
|
48
48
|
|
|
49
49
|
check_obsoletions
|
|
50
50
|
alert_about_unrecognized_cops(invalid_cop_names)
|
|
51
|
-
|
|
51
|
+
validate_all_cops_parameters
|
|
52
52
|
validate_parameter_names(valid_cop_names)
|
|
53
53
|
validate_enforced_styles(valid_cop_names)
|
|
54
54
|
validate_syntax_cop
|
|
@@ -170,6 +170,21 @@ module RuboCop
|
|
|
170
170
|
validate_department_new_cops_parameters
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
+
def validate_all_cops_parameters
|
|
174
|
+
validate_new_cops_parameter
|
|
175
|
+
validate_fail_level_parameter
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def validate_fail_level_parameter
|
|
179
|
+
fail_level = @config.for_all_cops['FailLevel']
|
|
180
|
+
return if fail_level.nil? || Cop::Severity::NAMES.include?(fail_level.to_sym)
|
|
181
|
+
|
|
182
|
+
message = "invalid #{fail_level} for `FailLevel` found in #{smart_loaded_path}\n" \
|
|
183
|
+
"Valid choices are: #{Cop::Severity::NAMES.join(', ')}"
|
|
184
|
+
|
|
185
|
+
raise ValidationError, message
|
|
186
|
+
end
|
|
187
|
+
|
|
173
188
|
def validate_all_cops_new_cops_parameter
|
|
174
189
|
new_cop_parameter = @config.for_all_cops['NewCops']
|
|
175
190
|
return if new_cop_parameter.nil? || NEW_COPS_VALUES.include?(new_cop_parameter)
|
data/lib/rubocop/cop/badge.rb
CHANGED
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
|
45
45
|
|
|
46
46
|
def hash
|
|
47
47
|
# Do hashing manually to reduce Array allocations.
|
|
48
|
-
department.hash ^ cop_name.hash # rubocop:disable Security/CompoundHash
|
|
48
|
+
department.hash ^ cop_name.hash # rubocop:disable Security/CompoundHash -- hashing manually avoids the Array allocation
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def match?(other)
|
data/lib/rubocop/cop/base.rb
CHANGED
|
@@ -49,7 +49,12 @@ module RuboCop
|
|
|
49
49
|
InvestigationReport = Struct.new(:cop, :processed_source, :offenses, :corrector)
|
|
50
50
|
|
|
51
51
|
# List of methods names to restrict calls for `on_send` / `on_csend`
|
|
52
|
-
RESTRICT_ON_SEND = Set[].freeze # rubocop:disable InternalAffairs/UselessRestrictOnSend
|
|
52
|
+
RESTRICT_ON_SEND = Set[].freeze # rubocop:disable InternalAffairs/UselessRestrictOnSend -- the base class default, which cops override
|
|
53
|
+
|
|
54
|
+
# Departments whose cops report above `convention` unless a cop says
|
|
55
|
+
# otherwise. The exceptions live in `config/default.yml` as an explicit
|
|
56
|
+
# `Severity`, such as the lint-like cops in `Bundler` and `Gemspec`.
|
|
57
|
+
DEPARTMENT_SEVERITIES = { Lint: :warning, Security: :warning, Metrics: :refactor }.freeze
|
|
53
58
|
|
|
54
59
|
# List of cops that should not try to autocorrect at the same
|
|
55
60
|
# time as this cop
|
|
@@ -288,6 +293,13 @@ module RuboCop
|
|
|
288
293
|
@config.string_literals_frozen_by_default?
|
|
289
294
|
end
|
|
290
295
|
|
|
296
|
+
# Whether the user opted in to unstable behavior, with `--preview` or
|
|
297
|
+
# `AllCops: Preview`. Cops branch on this to ship a change that is not
|
|
298
|
+
# ready to be the default yet.
|
|
299
|
+
def preview?
|
|
300
|
+
@config.preview?(@options)
|
|
301
|
+
end
|
|
302
|
+
|
|
291
303
|
def relevant_file?(file)
|
|
292
304
|
return false unless target_satisfies_all_gem_version_requirements?
|
|
293
305
|
return true unless @config.clusivity_config_for_badge?(self.class.badge)
|
|
@@ -326,7 +338,7 @@ module RuboCop
|
|
|
326
338
|
|
|
327
339
|
### Reserved for Commissioner
|
|
328
340
|
|
|
329
|
-
# rubocop:disable Layout/ClassStructure
|
|
341
|
+
# rubocop:disable Layout/ClassStructure -- grouped under the Commissioner heading above
|
|
330
342
|
# @api private
|
|
331
343
|
def callbacks_needed
|
|
332
344
|
self.class.callbacks_needed
|
|
@@ -561,7 +573,7 @@ module RuboCop
|
|
|
561
573
|
end
|
|
562
574
|
|
|
563
575
|
def default_severity
|
|
564
|
-
self.class.
|
|
576
|
+
DEPARTMENT_SEVERITIES.fetch(self.class.department, :convention)
|
|
565
577
|
end
|
|
566
578
|
|
|
567
579
|
def custom_severity
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module RuboCop
|
|
4
|
-
module Cop # rubocop:disable Style/Documentation
|
|
4
|
+
module Cop # rubocop:disable Style/Documentation -- a namespace that only autoloads the correctors below
|
|
5
5
|
# Autoloads corrector classes used by cops. Classes are autoloaded to reduce the number of
|
|
6
6
|
# required classes because they're referenced only when autocorrection is performed.
|
|
7
7
|
|
|
8
|
-
# rubocop:disable Layout/LineLength
|
|
8
|
+
# rubocop:disable Layout/LineLength -- the autoload paths do not wrap
|
|
9
9
|
autoload :AlignmentCorrector, 'rubocop/cop/correctors/alignment_corrector'
|
|
10
10
|
autoload :ConditionCorrector, 'rubocop/cop/correctors/condition_corrector'
|
|
11
11
|
autoload :EachToForCorrector, 'rubocop/cop/correctors/each_to_for_corrector'
|
|
@@ -92,7 +92,7 @@ module RuboCop
|
|
|
92
92
|
(str "true")
|
|
93
93
|
PATTERN
|
|
94
94
|
|
|
95
|
-
def on_block(node) # rubocop:disable Metrics/MethodLength, InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
95
|
+
def on_block(node) # rubocop:disable Metrics/MethodLength, InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- the gemspec block is matched by its named block variable
|
|
96
96
|
gem_specification(node) do |block_var|
|
|
97
97
|
metadata_value = metadata(node)
|
|
98
98
|
mfa_value = mfa_value(metadata_value)
|
|
@@ -147,7 +147,7 @@ module RuboCop
|
|
|
147
147
|
badge: badge,
|
|
148
148
|
version_added: version_added)
|
|
149
149
|
|
|
150
|
-
injector.inject do # rubocop:disable Lint/UnexpectedBlockArity
|
|
150
|
+
injector.inject do # rubocop:disable Lint/UnexpectedBlockArity -- this `inject` is the injector API, not `Enumerable#inject`
|
|
151
151
|
output.puts(format(CONFIGURATION_ADDED_MESSAGE,
|
|
152
152
|
configuration_file_path: config_file_path))
|
|
153
153
|
end
|
|
@@ -75,7 +75,7 @@ module RuboCop
|
|
|
75
75
|
@on_csend_definition = node if node.new_identifier.value == :on_csend
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
-
def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
|
|
78
|
+
def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend -- this cop is what enforces the rule, and does not apply to itself
|
|
79
79
|
return unless (new_identifier = node.first_argument)
|
|
80
80
|
return unless new_identifier.basic_literal?
|
|
81
81
|
|
|
@@ -64,10 +64,10 @@ module RuboCop
|
|
|
64
64
|
autocorrect_one(corrector, comment)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
# Corrects all comment lines that
|
|
68
|
-
#
|
|
69
|
-
# of correcting, saving the file, parsing
|
|
70
|
-
# then correcting one more line, and so on.
|
|
67
|
+
# Corrects all preceding comment lines that have the same indentation
|
|
68
|
+
# and are separated from the given comment by nothing but blank lines.
|
|
69
|
+
# This is to avoid a long chain of correcting, saving the file, parsing
|
|
70
|
+
# and inspecting again, and then correcting one more line, and so on.
|
|
71
71
|
def autocorrect_preceding_comments(corrector, comment)
|
|
72
72
|
comments = processed_source.comments
|
|
73
73
|
index = comments.index(comment)
|
|
@@ -82,7 +82,10 @@ module RuboCop
|
|
|
82
82
|
def should_correct?(preceding_comment, reference_comment)
|
|
83
83
|
loc = preceding_comment.loc
|
|
84
84
|
ref_loc = reference_comment.loc
|
|
85
|
-
|
|
85
|
+
return false unless loc.column == ref_loc.column
|
|
86
|
+
return false unless own_line_comment?(preceding_comment)
|
|
87
|
+
|
|
88
|
+
((loc.line + 1)...ref_loc.line).all? { |line| processed_source[line - 1].blank? }
|
|
86
89
|
end
|
|
87
90
|
|
|
88
91
|
def autocorrect_one(corrector, comment)
|
|
@@ -93,6 +93,7 @@ module RuboCop
|
|
|
93
93
|
when :def, :defs then base_for_method_definition(parent)
|
|
94
94
|
when :kwbegin then parent.loc.begin
|
|
95
95
|
when :block, :numblock, :itblock then start_line_range(parent)
|
|
96
|
+
when :class, :module, :sclass then parent.loc.keyword
|
|
96
97
|
else node.loc.keyword
|
|
97
98
|
end
|
|
98
99
|
end
|
|
@@ -89,15 +89,16 @@ module RuboCop
|
|
|
89
89
|
'in an array, relative to %<base_description>s.'
|
|
90
90
|
|
|
91
91
|
def on_array(node)
|
|
92
|
-
return
|
|
92
|
+
return unless node.loc.begin
|
|
93
|
+
return if autocorrect_incompatible_with_other_cops?(node, nil)
|
|
93
94
|
|
|
94
|
-
check(node, nil)
|
|
95
|
+
check(node, nil)
|
|
95
96
|
end
|
|
96
97
|
|
|
97
98
|
def on_send(node)
|
|
98
|
-
return if style != :consistent && enforce_first_argument_with_fixed_indentation?
|
|
99
|
-
|
|
100
99
|
each_argument_node(node, :array) do |array_node, left_parenthesis|
|
|
100
|
+
next if autocorrect_incompatible_with_other_cops?(array_node, left_parenthesis)
|
|
101
|
+
|
|
101
102
|
check(array_node, left_parenthesis)
|
|
102
103
|
end
|
|
103
104
|
end
|
|
@@ -105,6 +106,18 @@ module RuboCop
|
|
|
105
106
|
|
|
106
107
|
private
|
|
107
108
|
|
|
109
|
+
def autocorrect_incompatible_with_other_cops?(array_node, left_parenthesis)
|
|
110
|
+
return false unless enforce_first_argument_with_fixed_indentation?
|
|
111
|
+
return true if style != :consistent
|
|
112
|
+
|
|
113
|
+
# `Layout/ArrayAlignment` does not align single-element arrays.
|
|
114
|
+
return false if array_node.children.size < 2
|
|
115
|
+
|
|
116
|
+
_base_column, indent_base_type =
|
|
117
|
+
indent_base(array_node.loc.begin, array_node.values.first, left_parenthesis)
|
|
118
|
+
indent_base_type != :start_of_line
|
|
119
|
+
end
|
|
120
|
+
|
|
108
121
|
def autocorrect(corrector, node)
|
|
109
122
|
AlignmentCorrector.correct(corrector, processed_source, node, @column_delta)
|
|
110
123
|
end
|
|
@@ -53,6 +53,7 @@ module RuboCop
|
|
|
53
53
|
def on_def(node)
|
|
54
54
|
return if node.arguments.empty?
|
|
55
55
|
return if node.arguments.loc.begin.nil?
|
|
56
|
+
return if autocorrect_incompatible_with_other_cops?(node)
|
|
56
57
|
|
|
57
58
|
check(node)
|
|
58
59
|
end
|
|
@@ -60,6 +61,11 @@ module RuboCop
|
|
|
60
61
|
|
|
61
62
|
private
|
|
62
63
|
|
|
64
|
+
def autocorrect_incompatible_with_other_cops?(node)
|
|
65
|
+
node.arguments.size >= 2 &&
|
|
66
|
+
style == :align_parentheses && enforce_parameter_with_fixed_indentation?
|
|
67
|
+
end
|
|
68
|
+
|
|
63
69
|
def autocorrect(corrector, node)
|
|
64
70
|
AlignmentCorrector.correct(corrector, processed_source, node, @column_delta)
|
|
65
71
|
end
|
|
@@ -95,6 +101,11 @@ module RuboCop
|
|
|
95
101
|
base_description: base_description
|
|
96
102
|
)
|
|
97
103
|
end
|
|
104
|
+
|
|
105
|
+
def enforce_parameter_with_fixed_indentation?
|
|
106
|
+
parameter_alignment_config = config.for_enabled_cop('Layout/ParameterAlignment')
|
|
107
|
+
parameter_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
|
|
108
|
+
end
|
|
98
109
|
end
|
|
99
110
|
end
|
|
100
111
|
end
|
|
@@ -330,7 +330,11 @@ module RuboCop
|
|
|
330
330
|
end
|
|
331
331
|
|
|
332
332
|
def correct_no_value(corrector, key_delta, key)
|
|
333
|
-
adjust(corrector, key_delta, key)
|
|
333
|
+
adjust(corrector, clamped_key_delta(key_delta, key), key)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def clamped_key_delta(key_delta, key)
|
|
337
|
+
[key_delta, -key.column].max
|
|
334
338
|
end
|
|
335
339
|
|
|
336
340
|
def correct_key_value(corrector, delta, key, value, separator)
|
|
@@ -341,10 +345,7 @@ module RuboCop
|
|
|
341
345
|
value_delta = delta[:value] || 0
|
|
342
346
|
key_delta = delta[:key] || 0
|
|
343
347
|
|
|
344
|
-
|
|
345
|
-
key_delta = -key_column if key_delta < -key_column
|
|
346
|
-
|
|
347
|
-
adjust(corrector, key_delta, key)
|
|
348
|
+
adjust(corrector, clamped_key_delta(key_delta, key), key)
|
|
348
349
|
adjust(corrector, separator_delta, separator)
|
|
349
350
|
adjust(corrector, value_delta, value)
|
|
350
351
|
end
|
|
@@ -400,7 +400,7 @@ module RuboCop
|
|
|
400
400
|
if body_node.rescue_type?
|
|
401
401
|
check_rescue?(body_node)
|
|
402
402
|
elsif body_node.ensure_type?
|
|
403
|
-
block_body, = *body_node # rubocop:disable InternalAffairs/NodeDestructuring
|
|
403
|
+
block_body, = *body_node # rubocop:disable InternalAffairs/NodeDestructuring -- `EnsureNode` has no accessor for the protected body
|
|
404
404
|
if block_body&.rescue_type?
|
|
405
405
|
check_rescue?(block_body)
|
|
406
406
|
else
|
|
@@ -440,7 +440,7 @@ module RuboCop
|
|
|
440
440
|
begin_pos - indentation
|
|
441
441
|
end
|
|
442
442
|
|
|
443
|
-
pos =
|
|
443
|
+
pos = ind <= begin_pos ? ind..begin_pos : begin_pos..ind
|
|
444
444
|
range_between(pos.begin, pos.end)
|
|
445
445
|
end
|
|
446
446
|
|
|
@@ -104,6 +104,11 @@ module RuboCop
|
|
|
104
104
|
alias on_defs on_def
|
|
105
105
|
|
|
106
106
|
def on_new_investigation
|
|
107
|
+
@breakable_range_by_line_index = {}
|
|
108
|
+
@breakable_string_delimiters = {}
|
|
109
|
+
@endless_methods_by_line = {}
|
|
110
|
+
@heredocs = nil
|
|
111
|
+
|
|
107
112
|
return unless processed_source.raw_source.include?(';')
|
|
108
113
|
|
|
109
114
|
check_for_breakable_semicolons(processed_source)
|
|
@@ -288,7 +293,7 @@ module RuboCop
|
|
|
288
293
|
source_range = node.source_range
|
|
289
294
|
relevant_substr = largest_possible_string(node)
|
|
290
295
|
|
|
291
|
-
if (space_pos = relevant_substr
|
|
296
|
+
if (space_pos = breakable_space_position(node, relevant_substr))
|
|
292
297
|
source_range.resize(space_pos + 1)
|
|
293
298
|
elsif (escape_pos = relevant_substr.rindex(/\\(u[\da-f]{0,4}|x[\da-f]{0,2})?\z/))
|
|
294
299
|
source_range.resize(escape_pos)
|
|
@@ -300,6 +305,19 @@ module RuboCop
|
|
|
300
305
|
end
|
|
301
306
|
end
|
|
302
307
|
|
|
308
|
+
def breakable_space_position(node, substr)
|
|
309
|
+
limit = string_content_length(node) - 1
|
|
310
|
+
space_pos = substr.rindex(/\s/)
|
|
311
|
+
space_pos = substr[0, limit].rindex(/\s/) if space_pos && space_pos + 1 > limit
|
|
312
|
+
space_pos
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def string_content_length(node)
|
|
316
|
+
content_end = node.loc?(:end) ? node.loc.end.begin_pos : node.source_range.end_pos
|
|
317
|
+
|
|
318
|
+
content_end - node.source_range.begin_pos
|
|
319
|
+
end
|
|
320
|
+
|
|
303
321
|
def breakable_dstr_begin_position(node)
|
|
304
322
|
source_range = node.source_range
|
|
305
323
|
source_range.begin_pos if source_range.column < max && source_range.last_column >= max
|
|
@@ -5,7 +5,8 @@ module RuboCop
|
|
|
5
5
|
module Layout
|
|
6
6
|
# Checks the spacing inside and after block parameters pipes. Line breaks
|
|
7
7
|
# inside parameter pipes are checked by `Layout/MultilineBlockLayout` and
|
|
8
|
-
# not by this cop.
|
|
8
|
+
# not by this cop. Spaces inside a lambda's parameter parentheses are left
|
|
9
|
+
# to `Layout/SpaceInsideParens` when that cop enforces a conflicting style.
|
|
9
10
|
#
|
|
10
11
|
# @example EnforcedStyleInsidePipes: no_space (default)
|
|
11
12
|
# # bad
|
|
@@ -29,12 +30,12 @@ module RuboCop
|
|
|
29
30
|
include RangeHelp
|
|
30
31
|
extend AutoCorrector
|
|
31
32
|
|
|
32
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
33
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- checks spacing inside a block parameter list
|
|
33
34
|
arguments = node.arguments
|
|
34
35
|
|
|
35
36
|
return unless node.arguments? && pipes?(arguments)
|
|
36
37
|
|
|
37
|
-
check_inside_pipes(arguments)
|
|
38
|
+
check_inside_pipes(arguments) unless conflicting_space_inside_parens_style?(arguments)
|
|
38
39
|
check_after_closing_pipe(arguments) if node.body
|
|
39
40
|
check_each_arg(arguments)
|
|
40
41
|
end
|
|
@@ -53,6 +54,16 @@ module RuboCop
|
|
|
53
54
|
'EnforcedStyleInsidePipes'
|
|
54
55
|
end
|
|
55
56
|
|
|
57
|
+
def conflicting_space_inside_parens_style?(arguments)
|
|
58
|
+
return false unless arguments.loc.begin.source == '('
|
|
59
|
+
|
|
60
|
+
case config.for_enabled_cop('Layout/SpaceInsideParens')['EnforcedStyle']
|
|
61
|
+
when 'no_space' then style == :space
|
|
62
|
+
when 'space', 'compact' then style == :no_space
|
|
63
|
+
else false
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
56
67
|
def check_inside_pipes(arguments)
|
|
57
68
|
case style
|
|
58
69
|
when :no_space
|
|
@@ -258,7 +258,7 @@ module RuboCop
|
|
|
258
258
|
return false unless allow_for_alignment?
|
|
259
259
|
return false unless with_space.source.start_with?(EXCESSIVE_SPACE)
|
|
260
260
|
|
|
261
|
-
return !aligned_with_operator?(operator) unless type
|
|
261
|
+
return !aligned_with_operator?(operator) unless grouped_alignment_type?(type)
|
|
262
262
|
|
|
263
263
|
token = Token.new(operator, nil, operator.source)
|
|
264
264
|
align_preceding = aligned_with_preceding_equals_operator(token)
|
|
@@ -269,6 +269,10 @@ module RuboCop
|
|
|
269
269
|
aligned_with_subsequent_equals_operator(token) != :yes
|
|
270
270
|
end
|
|
271
271
|
|
|
272
|
+
def grouped_alignment_type?(type)
|
|
273
|
+
type == :assignment || (type == :special_asgn && force_equal_sign_alignment?)
|
|
274
|
+
end
|
|
275
|
+
|
|
272
276
|
def excess_trailing_space?(right_operand, with_space)
|
|
273
277
|
with_space.source.end_with?(EXCESSIVE_SPACE) &&
|
|
274
278
|
(!allow_for_alignment? || !aligned_with_something?(right_operand))
|
|
@@ -21,7 +21,9 @@ module RuboCop
|
|
|
21
21
|
#
|
|
22
22
|
# Constructor calls (`Foo.new`) and keyword-argument validation are out of
|
|
23
23
|
# scope: only positional arity of explicitly defined singleton methods is
|
|
24
|
-
# checked.
|
|
24
|
+
# checked. `new` is skipped outright, because `Class#new` is not in the
|
|
25
|
+
# index: any `new` the index does find sits below it in the method
|
|
26
|
+
# resolution order, where Ruby would never reach it.
|
|
25
27
|
#
|
|
26
28
|
# @example
|
|
27
29
|
# # Given the project defines:
|
|
@@ -45,8 +47,7 @@ module RuboCop
|
|
|
45
47
|
MSG = 'Wrong number of arguments to `%<method>s` (given %<given>d, expected %<expected>s).'
|
|
46
48
|
|
|
47
49
|
def on_send(node)
|
|
48
|
-
return unless
|
|
49
|
-
return unless node.receiver&.const_type?
|
|
50
|
+
return unless checkable_call?(node)
|
|
50
51
|
|
|
51
52
|
shape = resolved_signature_shape(node)
|
|
52
53
|
return unless shape
|
|
@@ -61,6 +62,10 @@ module RuboCop
|
|
|
61
62
|
|
|
62
63
|
private
|
|
63
64
|
|
|
65
|
+
def checkable_call?(node)
|
|
66
|
+
project_index && node.receiver&.const_type? && !node.method?(:new)
|
|
67
|
+
end
|
|
68
|
+
|
|
64
69
|
def message(node, given, min, max)
|
|
65
70
|
format(MSG, method: node.method_name, given: given, expected: expected_range(min, max))
|
|
66
71
|
end
|
|
@@ -77,9 +82,14 @@ module RuboCop
|
|
|
77
82
|
nil
|
|
78
83
|
end
|
|
79
84
|
|
|
85
|
+
# A call with an explicit receiver cannot reach a private method, so its
|
|
86
|
+
# signature says nothing about the call. This matters because `Object`
|
|
87
|
+
# closes the singleton ancestry of every constant, and a bare `def` at
|
|
88
|
+
# the top level of any file — what every block-based DSL produces — is a
|
|
89
|
+
# private instance method of `Object`.
|
|
80
90
|
def singleton_signature_shape(declaration, method_name)
|
|
81
91
|
member = indexed_singleton_member(declaration, "#{method_name}()")
|
|
82
|
-
return nil unless member
|
|
92
|
+
return nil unless member&.public?
|
|
83
93
|
|
|
84
94
|
indexed_member_shape(member)
|
|
85
95
|
end
|
|
@@ -106,6 +106,8 @@ module RuboCop
|
|
|
106
106
|
def traverse_node(node, &block)
|
|
107
107
|
# if the node is a block, any assignments are irrelevant
|
|
108
108
|
return if node.any_block_type?
|
|
109
|
+
# an assignment inside `defined?` is never executed
|
|
110
|
+
return if node.defined_type?
|
|
109
111
|
|
|
110
112
|
result = yield node if ASGN_TYPES.include?(node.type)
|
|
111
113
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# rubocop:disable Lint/RedundantCopDisableDirective
|
|
4
|
-
# rubocop:disable Style/DoubleCopDisableDirective
|
|
5
3
|
module RuboCop
|
|
6
4
|
module Cop
|
|
7
5
|
module Lint
|
|
@@ -23,12 +21,11 @@ module RuboCop
|
|
|
23
21
|
# # good
|
|
24
22
|
# # rubocop:disable all
|
|
25
23
|
#
|
|
26
|
-
# # bad
|
|
24
|
+
# # bad - only the first directive takes effect
|
|
27
25
|
# # rubocop:disable Layout/LineLength # rubocop:disable Style/Encoding
|
|
28
26
|
#
|
|
29
27
|
# # good
|
|
30
|
-
# # rubocop:disable Layout/LineLength
|
|
31
|
-
# # rubocop:disable Style/Encoding
|
|
28
|
+
# # rubocop:disable Layout/LineLength, Style/Encoding
|
|
32
29
|
#
|
|
33
30
|
# # bad
|
|
34
31
|
# # rubocop:wrongmode Layout/LineLength
|
|
@@ -55,13 +52,19 @@ module RuboCop
|
|
|
55
52
|
# # rubocop:disable Layout/LineLength
|
|
56
53
|
#
|
|
57
54
|
class CopDirectiveSyntax < Base
|
|
55
|
+
extend AutoCorrector
|
|
56
|
+
|
|
58
57
|
COMMON_MSG = 'Malformed directive comment detected.'
|
|
59
58
|
|
|
60
59
|
MISSING_MODE_NAME_MSG = 'The mode name is missing.'
|
|
61
|
-
INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, `disable-next`, `todo`, `todo-next`, `push`, or `pop`.' # rubocop:disable Layout/LineLength
|
|
60
|
+
INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, `disable-next`, `enable-next`, `todo`, `todo-next`, `next`, `push`, or `pop`.' # rubocop:disable Layout/LineLength -- the message lists every mode and does not wrap
|
|
62
61
|
MISSING_COP_NAME_MSG = 'The cop name is missing.'
|
|
62
|
+
MULTIPLE_DIRECTIVES_MSG = 'Only the first directive on a line takes effect. ' \
|
|
63
|
+
'List the cop names in a single directive instead.'
|
|
63
64
|
MALFORMED_COP_NAMES_MSG = 'Cop names must be separated by commas. ' \
|
|
64
65
|
'Comment in the directive must start with `--`.'
|
|
66
|
+
INVALID_SIGNED_ARGS_MSG = '`push` and `next` arguments must be `+`- or `-`-prefixed ' \
|
|
67
|
+
'cop names, and `pop` takes no arguments.'
|
|
65
68
|
NEXT_DIRECTIVE_AT_EOL_MSG = 'A `-next` directive must be on its own line, above the ' \
|
|
66
69
|
'statement it applies to.'
|
|
67
70
|
INVALID_KEYWORD_MSG = 'The directive keyword must be `rubocop`, not `%<keyword>s`.'
|
|
@@ -89,7 +92,11 @@ module RuboCop
|
|
|
89
92
|
private
|
|
90
93
|
|
|
91
94
|
def check_directive(comment, directive_comment)
|
|
92
|
-
if directive_comment
|
|
95
|
+
if (directives = multiple_directives(comment, directive_comment))
|
|
96
|
+
add_offense(comment, message: "#{COMMON_MSG} #{MULTIPLE_DIRECTIVES_MSG}") do |corrector|
|
|
97
|
+
merge_directives(corrector, comment, directives)
|
|
98
|
+
end
|
|
99
|
+
elsif directive_comment.malformed?
|
|
93
100
|
add_offense(comment, message: offense_message(directive_comment))
|
|
94
101
|
elsif misplaced_next_directive?(directive_comment)
|
|
95
102
|
add_offense(comment, message: NEXT_DIRECTIVE_AT_EOL_MSG)
|
|
@@ -98,13 +105,72 @@ module RuboCop
|
|
|
98
105
|
end
|
|
99
106
|
end
|
|
100
107
|
|
|
101
|
-
#
|
|
102
|
-
#
|
|
108
|
+
# Everything after the first directive in a comment is trailing text as
|
|
109
|
+
# far as the parser is concerned, so a second directive written on the
|
|
110
|
+
# same line disables nothing at all. A valid `--` reason may mention a
|
|
111
|
+
# directive as plain text, which should not be treated as another one.
|
|
112
|
+
def multiple_directives(comment, directive_comment)
|
|
113
|
+
matches = comment.text.to_enum(:scan, DirectiveComment::DIRECTIVE_COMMENT_REGEXP)
|
|
114
|
+
.map { Regexp.last_match }
|
|
115
|
+
matches = filter_reason_matches(matches, directive_comment)
|
|
116
|
+
|
|
117
|
+
matches if matches.size > 1
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def filter_reason_matches(matches, directive_comment)
|
|
121
|
+
return matches unless directive_comment.reason
|
|
122
|
+
|
|
123
|
+
[matches.first, *matches.drop(1).reject { |match| match.post_match.match?(/\S/) }]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def merge_directives(corrector, comment, directives)
|
|
127
|
+
return unless directives_adjacent?(comment, directives)
|
|
128
|
+
return unless (mode = merged_mode(directives))
|
|
129
|
+
return unless (cops = merged_cops(directives))
|
|
130
|
+
|
|
131
|
+
corrector.replace(comment, "# rubocop:#{mode} #{cops.join(', ')}")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# `all` covers every cop already, so folding it into a list of names
|
|
135
|
+
# would be a rewrite rather than a merge.
|
|
136
|
+
def merged_cops(directives)
|
|
137
|
+
cops = directives.flat_map { |match| match[2].to_s.split(',').map(&:strip) }
|
|
138
|
+
cops = cops.reject(&:empty?).uniq
|
|
139
|
+
cops unless cops.empty? || cops.include?('all')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Anything written between the directives is a `--` reason or prose,
|
|
143
|
+
# and merging around it would either move it or drop it.
|
|
144
|
+
def directives_adjacent?(comment, directives)
|
|
145
|
+
text = comment.text
|
|
146
|
+
bounds = directives.map { |match| match.end(0) }
|
|
147
|
+
.zip(directives.map { |match| match.begin(0) }[1..] + [text.length])
|
|
148
|
+
bounds.all? { |from, to| text[from...to].strip.empty? }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# `todo` is an alias of `disable`, so those two combine. Anything else
|
|
152
|
+
# (an `enable` beside a `disable`, or directives of different scopes)
|
|
153
|
+
# means different things per directive and can't be folded into one.
|
|
154
|
+
def merged_mode(directives)
|
|
155
|
+
modes = directives.map { |match| match[1] }.uniq
|
|
156
|
+
return modes.first if modes.size == 1
|
|
157
|
+
return modes.first if (modes - %w[disable todo]).empty?
|
|
158
|
+
|
|
159
|
+
nil
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# An EOL next-statement directive is not honored - it must fail
|
|
163
|
+
# loudly instead of silently doing nothing.
|
|
103
164
|
def misplaced_next_directive?(directive_comment)
|
|
104
|
-
directive_comment
|
|
165
|
+
next_statement_directive?(directive_comment) &&
|
|
105
166
|
!processed_source.comment_config.comment_only_line?(directive_comment.line_number)
|
|
106
167
|
end
|
|
107
168
|
|
|
169
|
+
def next_statement_directive?(directive_comment)
|
|
170
|
+
directive_comment.disable_next? || directive_comment.enable_next? ||
|
|
171
|
+
directive_comment.next?
|
|
172
|
+
end
|
|
173
|
+
|
|
108
174
|
# rubocop:disable-next Metrics/MethodLength
|
|
109
175
|
def offense_message(directive_comment)
|
|
110
176
|
comment = directive_comment.comment
|
|
@@ -116,6 +182,8 @@ module RuboCop
|
|
|
116
182
|
INVALID_MODE_NAME_MSG
|
|
117
183
|
elsif directive_comment.missing_cop_name?
|
|
118
184
|
MISSING_COP_NAME_MSG
|
|
185
|
+
elsif directive_comment.invalid_signed_args?
|
|
186
|
+
INVALID_SIGNED_ARGS_MSG
|
|
119
187
|
else
|
|
120
188
|
MALFORMED_COP_NAMES_MSG
|
|
121
189
|
end
|
|
@@ -142,10 +210,10 @@ module RuboCop
|
|
|
142
210
|
end
|
|
143
211
|
|
|
144
212
|
def unknown_cop_name(directive_comment)
|
|
145
|
-
return if directive_comment.
|
|
213
|
+
return if directive_comment.pop? || directive_comment.all_cops?
|
|
146
214
|
|
|
147
215
|
registry = directive_comment.cop_registry
|
|
148
|
-
directive_comment.
|
|
216
|
+
directive_names(directive_comment).find do |name|
|
|
149
217
|
next false if registry.department?(name)
|
|
150
218
|
|
|
151
219
|
qualified = registry.qualified_cop_name(name, nil, warn: false)
|
|
@@ -153,6 +221,14 @@ module RuboCop
|
|
|
153
221
|
end
|
|
154
222
|
end
|
|
155
223
|
|
|
224
|
+
def directive_names(directive_comment)
|
|
225
|
+
if directive_comment.push? || directive_comment.next?
|
|
226
|
+
directive_comment.signed_args.values.flatten
|
|
227
|
+
else
|
|
228
|
+
directive_comment.raw_cop_names
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
156
232
|
def unknown_cop_message(directive_comment, name)
|
|
157
233
|
similar = NameSimilarity.find_similar_name(name, directive_comment.cop_registry.names)
|
|
158
234
|
suggestion = similar ? " (did you mean `#{similar}`?)" : ''
|
|
@@ -162,5 +238,3 @@ module RuboCop
|
|
|
162
238
|
end
|
|
163
239
|
end
|
|
164
240
|
end
|
|
165
|
-
# rubocop:enable Lint/RedundantCopDisableDirective
|
|
166
|
-
# rubocop:enable Style/DoubleCopDisableDirective
|