rubocop 1.88.2 → 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 +67 -11
- 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 +6 -4
- data/lib/rubocop/cop/bundler.rb +19 -0
- data/lib/rubocop/cop/corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +55 -5
- 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/class_structure.rb +8 -2
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +3 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +27 -0
- data/lib/rubocop/cop/layout/line_length.rb +85 -12
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +12 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +77 -0
- 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/constant_reassignment.rb +1 -10
- data/lib/rubocop/cop/lint/constant_resolution.rb +25 -0
- 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/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 +37 -1
- data/lib/rubocop/cop/lint/unused_private_method.rb +157 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -0
- data/lib/rubocop/cop/lint/void.rb +17 -6
- data/lib/rubocop/cop/lint.rb +176 -0
- 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/check_line_breakable.rb +23 -5
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +23 -6
- 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 +42 -6
- data/lib/rubocop/cop/mixin.rb +78 -77
- data/lib/rubocop/cop/naming/accessor_method_name.rb +24 -0
- data/lib/rubocop/cop/naming/predicate_prefix.rb +33 -5
- 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.rb +19 -0
- 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/conditional_assignment.rb +22 -0
- data/lib/rubocop/cop/style/copyright.rb +6 -1
- 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/endless_method.rb +0 -10
- data/lib/rubocop/cop/style/if_unless_modifier.rb +7 -48
- data/lib/rubocop/cop/style/lambda.rb +4 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +20 -3
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +30 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +7 -1
- 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/redundant_assignment.rb +11 -0
- data/lib/rubocop/cop/style/redundant_constant_base.rb +37 -1
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
- data/lib/rubocop/cop/style/redundant_format.rb +12 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +78 -135
- data/lib/rubocop/cop/style/redundant_parentheses.rb +63 -63
- data/lib/rubocop/cop/style/safe_navigation.rb +10 -0
- 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.rb +310 -0
- data/lib/rubocop/cop/team.rb +48 -3
- 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 +45 -20
- 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
|
@@ -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, ' ')
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
# Cops for the `Layout` department. The department's cops are registered for lazy loading
|
|
6
|
+
# and their files are loaded on demand.
|
|
7
|
+
module Layout
|
|
8
|
+
extend LazyLoader
|
|
9
|
+
|
|
10
|
+
register_cop :AccessModifierIndentation, "#{__dir__}/layout/access_modifier_indentation"
|
|
11
|
+
register_cop :ArgumentAlignment, "#{__dir__}/layout/argument_alignment"
|
|
12
|
+
register_cop :ArrayAlignment, "#{__dir__}/layout/array_alignment"
|
|
13
|
+
register_cop :AssignmentIndentation, "#{__dir__}/layout/assignment_indentation"
|
|
14
|
+
register_cop :BeginEndAlignment, "#{__dir__}/layout/begin_end_alignment"
|
|
15
|
+
register_cop :BlockAlignment, "#{__dir__}/layout/block_alignment"
|
|
16
|
+
register_cop :BlockEndNewline, "#{__dir__}/layout/block_end_newline"
|
|
17
|
+
register_cop :CaseIndentation, "#{__dir__}/layout/case_indentation"
|
|
18
|
+
register_cop :ClassStructure, "#{__dir__}/layout/class_structure"
|
|
19
|
+
register_cop :ClosingHeredocIndentation, "#{__dir__}/layout/closing_heredoc_indentation"
|
|
20
|
+
register_cop :ClosingParenthesisIndentation, "#{__dir__}/layout/closing_parenthesis_indentation"
|
|
21
|
+
register_cop :CommentIndentation, "#{__dir__}/layout/comment_indentation"
|
|
22
|
+
register_cop :ConditionPosition, "#{__dir__}/layout/condition_position"
|
|
23
|
+
register_cop :DefEndAlignment, "#{__dir__}/layout/def_end_alignment"
|
|
24
|
+
register_cop :DotPosition, "#{__dir__}/layout/dot_position"
|
|
25
|
+
register_cop :ElseAlignment, "#{__dir__}/layout/else_alignment"
|
|
26
|
+
register_cop :EmptyComment, "#{__dir__}/layout/empty_comment"
|
|
27
|
+
register_cop :EmptyLineAfterGuardClause, "#{__dir__}/layout/empty_line_after_guard_clause"
|
|
28
|
+
register_cop :EmptyLineAfterMagicComment, "#{__dir__}/layout/empty_line_after_magic_comment"
|
|
29
|
+
register_cop :EmptyLineAfterMultilineCondition, "#{__dir__}/layout/empty_line_after_multiline_condition"
|
|
30
|
+
register_cop :EmptyLineBetweenDefs, "#{__dir__}/layout/empty_line_between_defs"
|
|
31
|
+
register_cop :EmptyLinesAfterModuleInclusion, "#{__dir__}/layout/empty_lines_after_module_inclusion"
|
|
32
|
+
register_cop :EmptyLinesAroundAccessModifier, "#{__dir__}/layout/empty_lines_around_access_modifier"
|
|
33
|
+
register_cop :EmptyLinesAroundArguments, "#{__dir__}/layout/empty_lines_around_arguments"
|
|
34
|
+
register_cop :EmptyLinesAroundAttributeAccessor, "#{__dir__}/layout/empty_lines_around_attribute_accessor"
|
|
35
|
+
register_cop :EmptyLinesAroundBeginBody, "#{__dir__}/layout/empty_lines_around_begin_body"
|
|
36
|
+
register_cop :EmptyLinesAroundBlockBody, "#{__dir__}/layout/empty_lines_around_block_body"
|
|
37
|
+
register_cop :EmptyLinesAroundClassBody, "#{__dir__}/layout/empty_lines_around_class_body"
|
|
38
|
+
register_cop :EmptyLinesAroundExceptionHandlingKeywords, "#{__dir__}/layout/empty_lines_around_exception_handling_keywords"
|
|
39
|
+
register_cop :EmptyLinesAroundMethodBody, "#{__dir__}/layout/empty_lines_around_method_body"
|
|
40
|
+
register_cop :EmptyLinesAroundModuleBody, "#{__dir__}/layout/empty_lines_around_module_body"
|
|
41
|
+
register_cop :EmptyLines, "#{__dir__}/layout/empty_lines"
|
|
42
|
+
register_cop :EndAlignment, "#{__dir__}/layout/end_alignment"
|
|
43
|
+
register_cop :EndOfLine, "#{__dir__}/layout/end_of_line"
|
|
44
|
+
register_cop :ExtraSpacing, "#{__dir__}/layout/extra_spacing"
|
|
45
|
+
register_cop :FirstArgumentIndentation, "#{__dir__}/layout/first_argument_indentation"
|
|
46
|
+
register_cop :FirstArrayElementIndentation, "#{__dir__}/layout/first_array_element_indentation"
|
|
47
|
+
register_cop :FirstArrayElementLineBreak, "#{__dir__}/layout/first_array_element_line_break"
|
|
48
|
+
register_cop :FirstHashElementIndentation, "#{__dir__}/layout/first_hash_element_indentation"
|
|
49
|
+
register_cop :FirstHashElementLineBreak, "#{__dir__}/layout/first_hash_element_line_break"
|
|
50
|
+
register_cop :FirstMethodArgumentLineBreak, "#{__dir__}/layout/first_method_argument_line_break"
|
|
51
|
+
register_cop :FirstMethodParameterLineBreak, "#{__dir__}/layout/first_method_parameter_line_break"
|
|
52
|
+
register_cop :FirstParameterIndentation, "#{__dir__}/layout/first_parameter_indentation"
|
|
53
|
+
register_cop :HashAlignment, "#{__dir__}/layout/hash_alignment"
|
|
54
|
+
register_cop :HeredocArgumentClosingParenthesis, "#{__dir__}/layout/heredoc_argument_closing_parenthesis"
|
|
55
|
+
register_cop :HeredocIndentation, "#{__dir__}/layout/heredoc_indentation"
|
|
56
|
+
register_cop :IndentationConsistency, "#{__dir__}/layout/indentation_consistency"
|
|
57
|
+
register_cop :IndentationStyle, "#{__dir__}/layout/indentation_style"
|
|
58
|
+
register_cop :IndentationWidth, "#{__dir__}/layout/indentation_width"
|
|
59
|
+
register_cop :InitialIndentation, "#{__dir__}/layout/initial_indentation"
|
|
60
|
+
register_cop :LeadingCommentSpace, "#{__dir__}/layout/leading_comment_space"
|
|
61
|
+
register_cop :LeadingEmptyLines, "#{__dir__}/layout/leading_empty_lines"
|
|
62
|
+
register_cop :LineContinuationLeadingSpace, "#{__dir__}/layout/line_continuation_leading_space"
|
|
63
|
+
register_cop :LineContinuationSpacing, "#{__dir__}/layout/line_continuation_spacing"
|
|
64
|
+
register_cop :LineEndStringConcatenationIndentation, "#{__dir__}/layout/line_end_string_concatenation_indentation"
|
|
65
|
+
register_cop :LineLength, "#{__dir__}/layout/line_length"
|
|
66
|
+
register_cop :MultilineArrayBraceLayout, "#{__dir__}/layout/multiline_array_brace_layout"
|
|
67
|
+
register_cop :MultilineArrayLineBreaks, "#{__dir__}/layout/multiline_array_line_breaks"
|
|
68
|
+
register_cop :MultilineAssignmentLayout, "#{__dir__}/layout/multiline_assignment_layout"
|
|
69
|
+
register_cop :MultilineBlockLayout, "#{__dir__}/layout/multiline_block_layout"
|
|
70
|
+
register_cop :MultilineHashBraceLayout, "#{__dir__}/layout/multiline_hash_brace_layout"
|
|
71
|
+
register_cop :MultilineHashKeyLineBreaks, "#{__dir__}/layout/multiline_hash_key_line_breaks"
|
|
72
|
+
register_cop :MultilineMethodArgumentLineBreaks, "#{__dir__}/layout/multiline_method_argument_line_breaks"
|
|
73
|
+
register_cop :MultilineMethodCallBraceLayout, "#{__dir__}/layout/multiline_method_call_brace_layout"
|
|
74
|
+
register_cop :MultilineMethodCallIndentation, "#{__dir__}/layout/multiline_method_call_indentation"
|
|
75
|
+
register_cop :MultilineMethodDefinitionBraceLayout, "#{__dir__}/layout/multiline_method_definition_brace_layout"
|
|
76
|
+
register_cop :MultilineMethodParameterLineBreaks, "#{__dir__}/layout/multiline_method_parameter_line_breaks"
|
|
77
|
+
register_cop :MultilineOperationIndentation, "#{__dir__}/layout/multiline_operation_indentation"
|
|
78
|
+
register_cop :ParameterAlignment, "#{__dir__}/layout/parameter_alignment"
|
|
79
|
+
register_cop :RedundantLineBreak, "#{__dir__}/layout/redundant_line_break"
|
|
80
|
+
register_cop :RescueEnsureAlignment, "#{__dir__}/layout/rescue_ensure_alignment"
|
|
81
|
+
register_cop :SingleLineBlockChain, "#{__dir__}/layout/single_line_block_chain"
|
|
82
|
+
register_cop :SpaceAfterColon, "#{__dir__}/layout/space_after_colon"
|
|
83
|
+
register_cop :SpaceAfterComma, "#{__dir__}/layout/space_after_comma"
|
|
84
|
+
register_cop :SpaceAfterMethodName, "#{__dir__}/layout/space_after_method_name"
|
|
85
|
+
register_cop :SpaceAfterNot, "#{__dir__}/layout/space_after_not"
|
|
86
|
+
register_cop :SpaceAfterSemicolon, "#{__dir__}/layout/space_after_semicolon"
|
|
87
|
+
register_cop :SpaceAroundBlockParameters, "#{__dir__}/layout/space_around_block_parameters"
|
|
88
|
+
register_cop :SpaceAroundEqualsInParameterDefault, "#{__dir__}/layout/space_around_equals_in_parameter_default"
|
|
89
|
+
register_cop :SpaceAroundKeyword, "#{__dir__}/layout/space_around_keyword"
|
|
90
|
+
register_cop :SpaceAroundMethodCallOperator, "#{__dir__}/layout/space_around_method_call_operator"
|
|
91
|
+
register_cop :SpaceAroundOperators, "#{__dir__}/layout/space_around_operators"
|
|
92
|
+
register_cop :SpaceBeforeBlockBraces, "#{__dir__}/layout/space_before_block_braces"
|
|
93
|
+
register_cop :SpaceBeforeBrackets, "#{__dir__}/layout/space_before_brackets"
|
|
94
|
+
register_cop :SpaceBeforeComma, "#{__dir__}/layout/space_before_comma"
|
|
95
|
+
register_cop :SpaceBeforeComment, "#{__dir__}/layout/space_before_comment"
|
|
96
|
+
register_cop :SpaceBeforeFirstArg, "#{__dir__}/layout/space_before_first_arg"
|
|
97
|
+
register_cop :SpaceBeforeSemicolon, "#{__dir__}/layout/space_before_semicolon"
|
|
98
|
+
register_cop :SpaceInLambdaLiteral, "#{__dir__}/layout/space_in_lambda_literal"
|
|
99
|
+
register_cop :SpaceInsideArrayPercentLiteral, "#{__dir__}/layout/space_inside_array_percent_literal"
|
|
100
|
+
register_cop :SpaceInsideArrayLiteralBrackets, "#{__dir__}/layout/space_inside_array_literal_brackets"
|
|
101
|
+
register_cop :SpaceInsideBlockBraces, "#{__dir__}/layout/space_inside_block_braces"
|
|
102
|
+
register_cop :SpaceInsideHashLiteralBraces, "#{__dir__}/layout/space_inside_hash_literal_braces"
|
|
103
|
+
register_cop :SpaceInsideParens, "#{__dir__}/layout/space_inside_parens"
|
|
104
|
+
register_cop :SpaceInsidePercentLiteralDelimiters, "#{__dir__}/layout/space_inside_percent_literal_delimiters"
|
|
105
|
+
register_cop :SpaceInsideRangeLiteral, "#{__dir__}/layout/space_inside_range_literal"
|
|
106
|
+
register_cop :SpaceInsideReferenceBrackets, "#{__dir__}/layout/space_inside_reference_brackets"
|
|
107
|
+
register_cop :SpaceInsideStringInterpolation, "#{__dir__}/layout/space_inside_string_interpolation"
|
|
108
|
+
register_cop :TrailingEmptyLines, "#{__dir__}/layout/trailing_empty_lines"
|
|
109
|
+
register_cop :TrailingWhitespace, "#{__dir__}/layout/trailing_whitespace"
|
|
110
|
+
|
|
111
|
+
autoload :EmptyLinesAroundBody, "#{__dir__}/mixin/empty_lines_around_body"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
# Extend a department module with this module and call `register_cop` to register
|
|
6
|
+
# the department's cops with the global registry without loading their files until
|
|
7
|
+
# a cop class itself is needed:
|
|
8
|
+
#
|
|
9
|
+
# module RuboCop
|
|
10
|
+
# module Cop
|
|
11
|
+
# # The Foo department.
|
|
12
|
+
# module Foo
|
|
13
|
+
# extend LazyLoader
|
|
14
|
+
#
|
|
15
|
+
# register_cop :BarBaz, "#{__dir__}/foo/bar_baz"
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
module LazyLoader
|
|
20
|
+
# Registers a cop for lazy loading. The cop appears in the registry by name right away,
|
|
21
|
+
# but its file is loaded only when the cop class is needed, e.g. when the cop is enabled
|
|
22
|
+
# for an inspection run.
|
|
23
|
+
#
|
|
24
|
+
# The path must be absolute so that loading does not depend on `$LOAD_PATH` and cannot resolve
|
|
25
|
+
# to another RuboCop installation.
|
|
26
|
+
#
|
|
27
|
+
# @param constant_name [Symbol] name of the cop class, e.g. `:BarBaz`
|
|
28
|
+
# @param path [String] absolute path to the file defining the cop class,
|
|
29
|
+
# with or without the `.rb` extension
|
|
30
|
+
def register_cop(constant_name, path)
|
|
31
|
+
raise ArgumentError, "cop path must be absolute: #{path}" unless File.absolute_path?(path)
|
|
32
|
+
|
|
33
|
+
autoload constant_name, path
|
|
34
|
+
|
|
35
|
+
qualified_name = "#{name}::#{constant_name}"
|
|
36
|
+
|
|
37
|
+
Registry.global.lazy_load(Badge.for(qualified_name), qualified_name)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -19,25 +19,27 @@ module RuboCop
|
|
|
19
19
|
# x != y # or x = !y
|
|
20
20
|
#
|
|
21
21
|
class AmbiguousAssignment < Base
|
|
22
|
+
include CheckAssignment
|
|
22
23
|
include RangeHelp
|
|
23
24
|
|
|
24
25
|
MSG = 'Suspicious assignment detected. Did you mean `%<op>s`?'
|
|
25
26
|
|
|
26
|
-
SIMPLE_ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn casgn].freeze
|
|
27
|
-
|
|
28
27
|
MISTAKES = { '=-' => '-=', '=+' => '+=', '=*' => '*=', '=!' => '!=' }.freeze
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
alias on_csend on_send
|
|
30
|
+
|
|
31
|
+
private
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
def check_assignment(node, rhs)
|
|
34
|
+
return unless rhs
|
|
35
|
+
return unless (operator = node.loc.operator)
|
|
36
|
+
|
|
37
|
+
range = range_between(operator.end_pos - 1, rhs.source_range.begin_pos + 1)
|
|
34
38
|
source = range.source
|
|
35
39
|
return unless MISTAKES.key?(source)
|
|
36
40
|
|
|
37
41
|
add_offense(range, message: format(MSG, op: MISTAKES[source]))
|
|
38
42
|
end
|
|
39
|
-
|
|
40
|
-
SIMPLE_ASSIGNMENT_TYPES.each { |asgn_type| alias_method :"on_#{asgn_type}", :on_asgn }
|
|
41
43
|
end
|
|
42
44
|
end
|
|
43
45
|
end
|
|
@@ -6,6 +6,11 @@ module RuboCop
|
|
|
6
6
|
# Checks for ambiguous block association with method
|
|
7
7
|
# when param passed without parentheses.
|
|
8
8
|
#
|
|
9
|
+
# This cop also detects `do...end` blocks that are likely intended for
|
|
10
|
+
# an enumerable method in the arguments but actually bind to the outer
|
|
11
|
+
# method call. For example, in `render json: data.map do |x| x end`,
|
|
12
|
+
# Ruby parses the `do...end` block as belonging to `render`, not `map`.
|
|
13
|
+
#
|
|
9
14
|
# This cop can customize allowed methods with `AllowedMethods`.
|
|
10
15
|
# By default, there are no allowed methods.
|
|
11
16
|
#
|
|
@@ -20,6 +25,18 @@ module RuboCop
|
|
|
20
25
|
# # or (different meaning)
|
|
21
26
|
# some_method(a) { |val| puts val }
|
|
22
27
|
#
|
|
28
|
+
# # bad
|
|
29
|
+
# render json: data.map do |item|
|
|
30
|
+
# item.to_h
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# # good
|
|
34
|
+
# render json: data.map { |item| item.to_h }
|
|
35
|
+
#
|
|
36
|
+
# # good
|
|
37
|
+
# mapped = data.map { |item| item.to_h }
|
|
38
|
+
# render json: mapped
|
|
39
|
+
#
|
|
23
40
|
# # good
|
|
24
41
|
# # Operator methods require no disambiguation
|
|
25
42
|
# foo == bar { |b| b.baz }
|
|
@@ -58,6 +75,19 @@ module RuboCop
|
|
|
58
75
|
MSG = 'Parenthesize the param `%<param>s` to make sure that the ' \
|
|
59
76
|
'block will be associated with the `%<method>s` method ' \
|
|
60
77
|
'call.'
|
|
78
|
+
MSG_DO_END_BLOCK = '`%<inner_method>s` is called without a block because the ' \
|
|
79
|
+
'`do` block binds to `%<outer_method>s`. ' \
|
|
80
|
+
'Use braces or extract to a variable.'
|
|
81
|
+
|
|
82
|
+
BLOCK_METHODS = %i[
|
|
83
|
+
map collect flat_map collect_concat
|
|
84
|
+
select filter find_all reject
|
|
85
|
+
find detect
|
|
86
|
+
each each_with_object each_with_index
|
|
87
|
+
reduce inject
|
|
88
|
+
sort_by min_by max_by
|
|
89
|
+
group_by filter_map
|
|
90
|
+
].to_set.freeze
|
|
61
91
|
|
|
62
92
|
def on_send(node)
|
|
63
93
|
return unless node.arguments?
|
|
@@ -74,8 +104,36 @@ module RuboCop
|
|
|
74
104
|
end
|
|
75
105
|
alias on_csend on_send
|
|
76
106
|
|
|
107
|
+
def on_block(node)
|
|
108
|
+
return if node.braces?
|
|
109
|
+
|
|
110
|
+
send_node = node.send_node
|
|
111
|
+
block_method_arg = find_ambiguous_block_method(node)
|
|
112
|
+
return unless block_method_arg
|
|
113
|
+
|
|
114
|
+
add_offense(block_method_arg,
|
|
115
|
+
message: format(MSG_DO_END_BLOCK,
|
|
116
|
+
inner_method: block_method_arg.method_name,
|
|
117
|
+
outer_method: send_node.method_name))
|
|
118
|
+
end
|
|
119
|
+
alias on_numblock on_block
|
|
120
|
+
alias on_itblock on_block
|
|
121
|
+
|
|
77
122
|
private
|
|
78
123
|
|
|
124
|
+
def find_ambiguous_block_method(block_node)
|
|
125
|
+
send_node = block_node.send_node
|
|
126
|
+
return unless send_node.send_type? && send_node.arguments?
|
|
127
|
+
return if send_node.parenthesized?
|
|
128
|
+
|
|
129
|
+
block_method_arg = find_block_method_arg(send_node)
|
|
130
|
+
return unless block_method_arg
|
|
131
|
+
return if allowed_method?(block_method_arg.method_name) ||
|
|
132
|
+
matches_allowed_pattern?(block_method_arg.source)
|
|
133
|
+
|
|
134
|
+
block_method_arg
|
|
135
|
+
end
|
|
136
|
+
|
|
79
137
|
def ambiguous_block_association?(send_node)
|
|
80
138
|
send_node.last_argument.any_block_type? && !send_node.last_argument.send_node.arguments?
|
|
81
139
|
end
|
|
@@ -92,6 +150,19 @@ module RuboCop
|
|
|
92
150
|
format(MSG, param: block_param.source, method: block_param.send_node.source)
|
|
93
151
|
end
|
|
94
152
|
|
|
153
|
+
# Only the call the `do` block could actually have attached to is a candidate:
|
|
154
|
+
# the one whose source ends where the arguments end. This skips calls chained
|
|
155
|
+
# into another call (`foo bar.map.to_a`) and calls buried inside a
|
|
156
|
+
# parenthesized subcall (`foo bar(baz.map)`), which were never block candidates.
|
|
157
|
+
def find_block_method_arg(send_node)
|
|
158
|
+
end_pos = send_node.source_range.end_pos
|
|
159
|
+
|
|
160
|
+
send_node.last_argument.each_node(:call).find do |node|
|
|
161
|
+
node.source_range.end_pos == end_pos &&
|
|
162
|
+
BLOCK_METHODS.include?(node.method_name) && !node.arguments?
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
95
166
|
def wrap_in_parentheses(corrector, node)
|
|
96
167
|
range = node.loc.selector.end.join(node.first_argument.source_range.begin)
|
|
97
168
|
|
|
@@ -209,21 +209,12 @@ module RuboCop
|
|
|
209
209
|
def report_cross_file_collision(node, fully_qualified_name, display_name)
|
|
210
210
|
return unless project_index
|
|
211
211
|
return unless (declaration = project_index[fully_qualified_name.delete_prefix('::')])
|
|
212
|
-
return unless (prior = prior_definition_in_other_file(declaration))
|
|
212
|
+
return unless (prior = prior_definition_in_other_file(declaration.definitions))
|
|
213
213
|
|
|
214
214
|
msg = format(CROSS_FILE_MSG, constant: display_name, path: prior.location.to_file_path)
|
|
215
215
|
|
|
216
216
|
add_offense(node, message: msg)
|
|
217
217
|
end
|
|
218
|
-
|
|
219
|
-
def prior_definition_in_other_file(declaration)
|
|
220
|
-
current = processed_source.file_path
|
|
221
|
-
|
|
222
|
-
declaration.definitions.find do |definition|
|
|
223
|
-
other = definition.location.to_file_path
|
|
224
|
-
!File.identical?(other, current)
|
|
225
|
-
end
|
|
226
|
-
end
|
|
227
218
|
end
|
|
228
219
|
end
|
|
229
220
|
end
|
|
@@ -20,6 +20,12 @@ module RuboCop
|
|
|
20
20
|
# to prevent conflicting rules. This is because it respects user configurations
|
|
21
21
|
# that want to enable this cop which is disabled by default.
|
|
22
22
|
#
|
|
23
|
+
# When `AllCops/UseProjectIndex` is enabled and the `rubydex` gem is
|
|
24
|
+
# installed, only genuinely ambiguous constants are reported: those
|
|
25
|
+
# that resolve to a different declaration through the surrounding
|
|
26
|
+
# nesting than they would fully qualified. This makes the cop practical
|
|
27
|
+
# to enable without `Only`/`Ignore` lists.
|
|
28
|
+
#
|
|
23
29
|
# @example
|
|
24
30
|
# # By default checks every constant
|
|
25
31
|
#
|
|
@@ -60,6 +66,8 @@ module RuboCop
|
|
|
60
66
|
# Login
|
|
61
67
|
#
|
|
62
68
|
class ConstantResolution < Base
|
|
69
|
+
include ProjectIndexHelp
|
|
70
|
+
|
|
63
71
|
MSG = 'Fully qualify this constant to avoid possibly ambiguous resolution.'
|
|
64
72
|
|
|
65
73
|
# @!method unqualified_const?(node)
|
|
@@ -69,12 +77,29 @@ module RuboCop
|
|
|
69
77
|
|
|
70
78
|
def on_const(node)
|
|
71
79
|
return if !unqualified_const?(node) || node.parent&.defined_module || node.loc.nil?
|
|
80
|
+
return if project_index && !ambiguous_resolution?(node)
|
|
72
81
|
|
|
73
82
|
add_offense(node)
|
|
74
83
|
end
|
|
75
84
|
|
|
76
85
|
private
|
|
77
86
|
|
|
87
|
+
# When `AllCops/UseProjectIndex` is enabled, only genuinely ambiguous
|
|
88
|
+
# references are reported: the constant resolves to a different
|
|
89
|
+
# declaration through the lexical nesting than it would fully
|
|
90
|
+
# qualified. Names that resolve identically either way, or that the
|
|
91
|
+
# index cannot resolve at all (e.g. constants from gems), are not
|
|
92
|
+
# reported.
|
|
93
|
+
def ambiguous_resolution?(node)
|
|
94
|
+
name = node.short_name.to_s
|
|
95
|
+
relative = project_index.resolve_constant(name, lexical_nesting_of(node))
|
|
96
|
+
absolute = project_index.resolve_constant(name, [])
|
|
97
|
+
|
|
98
|
+
!relative.nil? && !absolute.nil? && relative.name != absolute.name
|
|
99
|
+
rescue StandardError
|
|
100
|
+
false
|
|
101
|
+
end
|
|
102
|
+
|
|
78
103
|
def const_name?(name)
|
|
79
104
|
name = name.to_s
|
|
80
105
|
(allowed_names.empty? || allowed_names.include?(name)) && !ignored_names.include?(name)
|