rubocop 0.77.0 → 0.81.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +3 -3
- data/config/default.yml +136 -60
- data/lib/rubocop.rb +20 -4
- data/lib/rubocop/ast/builder.rb +45 -42
- data/lib/rubocop/ast/node.rb +11 -18
- data/lib/rubocop/ast/node/block_node.rb +5 -1
- data/lib/rubocop/ast/node/case_match_node.rb +56 -0
- data/lib/rubocop/ast/node/def_node.rb +11 -0
- data/lib/rubocop/ast/node/forward_args_node.rb +18 -0
- data/lib/rubocop/ast/node/regexp_node.rb +2 -4
- data/lib/rubocop/ast/traversal.rb +29 -10
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +7 -7
- data/lib/rubocop/cli/command/show_cops.rb +11 -4
- data/lib/rubocop/comment_config.rb +6 -1
- data/lib/rubocop/config.rb +28 -10
- data/lib/rubocop/config_loader.rb +19 -19
- data/lib/rubocop/config_obsoletion.rb +6 -4
- data/lib/rubocop/config_validator.rb +55 -95
- data/lib/rubocop/cop/autocorrect_logic.rb +7 -4
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +2 -2
- data/lib/rubocop/cop/cop.rb +3 -1
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/generator.rb +3 -4
- data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
- data/lib/rubocop/cop/layout/array_alignment.rb +53 -10
- data/lib/rubocop/cop/layout/block_end_newline.rb +5 -3
- data/lib/rubocop/cop/layout/else_alignment.rb +8 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/hash_alignment.rb +8 -4
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -4
- data/lib/rubocop/cop/layout/leading_comment_space.rb +33 -2
- data/lib/rubocop/cop/{metrics → layout}/line_length.rb +35 -79
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +14 -5
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +49 -6
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +17 -0
- data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
- data/lib/rubocop/cop/lint/boolean_symbol.rb +12 -0
- data/lib/rubocop/cop/lint/debugger.rb +1 -1
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/loop.rb +6 -4
- data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +89 -0
- data/lib/rubocop/cop/lint/raise_exception.rb +39 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -3
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +13 -8
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +58 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +12 -22
- data/lib/rubocop/cop/lint/unused_method_argument.rb +32 -6
- data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -0
- data/lib/rubocop/cop/migration/department_name.rb +47 -6
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +6 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +7 -7
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +171 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +88 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +5 -0
- data/lib/rubocop/cop/mixin/rational_literal.rb +18 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -12
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +30 -0
- data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +11 -0
- data/lib/rubocop/cop/registry.rb +7 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -6
- data/lib/rubocop/cop/style/attr.rb +8 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
- data/lib/rubocop/cop/style/documentation.rb +43 -5
- data/lib/rubocop/cop/style/end_block.rb +6 -0
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
- data/lib/rubocop/cop/style/guard_clause.rb +3 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +89 -0
- data/lib/rubocop/cop/style/hash_transform_keys.rb +83 -0
- data/lib/rubocop/cop/style/hash_transform_values.rb +83 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +38 -3
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +9 -5
- data/lib/rubocop/cop/style/lambda.rb +1 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -205
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +169 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +54 -0
- data/lib/rubocop/cop/style/module_function.rb +56 -10
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +5 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -4
- data/lib/rubocop/cop/style/numeric_predicate.rb +4 -3
- data/lib/rubocop/cop/style/one_line_conditional.rb +3 -2
- data/lib/rubocop/cop/style/or_assignment.rb +3 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +7 -7
- data/lib/rubocop/cop/style/redundant_condition.rb +17 -4
- data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
- data/lib/rubocop/cop/style/symbol_array.rb +2 -2
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +34 -22
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +41 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +85 -0
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +44 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +7 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +16 -1
- data/lib/rubocop/cop/variable_force.rb +4 -1
- data/lib/rubocop/formatter/base_formatter.rb +2 -2
- data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/formatter_set.rb +1 -0
- data/lib/rubocop/formatter/json_formatter.rb +6 -5
- data/lib/rubocop/formatter/junit_formatter.rb +74 -0
- data/lib/rubocop/formatter/tap_formatter.rb +1 -1
- data/lib/rubocop/node_pattern.rb +97 -11
- data/lib/rubocop/options.rb +8 -8
- data/lib/rubocop/processed_source.rb +1 -1
- data/lib/rubocop/result_cache.rb +2 -0
- data/lib/rubocop/rspec/shared_contexts.rb +5 -0
- data/lib/rubocop/runner.rb +5 -1
- data/lib/rubocop/target_ruby.rb +151 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +38 -10
- data/lib/rubocop/cop/lint/end_in_method.rb +0 -40
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +0 -209
@@ -190,7 +190,10 @@ module RuboCop
|
|
190
190
|
end
|
191
191
|
|
192
192
|
def regexp_captured_names(node)
|
193
|
-
regexp_string = node.children
|
193
|
+
regexp_string = node.children.select(&:str_type?).map do |child|
|
194
|
+
child.children.first
|
195
|
+
end.join || ''
|
196
|
+
|
194
197
|
regexp = Regexp.new(regexp_string)
|
195
198
|
|
196
199
|
regexp.named_captures.keys
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# rubocop:disable
|
3
|
+
# rubocop:disable Layout/LineLength
|
4
4
|
|
5
5
|
module RuboCop
|
6
6
|
module Formatter
|
@@ -41,7 +41,7 @@ module RuboCop
|
|
41
41
|
# * `#finished`
|
42
42
|
#
|
43
43
|
class BaseFormatter
|
44
|
-
# rubocop:enable
|
44
|
+
# rubocop:enable Layout/LineLength
|
45
45
|
|
46
46
|
# @api public
|
47
47
|
#
|
@@ -29,7 +29,7 @@ module RuboCop
|
|
29
29
|
|
30
30
|
report_line(offense.location)
|
31
31
|
report_highlighted_area(offense.highlighted_area)
|
32
|
-
rescue IndexError
|
32
|
+
rescue IndexError
|
33
33
|
# range is not on a valid line; perhaps the source file is empty
|
34
34
|
end
|
35
35
|
end
|
@@ -53,11 +53,12 @@ module RuboCop
|
|
53
53
|
|
54
54
|
def hash_for_offense(offense)
|
55
55
|
{
|
56
|
-
severity:
|
57
|
-
message:
|
58
|
-
cop_name:
|
59
|
-
corrected:
|
60
|
-
|
56
|
+
severity: offense.severity.name,
|
57
|
+
message: offense.message,
|
58
|
+
cop_name: offense.cop_name,
|
59
|
+
corrected: offense.corrected?,
|
60
|
+
correctable: offense.correctable?,
|
61
|
+
location: hash_for_location(offense)
|
61
62
|
}
|
62
63
|
end
|
63
64
|
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
#
|
6
|
+
# This code is based on https://github.com/mikian/rubocop-junit-formatter.
|
7
|
+
#
|
8
|
+
# Copyright (c) 2015 Mikko Kokkonen
|
9
|
+
#
|
10
|
+
# MIT License
|
11
|
+
#
|
12
|
+
# https://github.com/mikian/rubocop-junit-formatter/blob/master/LICENSE.txt
|
13
|
+
#
|
14
|
+
module RuboCop
|
15
|
+
module Formatter
|
16
|
+
# This formatter formats the report data in JUnit format.
|
17
|
+
class JUnitFormatter < BaseFormatter
|
18
|
+
def initialize(output, options = {})
|
19
|
+
super
|
20
|
+
|
21
|
+
@document = REXML::Document.new.tap do |document|
|
22
|
+
document << REXML::XMLDecl.new
|
23
|
+
end
|
24
|
+
testsuites = REXML::Element.new('testsuites', @document)
|
25
|
+
testsuite = REXML::Element.new('testsuite', testsuites)
|
26
|
+
@testsuite = testsuite.tap do |element|
|
27
|
+
element.add_attributes('name' => 'rubocop')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def file_finished(file, offenses)
|
32
|
+
# TODO: Returns all cops with the same behavior as
|
33
|
+
# the original rubocop-junit-formatter.
|
34
|
+
# https://github.com/mikian/rubocop-junit-formatter/blob/v0.1.4/lib/rubocop/formatter/junit_formatter.rb#L9
|
35
|
+
#
|
36
|
+
# In the future, it would be preferable to return only enabled cops.
|
37
|
+
Cop::Cop.all.each do |cop|
|
38
|
+
REXML::Element.new('testcase', @testsuite).tap do |testcase|
|
39
|
+
testcase.attributes['classname'] = classname_attribute_value(file)
|
40
|
+
testcase.attributes['name'] = cop.cop_name
|
41
|
+
|
42
|
+
target_offenses = offenses.select do |offense|
|
43
|
+
offense.cop_name == cop.cop_name
|
44
|
+
end
|
45
|
+
|
46
|
+
add_failure_to(testcase, target_offenses, cop.cop_name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def classname_attribute_value(file)
|
52
|
+
file.gsub(/\.rb\Z/, '').gsub("#{Dir.pwd}/", '').tr('/', '.')
|
53
|
+
end
|
54
|
+
|
55
|
+
def finished(_inspected_files)
|
56
|
+
@document.write(output, 2)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def add_failure_to(testcase, offenses, cop_name)
|
62
|
+
# One failure per offense. Zero failures is a passing test case,
|
63
|
+
# for most surefire/nUnit parsers.
|
64
|
+
offenses.each do |offense|
|
65
|
+
REXML::Element.new('failure', testcase).tap do |failure|
|
66
|
+
failure.attributes['type'] = cop_name
|
67
|
+
failure.attributes['message'] = offense.message
|
68
|
+
failure.add_text(offense.location.to_s)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -56,7 +56,7 @@ module RuboCop
|
|
56
56
|
|
57
57
|
report_line(offense.location)
|
58
58
|
report_highlighted_area(offense.highlighted_area)
|
59
|
-
rescue IndexError
|
59
|
+
rescue IndexError
|
60
60
|
# range is not on a valid line; perhaps the source file is empty
|
61
61
|
end
|
62
62
|
end
|
data/lib/rubocop/node_pattern.rb
CHANGED
@@ -78,6 +78,8 @@ module RuboCop
|
|
78
78
|
# # matching process starts
|
79
79
|
# '^^send' # each ^ ascends one level in the AST
|
80
80
|
# # so this matches against the grandparent node
|
81
|
+
# '`send' # descends any number of level in the AST
|
82
|
+
# # so this matches against any descendant node
|
81
83
|
# '#method' # we call this a 'funcall'; it calls a method in the
|
82
84
|
# # context where a pattern-matching method is defined
|
83
85
|
# # if that returns a truthy value, the match succeeds
|
@@ -112,7 +114,7 @@ module RuboCop
|
|
112
114
|
SYMBOL = %r{:(?:[\w+@*/?!<>=~|%^-]+|\[\]=?)}.freeze
|
113
115
|
IDENTIFIER = /[a-zA-Z_][a-zA-Z0-9_-]*/.freeze
|
114
116
|
META = Regexp.union(
|
115
|
-
%w"( ) { } [ ] $< < > $... $ ! ^ ... + * ?"
|
117
|
+
%w"( ) { } [ ] $< < > $... $ ! ^ ` ... + * ?"
|
116
118
|
).freeze
|
117
119
|
NUMBER = /-?\d+(?:\.\d+)?/.freeze
|
118
120
|
STRING = /".+?"/.freeze
|
@@ -188,7 +190,7 @@ module RuboCop
|
|
188
190
|
|
189
191
|
@temps = 0 # avoid name clashes between temp variables
|
190
192
|
@captures = 0 # number of captures seen
|
191
|
-
@unify = {} # named wildcard -> temp variable
|
193
|
+
@unify = {} # named wildcard -> temp variable
|
192
194
|
@params = 0 # highest % (param) number seen
|
193
195
|
run(node_var)
|
194
196
|
end
|
@@ -223,6 +225,7 @@ module RuboCop
|
|
223
225
|
when '!' then compile_negation
|
224
226
|
when '$' then compile_capture
|
225
227
|
when '^' then compile_ascend
|
228
|
+
when '`' then compile_descend
|
226
229
|
when WILDCARD then compile_wildcard(token[1..-1])
|
227
230
|
when FUNCALL then compile_funcall(token)
|
228
231
|
when LITERAL then compile_literal(token)
|
@@ -380,7 +383,7 @@ module RuboCop
|
|
380
383
|
def compile_seq_head
|
381
384
|
return unless seq_head?
|
382
385
|
|
383
|
-
fail_due_to 'sequences
|
386
|
+
fail_due_to 'sequences cannot start with <' \
|
384
387
|
if @terms[0].respond_to? :call
|
385
388
|
|
386
389
|
with_seq_head_context(@terms[0])
|
@@ -466,12 +469,67 @@ module RuboCop
|
|
466
469
|
end
|
467
470
|
end
|
468
471
|
|
472
|
+
def access_unify(name)
|
473
|
+
var = @unify[name]
|
474
|
+
|
475
|
+
if var == :forbidden_unification
|
476
|
+
fail_due_to "Wildcard #{name} was first seen in a subset of a" \
|
477
|
+
" union and can't be used outside that union"
|
478
|
+
end
|
479
|
+
var
|
480
|
+
end
|
481
|
+
|
482
|
+
def forbid_unification(*names)
|
483
|
+
names.each do |name|
|
484
|
+
@unify[name] = :forbidden_unification
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
489
|
+
def unify_in_union(enum)
|
490
|
+
# We need to reset @unify before each branch is processed.
|
491
|
+
# Moreover we need to keep track of newly encountered wildcards.
|
492
|
+
# Var `new_unify_intersection` will hold those that are encountered
|
493
|
+
# in all branches; these are not a problem.
|
494
|
+
# Var `partial_unify` will hold those encountered in only a subset
|
495
|
+
# of the branches; these can't be used outside of the union.
|
496
|
+
|
497
|
+
return to_enum __method__, enum unless block_given?
|
498
|
+
|
499
|
+
new_unify_intersection = nil
|
500
|
+
partial_unify = []
|
501
|
+
unify_before = @unify.dup
|
502
|
+
|
503
|
+
result = enum.each do |e|
|
504
|
+
@unify = unify_before.dup if new_unify_intersection
|
505
|
+
yield e
|
506
|
+
new_unify = @unify.keys - unify_before.keys
|
507
|
+
if new_unify_intersection.nil?
|
508
|
+
# First iteration
|
509
|
+
new_unify_intersection = new_unify
|
510
|
+
else
|
511
|
+
union = new_unify_intersection | new_unify
|
512
|
+
new_unify_intersection &= new_unify
|
513
|
+
partial_unify |= union - new_unify_intersection
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
# At this point, all members of `new_unify_intersection` can be used
|
518
|
+
# for unification outside of the union, but partial_unify may not
|
519
|
+
|
520
|
+
forbid_unification(*partial_unify)
|
521
|
+
|
522
|
+
result
|
523
|
+
end
|
524
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
525
|
+
|
469
526
|
def compile_union
|
470
527
|
# we need to ensure that each branch of the {} contains the same
|
471
528
|
# number of captures (since only one branch of the {} can actually
|
472
529
|
# match, the same variables are used to hold the captures for each
|
473
530
|
# branch)
|
474
531
|
enum = tokens_until('}', 'union')
|
532
|
+
enum = unify_in_union(enum)
|
475
533
|
terms = insure_same_captures(enum, 'branch of {}')
|
476
534
|
.map { compile_expr }
|
477
535
|
|
@@ -496,6 +554,19 @@ module RuboCop
|
|
496
554
|
with_context("#{CUR_NODE} && #{compile_expr}", "#{CUR_NODE}.parent")
|
497
555
|
end
|
498
556
|
|
557
|
+
def compile_descend
|
558
|
+
with_temp_variables do |descendant|
|
559
|
+
pattern = with_context(compile_expr, descendant,
|
560
|
+
use_temp_node: false)
|
561
|
+
[
|
562
|
+
"RuboCop::NodePattern.descend(#{CUR_ELEMENT}).",
|
563
|
+
"any? do |#{descendant}|",
|
564
|
+
" #{pattern}",
|
565
|
+
'end'
|
566
|
+
].join("\n")
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
499
570
|
def compile_wildcard(name)
|
500
571
|
if name.empty?
|
501
572
|
'true'
|
@@ -503,12 +574,12 @@ module RuboCop
|
|
503
574
|
# we have already seen a wildcard with this name before
|
504
575
|
# so the value it matched the first time will already be stored
|
505
576
|
# in a temp. check if this value matches the one stored in the temp
|
506
|
-
"#{CUR_ELEMENT} ==
|
577
|
+
"#{CUR_ELEMENT} == #{access_unify(name)}"
|
507
578
|
else
|
508
|
-
n = @unify[name] =
|
509
|
-
# double assign to
|
510
|
-
"(
|
511
|
-
"
|
579
|
+
n = @unify[name] = "unify_#{name.gsub('-', '__')}"
|
580
|
+
# double assign to avoid "assigned but unused variable"
|
581
|
+
"(#{n} = #{CUR_ELEMENT}; " \
|
582
|
+
"#{n} = #{n}; true)"
|
512
583
|
end
|
513
584
|
end
|
514
585
|
|
@@ -560,9 +631,8 @@ module RuboCop
|
|
560
631
|
def compile_arg(token)
|
561
632
|
case token
|
562
633
|
when WILDCARD then
|
563
|
-
name
|
564
|
-
|
565
|
-
"temp#{number}"
|
634
|
+
name = token[1..-1]
|
635
|
+
access_unify(name) || fail_due_to('invalid in arglist: ' + token)
|
566
636
|
when LITERAL then token
|
567
637
|
when PARAM then get_param(token[1..-1])
|
568
638
|
when CLOSING then fail_due_to("#{token} in invalid position")
|
@@ -796,6 +866,22 @@ module RuboCop
|
|
796
866
|
def to_s
|
797
867
|
"#<#{self.class} #{pattern}>"
|
798
868
|
end
|
869
|
+
|
870
|
+
# Yields its argument and any descendants, depth-first.
|
871
|
+
#
|
872
|
+
def self.descend(element, &block)
|
873
|
+
return to_enum(__method__, element) unless block_given?
|
874
|
+
|
875
|
+
yield element
|
876
|
+
|
877
|
+
if element.is_a?(::RuboCop::AST::Node)
|
878
|
+
element.children.each do |child|
|
879
|
+
descend(child, &block)
|
880
|
+
end
|
881
|
+
end
|
882
|
+
|
883
|
+
nil
|
884
|
+
end
|
799
885
|
end
|
800
886
|
end
|
801
887
|
# rubocop:enable Metrics/ClassLength, Metrics/CyclomaticComplexity
|
data/lib/rubocop/options.rb
CHANGED
@@ -264,18 +264,18 @@ module RuboCop
|
|
264
264
|
# rubocop:disable Metrics/AbcSize
|
265
265
|
def validate_compatibility # rubocop:disable Metrics/MethodLength
|
266
266
|
if only_includes_redundant_disable?
|
267
|
-
raise OptionArgumentError, 'Lint/RedundantCopDisableDirective
|
268
|
-
'
|
267
|
+
raise OptionArgumentError, 'Lint/RedundantCopDisableDirective cannot ' \
|
268
|
+
'be used with --only.'
|
269
269
|
end
|
270
270
|
if except_syntax?
|
271
|
-
raise OptionArgumentError, 'Syntax checking
|
271
|
+
raise OptionArgumentError, 'Syntax checking cannot be turned off.'
|
272
272
|
end
|
273
273
|
unless boolean_or_empty_cache?
|
274
274
|
raise OptionArgumentError, '-C/--cache argument must be true or false'
|
275
275
|
end
|
276
276
|
|
277
277
|
if display_only_fail_level_offenses_with_autocorrect?
|
278
|
-
raise OptionArgumentError, '--autocorrect
|
278
|
+
raise OptionArgumentError, '--autocorrect cannot be used with ' \
|
279
279
|
'--display-only-fail-level-offenses'
|
280
280
|
end
|
281
281
|
validate_auto_gen_config
|
@@ -329,8 +329,8 @@ module RuboCop
|
|
329
329
|
auto_gen_config: '-P/--parallel uses caching to speed up execution, ' \
|
330
330
|
'while --auto-gen-config needs a non-cached run, ' \
|
331
331
|
'so they cannot be combined.',
|
332
|
-
fail_fast: '-P/--parallel
|
333
|
-
auto_correct: '-P/--parallel
|
332
|
+
fail_fast: '-P/--parallel cannot be combined with -F/--fail-fast.',
|
333
|
+
auto_correct: '-P/--parallel cannot be combined with --auto-correct.'
|
334
334
|
}
|
335
335
|
|
336
336
|
combos.each do |key, msg|
|
@@ -373,7 +373,7 @@ module RuboCop
|
|
373
373
|
# This module contains help texts for command line options.
|
374
374
|
module OptionsHelp
|
375
375
|
MAX_EXCL = RuboCop::Options::DEFAULT_MAXIMUM_EXCLUSION_ITEMS.to_s
|
376
|
-
# rubocop:disable
|
376
|
+
# rubocop:disable Layout/LineLength
|
377
377
|
FORMATTER_OPTION_LIST = RuboCop::Formatter::FormatterSet::BUILTIN_FORMATTERS_FOR_KEYS.keys
|
378
378
|
|
379
379
|
TEXT = {
|
@@ -455,6 +455,6 @@ module RuboCop
|
|
455
455
|
'reports. This is useful for editor integration.'],
|
456
456
|
init: 'Generate a .rubocop.yml file in the current directory.'
|
457
457
|
}.freeze
|
458
|
-
# rubocop:enable
|
458
|
+
# rubocop:enable Layout/LineLength
|
459
459
|
end
|
460
460
|
end
|
@@ -163,7 +163,7 @@ module RuboCop
|
|
163
163
|
ast, comments, tokens = parser.tokenize(@buffer)
|
164
164
|
|
165
165
|
ast.respond_to?(:complete!) && ast.complete!
|
166
|
-
rescue Parser::SyntaxError
|
166
|
+
rescue Parser::SyntaxError
|
167
167
|
# All errors are in diagnostics. No need to handle exception.
|
168
168
|
end
|
169
169
|
|
data/lib/rubocop/result_cache.rb
CHANGED
@@ -186,6 +186,8 @@ module RuboCop
|
|
186
186
|
options.to_s.gsub(/[^a-z]+/i, '_')
|
187
187
|
end
|
188
188
|
|
189
|
+
# The external dependency checksums are cached per RuboCop team so that
|
190
|
+
# the checksums don't need to be recomputed for each file.
|
189
191
|
def team_checksum(team)
|
190
192
|
@checksum_by_team ||= {}
|
191
193
|
@checksum_by_team[team.object_id] ||= team.external_dependency_checksum
|
@@ -52,6 +52,7 @@ RSpec.shared_context 'config', :config do
|
|
52
52
|
cop_name = described_class.cop_name
|
53
53
|
hash[cop_name] = RuboCop::ConfigLoader
|
54
54
|
.default_configuration[cop_name]
|
55
|
+
.merge('Enabled' => true) # in case it is 'pending'
|
55
56
|
.merge(cop_config)
|
56
57
|
end
|
57
58
|
|
@@ -88,3 +89,7 @@ end
|
|
88
89
|
RSpec.shared_context 'ruby 2.6', :ruby26 do
|
89
90
|
let(:ruby_version) { 2.6 }
|
90
91
|
end
|
92
|
+
|
93
|
+
RSpec.shared_context 'ruby 2.7', :ruby27 do
|
94
|
+
let(:ruby_version) { 2.7 }
|
95
|
+
end
|
data/lib/rubocop/runner.rb
CHANGED
@@ -214,7 +214,7 @@ module RuboCop
|
|
214
214
|
@config_store.for(Dir.pwd).for_all_cops['UseCache']) &&
|
215
215
|
# When running --auto-gen-config, there's some processing done in the
|
216
216
|
# cops related to calculating the Max parameters for Metrics cops. We
|
217
|
-
# need to do that processing and
|
217
|
+
# need to do that processing and cannot use caching.
|
218
218
|
!@options[:auto_gen_config] &&
|
219
219
|
# We can't cache results from code which is piped in to stdin
|
220
220
|
!@options[:stdin]
|
@@ -366,6 +366,10 @@ module RuboCop
|
|
366
366
|
end
|
367
367
|
end
|
368
368
|
|
369
|
+
# A Cop::Team instance is stateful and may change when inspecting.
|
370
|
+
# The "standby" team for a given config is an initialized but
|
371
|
+
# otherwise dormant team that can be used for config- and option-
|
372
|
+
# level caching in ResultCache.
|
369
373
|
def standby_team(config)
|
370
374
|
@team_by_config ||= {}
|
371
375
|
@team_by_config[config.object_id] ||=
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# The kind of Ruby that code inspected by RuboCop is written in.
|
5
|
+
class TargetRuby
|
6
|
+
KNOWN_RUBIES = [2.3, 2.4, 2.5, 2.6, 2.7].freeze
|
7
|
+
DEFAULT_VERSION = KNOWN_RUBIES.first
|
8
|
+
|
9
|
+
OBSOLETE_RUBIES = {
|
10
|
+
1.9 => '0.50', 2.0 => '0.50', 2.1 => '0.58', 2.2 => '0.69'
|
11
|
+
}.freeze
|
12
|
+
private_constant :KNOWN_RUBIES, :OBSOLETE_RUBIES
|
13
|
+
|
14
|
+
# A place where information about a target ruby version is found.
|
15
|
+
class Source
|
16
|
+
attr_reader :version, :name
|
17
|
+
|
18
|
+
def initialize(config)
|
19
|
+
@config = config
|
20
|
+
@version = find_version
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# The target ruby version may be configured in RuboCop's config.
|
29
|
+
class RuboCopConfig < Source
|
30
|
+
def name
|
31
|
+
"`TargetRubyVersion` parameter (in #{@config.smart_loaded_path})"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def find_version
|
37
|
+
@config.for_all_cops['TargetRubyVersion']&.to_f
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# The target ruby version may be found in a .ruby-version file.
|
42
|
+
class RubyVersionFile < Source
|
43
|
+
FILENAME = '.ruby-version'
|
44
|
+
|
45
|
+
def name
|
46
|
+
"`#{FILENAME}`"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def find_version
|
52
|
+
file = ruby_version_file
|
53
|
+
return unless file && File.file?(file)
|
54
|
+
|
55
|
+
File.read(file).match(/\A(ruby-)?(?<version>\d+\.\d+)/) do |md|
|
56
|
+
md[:version].to_f
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ruby_version_file
|
61
|
+
@ruby_version_file ||=
|
62
|
+
@config.find_file_upwards(FILENAME,
|
63
|
+
@config.base_dir_for_path_parameters)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# The lock file of Bundler may identify the target ruby version.
|
68
|
+
class BundlerLockFile < Source
|
69
|
+
def name
|
70
|
+
"`#{bundler_lock_file_path}`"
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def find_version
|
76
|
+
lock_file_path = bundler_lock_file_path
|
77
|
+
return nil unless lock_file_path
|
78
|
+
|
79
|
+
in_ruby_section = false
|
80
|
+
File.foreach(lock_file_path) do |line|
|
81
|
+
# If ruby is in Gemfile.lock or gems.lock, there should be two lines
|
82
|
+
# towards the bottom of the file that look like:
|
83
|
+
# RUBY VERSION
|
84
|
+
# ruby W.X.YpZ
|
85
|
+
# We ultimately want to match the "ruby W.X.Y.pZ" line, but there's
|
86
|
+
# extra logic to make sure we only start looking once we've seen the
|
87
|
+
# "RUBY VERSION" line.
|
88
|
+
in_ruby_section ||= line.match(/^\s*RUBY\s*VERSION\s*$/)
|
89
|
+
next unless in_ruby_section
|
90
|
+
|
91
|
+
# We currently only allow this feature to work with MRI ruby. If
|
92
|
+
# jruby (or something else) is used by the project, it's lock file
|
93
|
+
# will have a line that looks like:
|
94
|
+
# RUBY VERSION
|
95
|
+
# ruby W.X.YpZ (jruby x.x.x.x)
|
96
|
+
# The regex won't match in this situation.
|
97
|
+
result = line.match(/^\s*ruby\s+(\d+\.\d+)[p.\d]*\s*$/)
|
98
|
+
return result.captures.first.to_f if result
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def bundler_lock_file_path
|
103
|
+
@config.bundler_lock_file_path
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# If all else fails, a default version will be picked.
|
108
|
+
class Default < Source
|
109
|
+
def name
|
110
|
+
'default'
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def find_version
|
116
|
+
DEFAULT_VERSION
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.supported_versions
|
121
|
+
KNOWN_RUBIES
|
122
|
+
end
|
123
|
+
|
124
|
+
SOURCES = [RuboCopConfig, RubyVersionFile, BundlerLockFile, Default].freeze
|
125
|
+
private_constant :SOURCES
|
126
|
+
|
127
|
+
def initialize(config)
|
128
|
+
@config = config
|
129
|
+
end
|
130
|
+
|
131
|
+
def source
|
132
|
+
@source ||= SOURCES.each.lazy.map { |c| c.new(@config) }.detect(&:version)
|
133
|
+
end
|
134
|
+
|
135
|
+
def version
|
136
|
+
source.version
|
137
|
+
end
|
138
|
+
|
139
|
+
def supported?
|
140
|
+
KNOWN_RUBIES.include?(version)
|
141
|
+
end
|
142
|
+
|
143
|
+
def rubocop_version_with_support
|
144
|
+
if supported?
|
145
|
+
RuboCop::Version.version
|
146
|
+
else
|
147
|
+
OBSOLETE_RUBIES[version]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|