rubocop 0.77.0 → 0.81.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +3 -3
  4. data/config/default.yml +136 -60
  5. data/lib/rubocop.rb +20 -4
  6. data/lib/rubocop/ast/builder.rb +45 -42
  7. data/lib/rubocop/ast/node.rb +11 -18
  8. data/lib/rubocop/ast/node/block_node.rb +5 -1
  9. data/lib/rubocop/ast/node/case_match_node.rb +56 -0
  10. data/lib/rubocop/ast/node/def_node.rb +11 -0
  11. data/lib/rubocop/ast/node/forward_args_node.rb +18 -0
  12. data/lib/rubocop/ast/node/regexp_node.rb +2 -4
  13. data/lib/rubocop/ast/traversal.rb +29 -10
  14. data/lib/rubocop/cli/command/auto_genenerate_config.rb +7 -7
  15. data/lib/rubocop/cli/command/show_cops.rb +11 -4
  16. data/lib/rubocop/comment_config.rb +6 -1
  17. data/lib/rubocop/config.rb +28 -10
  18. data/lib/rubocop/config_loader.rb +19 -19
  19. data/lib/rubocop/config_obsoletion.rb +6 -4
  20. data/lib/rubocop/config_validator.rb +55 -95
  21. data/lib/rubocop/cop/autocorrect_logic.rb +7 -4
  22. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +2 -2
  23. data/lib/rubocop/cop/cop.rb +3 -1
  24. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  25. data/lib/rubocop/cop/generator.rb +3 -4
  26. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  27. data/lib/rubocop/cop/layout/array_alignment.rb +53 -10
  28. data/lib/rubocop/cop/layout/block_end_newline.rb +5 -3
  29. data/lib/rubocop/cop/layout/else_alignment.rb +8 -0
  30. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
  31. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
  32. data/lib/rubocop/cop/layout/hash_alignment.rb +8 -4
  33. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -4
  34. data/lib/rubocop/cop/layout/leading_comment_space.rb +33 -2
  35. data/lib/rubocop/cop/{metrics → layout}/line_length.rb +35 -79
  36. data/lib/rubocop/cop/layout/multiline_block_layout.rb +14 -5
  37. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
  38. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  39. data/lib/rubocop/cop/layout/space_around_operators.rb +49 -6
  40. data/lib/rubocop/cop/layout/space_before_block_braces.rb +17 -0
  41. data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
  42. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
  43. data/lib/rubocop/cop/lint/boolean_symbol.rb +12 -0
  44. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  45. data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
  46. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  47. data/lib/rubocop/cop/lint/loop.rb +6 -4
  48. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  49. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +89 -0
  50. data/lib/rubocop/cop/lint/raise_exception.rb +39 -0
  51. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -3
  52. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +13 -8
  53. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
  54. data/lib/rubocop/cop/lint/struct_new_override.rb +58 -0
  55. data/lib/rubocop/cop/lint/suppressed_exception.rb +12 -22
  56. data/lib/rubocop/cop/lint/unused_method_argument.rb +32 -6
  57. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -0
  58. data/lib/rubocop/cop/migration/department_name.rb +47 -6
  59. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  60. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
  61. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +6 -1
  62. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +7 -7
  63. data/lib/rubocop/cop/mixin/hash_transform_method.rb +171 -0
  64. data/lib/rubocop/cop/mixin/line_length_help.rb +88 -0
  65. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -0
  66. data/lib/rubocop/cop/mixin/rational_literal.rb +18 -0
  67. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
  68. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -12
  69. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  70. data/lib/rubocop/cop/naming/method_name.rb +30 -0
  71. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  72. data/lib/rubocop/cop/offense.rb +11 -0
  73. data/lib/rubocop/cop/registry.rb +7 -2
  74. data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -6
  75. data/lib/rubocop/cop/style/attr.rb +8 -0
  76. data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
  77. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  78. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
  79. data/lib/rubocop/cop/style/documentation.rb +43 -5
  80. data/lib/rubocop/cop/style/end_block.rb +6 -0
  81. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
  82. data/lib/rubocop/cop/style/guard_clause.rb +3 -2
  83. data/lib/rubocop/cop/style/hash_each_methods.rb +89 -0
  84. data/lib/rubocop/cop/style/hash_transform_keys.rb +83 -0
  85. data/lib/rubocop/cop/style/hash_transform_values.rb +83 -0
  86. data/lib/rubocop/cop/style/if_unless_modifier.rb +38 -3
  87. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  88. data/lib/rubocop/cop/style/inverse_methods.rb +9 -5
  89. data/lib/rubocop/cop/style/lambda.rb +1 -0
  90. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -205
  91. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +169 -0
  92. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +54 -0
  93. data/lib/rubocop/cop/style/module_function.rb +56 -10
  94. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
  95. data/lib/rubocop/cop/style/multiline_when_then.rb +5 -1
  96. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -4
  97. data/lib/rubocop/cop/style/numeric_predicate.rb +4 -3
  98. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -2
  99. data/lib/rubocop/cop/style/or_assignment.rb +3 -2
  100. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +7 -7
  101. data/lib/rubocop/cop/style/redundant_condition.rb +17 -4
  102. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  103. data/lib/rubocop/cop/style/symbol_array.rb +2 -2
  104. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  105. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +34 -22
  106. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +41 -0
  107. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +85 -0
  108. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +44 -0
  109. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +7 -1
  110. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  111. data/lib/rubocop/cop/style/yoda_condition.rb +16 -1
  112. data/lib/rubocop/cop/variable_force.rb +4 -1
  113. data/lib/rubocop/formatter/base_formatter.rb +2 -2
  114. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  115. data/lib/rubocop/formatter/formatter_set.rb +1 -0
  116. data/lib/rubocop/formatter/json_formatter.rb +6 -5
  117. data/lib/rubocop/formatter/junit_formatter.rb +74 -0
  118. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  119. data/lib/rubocop/node_pattern.rb +97 -11
  120. data/lib/rubocop/options.rb +8 -8
  121. data/lib/rubocop/processed_source.rb +1 -1
  122. data/lib/rubocop/result_cache.rb +2 -0
  123. data/lib/rubocop/rspec/shared_contexts.rb +5 -0
  124. data/lib/rubocop/runner.rb +5 -1
  125. data/lib/rubocop/target_ruby.rb +151 -0
  126. data/lib/rubocop/version.rb +1 -1
  127. metadata +38 -10
  128. data/lib/rubocop/cop/lint/end_in_method.rb +0 -40
  129. 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[0].children[0] || ''
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 Metrics/LineLength
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 Metrics/LineLength
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 # rubocop:disable Lint/SuppressedException
32
+ rescue IndexError
33
33
  # range is not on a valid line; perhaps the source file is empty
