rubocop 1.66.1 → 1.68.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +55 -6
- data/config/internal_affairs.yml +11 -0
- data/lib/rubocop/cached_data.rb +12 -4
- data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
- data/lib/rubocop/cli/command/execute_runner.rb +1 -1
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli/command/version.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +3 -3
- data/lib/rubocop/config_validator.rb +2 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +22 -2
- data/lib/rubocop/cop/base.rb +6 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
- data/lib/rubocop/cop/cop.rb +8 -0
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
- data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
- data/lib/rubocop/cop/internal_affairs.rb +16 -0
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -5
- data/lib/rubocop/cop/layout/leading_comment_space.rb +56 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
- data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
- data/lib/rubocop/cop/lint/ensure_return.rb +0 -3
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +10 -4
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +5 -14
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +25 -2
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +7 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +9 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +107 -41
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
- data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -0
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +3 -1
- data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
- data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +4 -5
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +12 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +46 -6
- data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +31 -3
- data/lib/rubocop/cop/style/collection_compact.rb +10 -10
- data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +7 -0
- data/lib/rubocop/cop/style/commented_keyword.rb +7 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +1 -14
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +15 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +6 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -3
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
- data/lib/rubocop/cop/style/lambda.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +59 -8
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -7
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/multiple_comparison.rb +28 -39
- data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +25 -6
- data/lib/rubocop/cop/style/redundant_begin.rb +4 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +23 -5
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -11
- data/lib/rubocop/cop/style/require_order.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +13 -1
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
- data/lib/rubocop/cop/style/safe_navigation.rb +104 -50
- data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +9 -6
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/team.rb +8 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
- data/lib/rubocop/cop/variable_force/branch.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +5 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cops_documentation_generator.rb +81 -40
- data/lib/rubocop/file_finder.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/lsp/runtime.rb +2 -0
- data/lib/rubocop/lsp/server.rb +0 -1
- data/lib/rubocop/rspec/expect_offense.rb +1 -0
- data/lib/rubocop/runner.rb +17 -6
- data/lib/rubocop/server/cache.rb +6 -1
- data/lib/rubocop/server/core.rb +1 -0
- data/lib/rubocop/target_ruby.rb +13 -13
- data/lib/rubocop/version.rb +28 -7
- data/lib/rubocop/yaml_duplication_checker.rb +20 -27
- data/lib/rubocop.rb +10 -0
- metadata +13 -4
data/lib/rubocop/cop/team.rb
CHANGED
@@ -9,11 +9,17 @@ module RuboCop
|
|
9
9
|
# For performance reasons, Team will first dispatch cops & forces in two groups,
|
10
10
|
# first the ones needed for autocorrection (if any), then the rest
|
11
11
|
# (unless autocorrections happened).
|
12
|
+
# rubocop:disable Metrics/ClassLength
|
12
13
|
class Team
|
13
14
|
# @return [Team]
|
14
15
|
def self.new(cop_or_classes, config, options = {})
|
15
16
|
# Support v0 api:
|
16
|
-
|
17
|
+
if cop_or_classes.first.is_a?(Class)
|
18
|
+
warn Rainbow(<<~WARNING).yellow, uplevel: 1
|
19
|
+
`Team.new` with cop classes is deprecated. Use `Team.mobilize` instead.
|
20
|
+
WARNING
|
21
|
+
return mobilize(cop_or_classes, config, options)
|
22
|
+
end
|
17
23
|
|
18
24
|
super
|
19
25
|
end
|
@@ -279,5 +285,6 @@ module RuboCop
|
|
279
285
|
end
|
280
286
|
end
|
281
287
|
end
|
288
|
+
# rubocop:enable Metrics/ClassLength
|
282
289
|
end
|
283
290
|
end
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -9,9 +9,10 @@ module RuboCop
|
|
9
9
|
|
10
10
|
MULTIPLE_LEFT_HAND_SIDE_TYPE = :mlhs
|
11
11
|
|
12
|
-
attr_reader :node, :variable, :referenced, :references
|
12
|
+
attr_reader :node, :variable, :referenced, :references, :reassigned
|
13
13
|
|
14
14
|
alias referenced? referenced
|
15
|
+
alias reassigned? reassigned
|
15
16
|
|
16
17
|
def initialize(node, variable)
|
17
18
|
unless VARIABLE_ASSIGNMENT_TYPES.include?(node.type)
|
@@ -24,6 +25,7 @@ module RuboCop
|
|
24
25
|
@variable = variable
|
25
26
|
@referenced = false
|
26
27
|
@references = []
|
28
|
+
@reassigned = false
|
27
29
|
end
|
28
30
|
|
29
31
|
def name
|
@@ -39,8 +41,14 @@ module RuboCop
|
|
39
41
|
@referenced = true
|
40
42
|
end
|
41
43
|
|
44
|
+
def reassigned!
|
45
|
+
return if referenced?
|
46
|
+
|
47
|
+
@reassigned = true
|
48
|
+
end
|
49
|
+
|
42
50
|
def used?
|
43
|
-
@variable.captured_by_block? || @referenced
|
51
|
+
(!reassigned? && @variable.captured_by_block?) || @referenced
|
44
52
|
end
|
45
53
|
|
46
54
|
def regexp_named_capture?
|
@@ -102,6 +110,7 @@ module RuboCop
|
|
102
110
|
end
|
103
111
|
|
104
112
|
def multiple_assignment_node
|
113
|
+
return nil unless node.parent&.mlhs_type?
|
105
114
|
return nil unless (grandparent_node = node.parent&.parent)
|
106
115
|
if (node = find_multiple_assignment_node(grandparent_node))
|
107
116
|
return node
|
@@ -119,7 +128,13 @@ module RuboCop
|
|
119
128
|
end
|
120
129
|
|
121
130
|
def for_assignment_node
|
122
|
-
node.
|
131
|
+
return unless (parent_node = node.parent)
|
132
|
+
return parent_node if parent_node.for_type?
|
133
|
+
|
134
|
+
grandparent_node = parent_node.parent
|
135
|
+
return grandparent_node if parent_node.mlhs_type? && grandparent_node&.for_type?
|
136
|
+
|
137
|
+
nil
|
123
138
|
end
|
124
139
|
|
125
140
|
def find_multiple_assignment_node(grandparent_node)
|
@@ -29,7 +29,11 @@ module RuboCop
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def assign(node)
|
32
|
-
|
32
|
+
assignment = Assignment.new(node, self)
|
33
|
+
|
34
|
+
@assignments.last&.reassigned! unless captured_by_block?
|
35
|
+
|
36
|
+
@assignments << assignment
|
33
37
|
end
|
34
38
|
|
35
39
|
def referenced?
|
@@ -61,8 +61,8 @@ module RuboCop
|
|
61
61
|
"at #{node.source_range}, #{node.inspect}"
|
62
62
|
end
|
63
63
|
|
64
|
-
variable.assign(node)
|
65
64
|
mark_variable_as_captured_by_block_if_so(variable)
|
65
|
+
variable.assign(node)
|
66
66
|
end
|
67
67
|
|
68
68
|
def reference_variable(name, node)
|
@@ -87,8 +87,8 @@ module RuboCop
|
|
87
87
|
# So just skip.
|
88
88
|
return unless variable
|
89
89
|
|
90
|
-
variable.reference!(node)
|
91
90
|
mark_variable_as_captured_by_block_if_so(variable)
|
91
|
+
variable.reference!(node)
|
92
92
|
end
|
93
93
|
|
94
94
|
def find_variable(name)
|
@@ -1,23 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
|
+
require 'yard'
|
4
5
|
|
5
6
|
# Class for generating documentation of all cops departments
|
6
7
|
# @api private
|
7
8
|
class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
8
9
|
include ::RuboCop::Cop::Documentation
|
10
|
+
CopData = Struct.new(
|
11
|
+
:cop, :description, :example_objects, :safety_objects, :see_objects, :config, keyword_init: true
|
12
|
+
)
|
13
|
+
|
14
|
+
STRUCTURE = {
|
15
|
+
name: ->(data) { cop_header(data.cop) },
|
16
|
+
required_ruby_version: ->(data) { required_ruby_version(data.cop) },
|
17
|
+
properties: ->(data) { properties(data.cop) },
|
18
|
+
description: ->(data) { "#{data.description}\n" },
|
19
|
+
safety: ->(data) { safety_object(data.safety_objects, data.cop) },
|
20
|
+
examples: ->(data) { examples(data.example_objects, data.cop) },
|
21
|
+
configuration: ->(data) { configurations(data.cop.department, data.config, data.cop) },
|
22
|
+
references: ->(data) { references(data.cop, data.see_objects) }
|
23
|
+
}.freeze
|
24
|
+
|
9
25
|
# This class will only generate documentation for cops that belong to one of
|
10
26
|
# the departments given in the `departments` array. E.g. if we only wanted
|
11
27
|
# documentation for Lint cops:
|
12
28
|
#
|
13
29
|
# CopsDocumentationGenerator.new(departments: ['Lint']).call
|
14
30
|
#
|
15
|
-
|
31
|
+
# You can append additional information:
|
32
|
+
#
|
33
|
+
# callback = ->(data) { required_rails_version(data.cop) }
|
34
|
+
# CopsDocumentationGenerator.new(extra_info: { ruby_version: callback }).call
|
35
|
+
#
|
36
|
+
# This will insert the string returned from the lambda _after_ the section from RuboCop itself.
|
37
|
+
# See `CopsDocumentationGenerator::STRUCTURE` for available sections.
|
38
|
+
#
|
39
|
+
def initialize(departments: [], extra_info: {}, base_dir: Dir.pwd)
|
16
40
|
@departments = departments.map(&:to_sym).sort!
|
41
|
+
@extra_info = extra_info
|
17
42
|
@cops = RuboCop::Cop::Registry.global
|
18
43
|
@config = RuboCop::ConfigLoader.default_configuration
|
19
|
-
@
|
20
|
-
|
44
|
+
@base_dir = base_dir
|
45
|
+
@docs_path = "#{base_dir}/docs/modules/ROOT"
|
46
|
+
FileUtils.mkdir_p("#{@docs_path}/pages")
|
21
47
|
end
|
22
48
|
|
23
49
|
def call
|
@@ -37,24 +63,21 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
37
63
|
cops.with_department(department).sort!
|
38
64
|
end
|
39
65
|
|
40
|
-
def cops_body(
|
41
|
-
check_examples_to_have_the_default_enforced_style!(
|
42
|
-
|
43
|
-
content =
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
content << examples(examples_objects) if examples_objects.any?
|
49
|
-
content << configurations(cop.department, pars)
|
50
|
-
content << references(cop, see_objects)
|
66
|
+
def cops_body(data)
|
67
|
+
check_examples_to_have_the_default_enforced_style!(data.example_objects, data.cop)
|
68
|
+
|
69
|
+
content = +''
|
70
|
+
STRUCTURE.each do |section, block|
|
71
|
+
content << instance_exec(data, &block)
|
72
|
+
content << @extra_info[section].call(data) if @extra_info[section]
|
73
|
+
end
|
51
74
|
content
|
52
75
|
end
|
53
76
|
|
54
|
-
def check_examples_to_have_the_default_enforced_style!(
|
55
|
-
return if
|
77
|
+
def check_examples_to_have_the_default_enforced_style!(example_objects, cop)
|
78
|
+
return if example_objects.none?
|
56
79
|
|
57
|
-
examples_describing_enforced_style =
|
80
|
+
examples_describing_enforced_style = example_objects.map(&:name).grep(/EnforcedStyle:/)
|
58
81
|
return if examples_describing_enforced_style.none?
|
59
82
|
|
60
83
|
if examples_describing_enforced_style.index { |name| name.match?('default') }.nonzero?
|
@@ -66,16 +89,20 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
66
89
|
raise "Specify the default EnforcedStyle for #{cop.cop_name}"
|
67
90
|
end
|
68
91
|
|
69
|
-
def examples(
|
70
|
-
|
92
|
+
def examples(example_objects, cop)
|
93
|
+
return '' if example_objects.none?
|
94
|
+
|
95
|
+
example_objects.each_with_object(cop_subsection('Examples', cop).dup) do |example, content|
|
71
96
|
content << "\n" unless content.end_with?("\n\n")
|
72
|
-
content <<
|
97
|
+
content << example_header(example.name, cop) unless example.name == ''
|
73
98
|
content << code_example(example)
|
74
99
|
end
|
75
100
|
end
|
76
101
|
|
77
|
-
def safety_object(
|
78
|
-
|
102
|
+
def safety_object(safety_objects, cop)
|
103
|
+
return '' if safety_objects.all? { |s| s.text.blank? }
|
104
|
+
|
105
|
+
safety_objects.each_with_object(cop_subsection('Safety', cop).dup) do |safety_object, content|
|
79
106
|
next if safety_object.text.blank?
|
80
107
|
|
81
108
|
content << "\n" unless content.end_with?("\n\n")
|
@@ -115,22 +142,25 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
115
142
|
end
|
116
143
|
# rubocop:enable Metrics/MethodLength
|
117
144
|
|
118
|
-
def
|
145
|
+
def cop_header(cop)
|
119
146
|
content = +"\n"
|
120
|
-
content << "
|
147
|
+
content << "[##{to_anchor(cop.cop_name)}]\n"
|
148
|
+
content << "== #{cop.cop_name}\n"
|
121
149
|
content << "\n"
|
122
150
|
content
|
123
151
|
end
|
124
152
|
|
125
|
-
def
|
153
|
+
def cop_subsection(title, cop)
|
126
154
|
content = +"\n"
|
155
|
+
content << "[##{to_anchor(title)}-#{to_anchor(cop.cop_name)}]\n"
|
127
156
|
content << "=== #{title}\n"
|
128
157
|
content << "\n"
|
129
158
|
content
|
130
159
|
end
|
131
160
|
|
132
|
-
def
|
133
|
-
content = +"
|
161
|
+
def example_header(title, cop)
|
162
|
+
content = +"[##{to_anchor(title)}-#{to_anchor(cop.cop_name)}]\n"
|
163
|
+
content << "==== #{title}\n"
|
134
164
|
content << "\n"
|
135
165
|
content
|
136
166
|
end
|
@@ -142,7 +172,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
142
172
|
content
|
143
173
|
end
|
144
174
|
|
145
|
-
def configurations(department, pars)
|
175
|
+
def configurations(department, pars, cop)
|
146
176
|
return '' if pars.empty?
|
147
177
|
|
148
178
|
header = ['Name', 'Default value', 'Configurable values']
|
@@ -157,7 +187,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
157
187
|
[configuration_name(department, name), default, configurable]
|
158
188
|
end
|
159
189
|
|
160
|
-
|
190
|
+
cop_subsection('Configurable attributes', cop) + to_table(header, content)
|
161
191
|
end
|
162
192
|
|
163
193
|
def configuration_name(department, name)
|
@@ -218,7 +248,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
218
248
|
else
|
219
249
|
wrap_backtick(val.nil? ? '<none>' : val)
|
220
250
|
end
|
221
|
-
value.gsub("#{
|
251
|
+
value.gsub("#{@base_dir}/", '').rstrip
|
222
252
|
end
|
223
253
|
|
224
254
|
def wrap_backtick(value)
|
@@ -235,7 +265,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
235
265
|
urls = RuboCop::Cop::MessageAnnotator.new(config, cop.name, cop_config, {}).urls
|
236
266
|
return '' if urls.empty? && see_objects.empty?
|
237
267
|
|
238
|
-
content =
|
268
|
+
content = cop_subsection('References', cop)
|
239
269
|
content << urls.map { |url| "* #{url}" }.join("\n")
|
240
270
|
content << "\n" unless urls.empty?
|
241
271
|
content << see_objects.map { |see| "* #{see.name}" }.join("\n")
|
@@ -247,7 +277,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
247
277
|
return '' unless department == :Layout
|
248
278
|
|
249
279
|
filename = "#{department_to_basename(department)}_footer.adoc"
|
250
|
-
file = "#{
|
280
|
+
file = "#{docs_path}/partials/#{filename}"
|
251
281
|
return '' unless File.exist?(file)
|
252
282
|
|
253
283
|
"\ninclude::../partials/#{filename}[]\n"
|
@@ -267,7 +297,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
267
297
|
HEADER
|
268
298
|
selected_cops.each { |cop| content << print_cop_with_doc(cop) }
|
269
299
|
content << footer_for_department(department)
|
270
|
-
file_name = "#{docs_path}/#{department_to_basename(department)}.adoc"
|
300
|
+
file_name = "#{docs_path}/pages/#{department_to_basename(department)}.adoc"
|
271
301
|
File.open(file_name, 'w') do |file|
|
272
302
|
puts "* generated #{file_name}"
|
273
303
|
file.write("#{content.strip}\n")
|
@@ -283,14 +313,16 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
283
313
|
]
|
284
314
|
pars = cop_config.reject { |k| non_display_keys.include? k }
|
285
315
|
description = 'No documentation'
|
286
|
-
|
316
|
+
example_objects = safety_objects = see_objects = []
|
287
317
|
cop_code(cop) do |code_object|
|
288
318
|
description = code_object.docstring unless code_object.docstring.blank?
|
289
|
-
|
290
|
-
|
291
|
-
|
319
|
+
example_objects = code_object.tags('example')
|
320
|
+
safety_objects = code_object.tags('safety')
|
321
|
+
see_objects = code_object.tags('see')
|
292
322
|
end
|
293
|
-
|
323
|
+
data = CopData.new(cop: cop, description: description, example_objects: example_objects,
|
324
|
+
safety_objects: safety_objects, see_objects: see_objects, config: pars)
|
325
|
+
cops_body(data)
|
294
326
|
end
|
295
327
|
|
296
328
|
def cop_code(cop)
|
@@ -306,7 +338,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
306
338
|
filename = "#{department_to_basename(department)}.adoc"
|
307
339
|
content = +"=== Department xref:#{filename}[#{type_title}]\n\n"
|
308
340
|
cops_of_department(department).each do |cop|
|
309
|
-
anchor = cop.cop_name
|
341
|
+
anchor = to_anchor(cop.cop_name)
|
310
342
|
content << "* xref:#{filename}##{anchor}[#{cop.cop_name}]\n"
|
311
343
|
end
|
312
344
|
|
@@ -314,7 +346,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
314
346
|
end
|
315
347
|
|
316
348
|
def print_table_of_contents
|
317
|
-
path = "#{docs_path}/cops.adoc"
|
349
|
+
path = "#{docs_path}/pages/cops.adoc"
|
318
350
|
|
319
351
|
File.write(path, table_contents) and return unless File.exist?(path)
|
320
352
|
|
@@ -338,4 +370,13 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
338
370
|
|
339
371
|
status == 'pending' ? 'Pending' : 'Enabled'
|
340
372
|
end
|
373
|
+
|
374
|
+
# HTML anchor are somewhat limited in what characters they can contain, just
|
375
|
+
# accept a known-good subset. As long as it's consistent it doesn't matter.
|
376
|
+
#
|
377
|
+
# Style/AccessModifierDeclarations => styleaccessmodifierdeclarations
|
378
|
+
# OnlyFor: [] (default) => onlyfor_-__-_default_
|
379
|
+
def to_anchor(title)
|
380
|
+
title.delete('/').tr(' ', '-').gsub(/[^a-zA-Z0-9-]/, '_').downcase
|
381
|
+
end
|
341
382
|
end
|
data/lib/rubocop/file_finder.rb
CHANGED
@@ -23,15 +23,20 @@ module RuboCop
|
|
23
23
|
last_file
|
24
24
|
end
|
25
25
|
|
26
|
+
def traverse_directories_upwards(start_dir, stop_dir = nil)
|
27
|
+
Pathname.new(start_dir).expand_path.ascend do |dir|
|
28
|
+
yield(dir)
|
29
|
+
dir = dir.to_s
|
30
|
+
break if dir == stop_dir || dir == FileFinder.root_level
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
26
34
|
private
|
27
35
|
|
28
36
|
def traverse_files_upwards(filename, start_dir, stop_dir)
|
29
|
-
|
37
|
+
traverse_directories_upwards(start_dir, stop_dir) do |dir|
|
30
38
|
file = dir + filename
|
31
39
|
yield(file.to_s) if file.exist?
|
32
|
-
|
33
|
-
dir = dir.to_s
|
34
|
-
break if dir == stop_dir || dir == FileFinder.root_level
|
35
40
|
end
|
36
41
|
end
|
37
42
|
end
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
HEADING = <<~COMMENTS
|
11
11
|
# This configuration was generated by
|
12
12
|
# `%<command>s`
|
13
|
-
# %<timestamp>susing RuboCop version #{Version
|
13
|
+
# %<timestamp>susing RuboCop version #{Version::STRING}.
|
14
14
|
# The point is for the user to remove these configuration records
|
15
15
|
# one by one as the offenses are removed from the code base.
|
16
16
|
# Note that changes in the inspected code, or installation of new
|
data/lib/rubocop/lsp/runtime.rb
CHANGED
data/lib/rubocop/lsp/server.rb
CHANGED
@@ -169,6 +169,7 @@ module RuboCop
|
|
169
169
|
raise 'Expected correction but no corrections were made' if new_source == source
|
170
170
|
|
171
171
|
expect(new_source).to eq(correction)
|
172
|
+
expect(@processed_source).to be_valid_syntax, 'Expected correction to be valid syntax'
|
172
173
|
end
|
173
174
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
174
175
|
|
data/lib/rubocop/runner.rb
CHANGED
@@ -139,7 +139,7 @@ module RuboCop
|
|
139
139
|
offenses = process_file(file)
|
140
140
|
yield file
|
141
141
|
|
142
|
-
if offenses.any? { |o| considered_failure?(o) }
|
142
|
+
if offenses.any? { |o| considered_failure?(o) && offense_displayed?(o) }
|
143
143
|
break false if @options[:fail_fast]
|
144
144
|
|
145
145
|
next false
|
@@ -362,6 +362,13 @@ module RuboCop
|
|
362
362
|
self.class.ruby_extractors.find do |ruby_extractor|
|
363
363
|
result = ruby_extractor.call(processed_source)
|
364
364
|
break result if result
|
365
|
+
rescue StandardError
|
366
|
+
location = if ruby_extractor.is_a?(Proc)
|
367
|
+
ruby_extractor.source_location
|
368
|
+
else
|
369
|
+
ruby_extractor.method(:call).source_location
|
370
|
+
end
|
371
|
+
raise Error, "Ruby extractor #{location[0]} failed to process #{processed_source.path}."
|
365
372
|
end
|
366
373
|
end
|
367
374
|
|
@@ -433,18 +440,22 @@ module RuboCop
|
|
433
440
|
!offense.corrected? && offense.severity >= minimum_severity_to_fail
|
434
441
|
end
|
435
442
|
|
436
|
-
def
|
443
|
+
def offense_displayed?(offense)
|
437
444
|
if @options[:display_only_fail_level_offenses]
|
438
|
-
|
445
|
+
considered_failure?(offense)
|
439
446
|
elsif @options[:display_only_safe_correctable]
|
440
|
-
|
447
|
+
supports_safe_autocorrect?(offense)
|
441
448
|
elsif @options[:display_only_correctable]
|
442
|
-
|
449
|
+
offense.correctable?
|
443
450
|
else
|
444
|
-
|
451
|
+
true
|
445
452
|
end
|
446
453
|
end
|
447
454
|
|
455
|
+
def offenses_to_report(offenses)
|
456
|
+
offenses.select { |o| offense_displayed?(o) }
|
457
|
+
end
|
458
|
+
|
448
459
|
def supports_safe_autocorrect?(offense)
|
449
460
|
cop_class = Cop::Registry.global.find_by_cop_name(offense.cop_name)
|
450
461
|
default_cfg = default_config(offense.cop_name)
|
data/lib/rubocop/server/cache.rb
CHANGED
@@ -43,13 +43,18 @@ module RuboCop
|
|
43
43
|
@project_dir_cache_key ||= project_dir[1..].tr('/', '+')
|
44
44
|
end
|
45
45
|
|
46
|
+
# rubocop:disable Metrics/AbcSize
|
46
47
|
def restart_key
|
47
48
|
lockfile_path = LOCKFILE_NAMES.map do |lockfile_name|
|
48
49
|
Pathname(project_dir).join(lockfile_name)
|
49
50
|
end.find(&:exist?)
|
51
|
+
version_data = lockfile_path&.read || RuboCop::Version::STRING
|
52
|
+
config_data = Pathname(ConfigFinder.find_config_path(Dir.pwd)).read
|
53
|
+
todo_data = (rubocop_todo = Pathname('.rubocop_todo.yml')).exist? ? rubocop_todo.read : ''
|
50
54
|
|
51
|
-
Digest::SHA1.hexdigest(
|
55
|
+
Digest::SHA1.hexdigest(version_data + config_data + todo_data)
|
52
56
|
end
|
57
|
+
# rubocop:enable Metrics/AbcSize
|
53
58
|
|
54
59
|
def dir
|
55
60
|
Pathname.new(File.join(cache_path, project_dir_cache_key)).tap do |d|
|
data/lib/rubocop/server/core.rb
CHANGED
data/lib/rubocop/target_ruby.rb
CHANGED
@@ -53,8 +53,6 @@ module RuboCop
|
|
53
53
|
class GemspecFile < Source
|
54
54
|
extend NodePattern::Macros
|
55
55
|
|
56
|
-
GEMSPEC_EXTENSION = '.gemspec'
|
57
|
-
|
58
56
|
# @!method required_ruby_version(node)
|
59
57
|
def_node_search :required_ruby_version, <<~PATTERN
|
60
58
|
(send _ :required_ruby_version= $_)
|
@@ -68,7 +66,7 @@ module RuboCop
|
|
68
66
|
PATTERN
|
69
67
|
|
70
68
|
def name
|
71
|
-
"`required_ruby_version` parameter (in #{
|
69
|
+
"`required_ruby_version` parameter (in #{gemspec_filepath})"
|
72
70
|
end
|
73
71
|
|
74
72
|
private
|
@@ -83,16 +81,18 @@ module RuboCop
|
|
83
81
|
find_minimal_known_ruby(right_hand_side)
|
84
82
|
end
|
85
83
|
|
86
|
-
def gemspec_filename
|
87
|
-
@gemspec_filename ||= begin
|
88
|
-
basename = Pathname.new(@config.base_dir_for_path_parameters).basename.to_s
|
89
|
-
"#{basename}#{GEMSPEC_EXTENSION}"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
84
|
def gemspec_filepath
|
94
|
-
@gemspec_filepath
|
95
|
-
|
85
|
+
return @gemspec_filepath if defined?(@gemspec_filepath)
|
86
|
+
|
87
|
+
@gemspec_filepath =
|
88
|
+
@config.traverse_directories_upwards(@config.base_dir_for_path_parameters) do |dir|
|
89
|
+
# NOTE: Can't use `dir.glob` because of JRuby 9.4.8.0 incompatibility:
|
90
|
+
# https://github.com/jruby/jruby/issues/8358
|
91
|
+
candidates = Pathname.glob("#{dir}/*.gemspec")
|
92
|
+
# Bundler will use a gemspec whatever the filename is, as long as its the only one in
|
93
|
+
# the folder.
|
94
|
+
break candidates.first if candidates.one?
|
95
|
+
end
|
96
96
|
end
|
97
97
|
|
98
98
|
def version_from_gemspec_file(file)
|
@@ -273,7 +273,7 @@ module RuboCop
|
|
273
273
|
|
274
274
|
def rubocop_version_with_support
|
275
275
|
if supported?
|
276
|
-
RuboCop::Version
|
276
|
+
RuboCop::Version::STRING
|
277
277
|
else
|
278
278
|
OBSOLETE_RUBIES[version]
|
279
279
|
end
|
data/lib/rubocop/version.rb
CHANGED
@@ -3,10 +3,11 @@
|
|
3
3
|
module RuboCop
|
4
4
|
# This module holds the RuboCop version information.
|
5
5
|
module Version
|
6
|
-
STRING = '1.
|
6
|
+
STRING = '1.68.0'
|
7
7
|
|
8
8
|
MSG = '%<version>s (using %<parser_version>s, ' \
|
9
9
|
'rubocop-ast %<rubocop_ast_version>s, ' \
|
10
|
+
'analyzing as Ruby %<target_ruby_version>s, ' \
|
10
11
|
'running on %<ruby_engine>s %<ruby_version>s)%<server_mode>s [%<ruby_platform>s]'
|
11
12
|
|
12
13
|
CANONICAL_FEATURE_NAMES = {
|
@@ -17,11 +18,13 @@ module RuboCop
|
|
17
18
|
'rubocop-md' => 'markdown', 'rubocop-factory_bot' => 'factory_bot'
|
18
19
|
}.freeze
|
19
20
|
|
21
|
+
# NOTE: Marked as private but used by gems like standard.
|
20
22
|
# @api private
|
21
23
|
def self.version(debug: false, env: nil)
|
22
24
|
if debug
|
23
25
|
verbose_version = format(MSG, version: STRING, parser_version: parser_version,
|
24
26
|
rubocop_ast_version: RuboCop::AST::Version::STRING,
|
27
|
+
target_ruby_version: target_ruby_version(env),
|
25
28
|
ruby_engine: RUBY_ENGINE, ruby_version: RUBY_VERSION,
|
26
29
|
server_mode: server_mode,
|
27
30
|
ruby_platform: RUBY_PLATFORM)
|
@@ -39,6 +42,11 @@ module RuboCop
|
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
45
|
+
# @api private
|
46
|
+
def self.verbose(env: nil)
|
47
|
+
version(debug: true, env: env)
|
48
|
+
end
|
49
|
+
|
42
50
|
# @api private
|
43
51
|
def self.parser_version
|
44
52
|
config_path = ConfigFinder.find_config_path(Dir.pwd)
|
@@ -56,12 +64,7 @@ module RuboCop
|
|
56
64
|
|
57
65
|
# @api private
|
58
66
|
def self.extension_versions(env)
|
59
|
-
features =
|
60
|
-
# Suppress any config issues when loading the config (ie. deprecations,
|
61
|
-
# pending cops, etc.).
|
62
|
-
env.config_store.unvalidated.for_pwd.loaded_features.sort
|
63
|
-
end
|
64
|
-
|
67
|
+
features = config_for_pwd(env).loaded_features.sort
|
65
68
|
features.filter_map do |loaded_feature|
|
66
69
|
next unless (match = loaded_feature.match(/rubocop-(?<feature>.*)/))
|
67
70
|
|
@@ -83,6 +86,24 @@ module RuboCop
|
|
83
86
|
end
|
84
87
|
end
|
85
88
|
|
89
|
+
# @api private
|
90
|
+
def self.target_ruby_version(env)
|
91
|
+
if env
|
92
|
+
config_for_pwd(env).target_ruby_version
|
93
|
+
else
|
94
|
+
TargetRuby.new(Config.new).version
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# @api private
|
99
|
+
def self.config_for_pwd(env)
|
100
|
+
Util.silence_warnings do
|
101
|
+
# Suppress any config issues when loading the config (ie. deprecations,
|
102
|
+
# pending cops, etc.).
|
103
|
+
env.config_store.unvalidated.for_pwd
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
86
107
|
# Returns feature version in one of two ways:
|
87
108
|
#
|
88
109
|
# * Find by RuboCop core version style (e.g. rubocop-performance, rubocop-rspec)
|