rubocop 0.77.0 → 0.81.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.
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