34
34
  end
35
35
  end
@@ -17,6 +17,7 @@ module RuboCop
17
17
  '[fu]ubar' => FuubarStyleFormatter,
18
18
  '[h]tml' => HTMLFormatter,
19
19
  '[j]son' => JSONFormatter,
20
+ '[ju]nit' => JUnitFormatter,
20
21
  '[o]ffenses' => OffenseCountFormatter,
21
22
  '[pa]cman' => PacmanFormatter,
22
23
  '[p]rogress' => ProgressFormatter,
@@ -53,11 +53,12 @@ module RuboCop
53
53
 
54
54
  def hash_for_offense(offense)
55
55
  {
56
- severity: offense.severity.name,
57
- message: offense.message,
58
- cop_name: offense.cop_name,
59
- corrected: offense.corrected?,
60
- location: hash_for_location(offense)
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 # rubocop:disable Lint/SuppressedException
59
+ rescue IndexError
60
60
  # range is not on a valid line; perhaps the source file is empty
61
61
  end
62
62
  end
@@ -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 number
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 can not start with <' \
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} == temp#{@unify[name]}"
577
+ "#{CUR_ELEMENT} == #{access_unify(name)}"
507
578
  else
508
- n = @unify[name] = next_temp_value
509
- # double assign to temp#{n} to avoid "assigned but unused variable"
510
- "(temp#{n} = #{CUR_ELEMENT}; " \
511
- "temp#{n} = temp#{n}; true)"
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 = token[1..-1]
564
- number = @unify[name] || fail_due_to('invalid in arglist: ' + token)
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
@@ -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 can ' \
268
- 'not be used with --only.'
267
+ raise OptionArgumentError, 'Lint/RedundantCopDisableDirective cannot ' \
268
+ 'be used with --only.'
269
269
  end
270
270
  if except_syntax?
271
- raise OptionArgumentError, 'Syntax checking can not be turned off.'
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 can not be used with ' \
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 can not be combined with -F/--fail-fast.',
333
- auto_correct: '-P/--parallel can not be combined with --auto-correct.'
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 Metrics/LineLength
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 Metrics/LineLength
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 # rubocop:disable Lint/SuppressedException
166
+ rescue Parser::SyntaxError
167
167
  # All errors are in diagnostics. No need to handle exception.
168
168
  end
169
169
 
@@ -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
@@ -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 can not use caching.
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