rubocop 1.40.0 → 1.43.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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +52 -2
  5. data/lib/rubocop/cli.rb +1 -1
  6. data/lib/rubocop/config.rb +34 -11
  7. data/lib/rubocop/config_loader.rb +9 -0
  8. data/lib/rubocop/config_loader_resolver.rb +5 -1
  9. data/lib/rubocop/config_validator.rb +1 -1
  10. data/lib/rubocop/cop/badge.rb +9 -4
  11. data/lib/rubocop/cop/base.rb +83 -66
  12. data/lib/rubocop/cop/commissioner.rb +8 -3
  13. data/lib/rubocop/cop/cop.rb +29 -29
  14. data/lib/rubocop/cop/corrector.rb +23 -11
  15. data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
  16. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  17. data/lib/rubocop/cop/layout/class_structure.rb +32 -11
  18. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
  19. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  20. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  21. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  22. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  23. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  24. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  25. data/lib/rubocop/cop/layout/indentation_style.rb +7 -2
  26. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  27. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -5
  28. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  29. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  30. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  31. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  32. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  33. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  34. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  35. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  36. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  37. data/lib/rubocop/cop/layout/trailing_whitespace.rb +11 -4
  38. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  39. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  40. data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
  41. data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
  42. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  43. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
  44. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -1
  45. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  46. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  47. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
  48. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -19
  49. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  50. data/lib/rubocop/cop/lint/useless_rescue.rb +71 -0
  51. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -3
  52. data/lib/rubocop/cop/metrics/class_length.rb +1 -1
  53. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  54. data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
  55. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  56. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -4
  57. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  58. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  59. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
  60. data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
  61. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
  62. data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
  63. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -2
  64. data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
  65. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
  66. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
  67. data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
  68. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  69. data/lib/rubocop/cop/mixin/require_library.rb +2 -0
  70. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  71. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -1
  72. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  73. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  74. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  75. data/lib/rubocop/cop/registry.rb +28 -25
  76. data/lib/rubocop/cop/security/compound_hash.rb +2 -1
  77. data/lib/rubocop/cop/style/alias.rb +9 -1
  78. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  79. data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
  80. data/lib/rubocop/cop/style/documentation.rb +11 -5
  81. data/lib/rubocop/cop/style/guard_clause.rb +17 -9
  82. data/lib/rubocop/cop/style/hash_each_methods.rb +13 -1
  83. data/lib/rubocop/cop/style/hash_syntax.rb +11 -7
  84. data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
  85. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -3
  86. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  87. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  88. data/lib/rubocop/cop/style/map_to_set.rb +61 -0
  89. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -9
  90. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
  91. data/lib/rubocop/cop/style/min_max_comparison.rb +73 -0
  92. data/lib/rubocop/cop/style/missing_else.rb +13 -1
  93. data/lib/rubocop/cop/style/operator_method_call.rb +15 -1
  94. data/lib/rubocop/cop/style/redundant_constant_base.rb +13 -0
  95. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
  96. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  97. data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
  98. data/lib/rubocop/cop/style/require_order.rb +63 -9
  99. data/lib/rubocop/cop/style/select_by_regexp.rb +6 -2
  100. data/lib/rubocop/cop/style/semicolon.rb +2 -1
  101. data/lib/rubocop/cop/style/signal_exception.rb +8 -6
  102. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
  103. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
  104. data/lib/rubocop/cop/style/word_array.rb +41 -0
  105. data/lib/rubocop/cop/style/yoda_expression.rb +81 -0
  106. data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
  107. data/lib/rubocop/cop/team.rb +29 -29
  108. data/lib/rubocop/cop/util.rb +31 -4
  109. data/lib/rubocop/cop/variable_force.rb +0 -3
  110. data/lib/rubocop/cops_documentation_generator.rb +33 -11
  111. data/lib/rubocop/directive_comment.rb +1 -1
  112. data/lib/rubocop/file_patterns.rb +43 -0
  113. data/lib/rubocop/formatter.rb +2 -0
  114. data/lib/rubocop/options.rb +1 -1
  115. data/lib/rubocop/path_util.rb +38 -22
  116. data/lib/rubocop/result_cache.rb +1 -1
  117. data/lib/rubocop/runner.rb +10 -3
  118. data/lib/rubocop/target_finder.rb +1 -1
  119. data/lib/rubocop/target_ruby.rb +0 -1
  120. data/lib/rubocop/version.rb +1 -1
  121. data/lib/rubocop.rb +7 -1
  122. metadata +16 -10
  123. data/lib/rubocop/optimized_patterns.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb2b7b02733dca8e7577cd5ccd776044179cd762685152d9c7d5a739dd7cf9e1
4
- data.tar.gz: 47b6ef2704e65f30af91def68b22331aca13d629d954cc860288738dccd4f14d
3
+ metadata.gz: adbae8e6d8a8ad828f302b9d3bba545a8b7fe54727480077a1878d4c2109dbf3
4
+ data.tar.gz: fb30d554306879712c48bec3d389b4232ee8f8dde6d410dd139b73796a076d3d
5
5
  SHA512:
6
- metadata.gz: c65cd2840052b36832dec3218f2994b0dbaae5e482328c767b0f82ac3d882ce1a29a02ddd53e960c199514ff241d17d0c5f33b139b50634fce4c7fa246018a1c
7
- data.tar.gz: 51442c821afd72669bb0845386c1c05495618736b46978e1d2fae12f3f69f30ff914025209f6efc2c673692e585e4e2968fe76467f2433ba98f2209d435b46bd
6
+ metadata.gz: 7aa85cf4d34b4994422b5aa921d746b68bc282c97f7563affa2b2574a9b1102eefce4e10bed58801bb6ef9fb2ee2d3d563a63f5b114d754a69c872f6830a793e
7
+ data.tar.gz: 1e088db8ccb3cdcf2ab7b9e624b68bfc4513681e4cc8ee6bd69084dfa91fda775fc28483a4764962829230d6d2fd5726855299ba1ae622bf85cc66f55451c8c9
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-22 Bozhidar Batsov
1
+ Copyright (c) 2012-23 Bozhidar Batsov
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
53
53
  in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 1.40', require: false
56
+ gem 'rubocop', '~> 1.43', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -246,5 +246,5 @@ RuboCop's changelog is available [here](CHANGELOG.md).
246
246
 
247
247
  ## Copyright
248
248
 
249
- Copyright (c) 2012-2022 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
249
+ Copyright (c) 2012-2023 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
250
250
  further details.
data/config/default.yml CHANGED
@@ -762,6 +762,7 @@ Layout/FirstArrayElementLineBreak:
762
762
  multi-line array.
763
763
  Enabled: false
764
764
  VersionAdded: '0.49'
765
+ AllowMultilineFinalElement: false
765
766
 
766
767
  Layout/FirstHashElementIndentation:
767
768
  Description: 'Checks the indentation of the first key in a hash literal.'
@@ -794,6 +795,7 @@ Layout/FirstHashElementLineBreak:
794
795
  multi-line hash.
795
796
  Enabled: false
796
797
  VersionAdded: '0.49'
798
+ AllowMultilineFinalElement: false
797
799
 
798
800
  Layout/FirstMethodArgumentLineBreak:
799
801
  Description: >-
@@ -801,6 +803,7 @@ Layout/FirstMethodArgumentLineBreak:
801
803
  multi-line method call.
802
804
  Enabled: false
803
805
  VersionAdded: '0.49'
806
+ AllowMultilineFinalElement: false
804
807
 
805
808
  Layout/FirstMethodParameterLineBreak:
806
809
  Description: >-
@@ -808,6 +811,7 @@ Layout/FirstMethodParameterLineBreak:
808
811
  multi-line method parameter definition.
809
812
  Enabled: false
810
813
  VersionAdded: '0.49'
814
+ AllowMultilineFinalElement: false
811
815
 
812
816
  Layout/FirstParameterIndentation:
813
817
  Description: >-
@@ -1067,6 +1071,7 @@ Layout/MultilineArrayLineBreaks:
1067
1071
  starts on a separate line.
1068
1072
  Enabled: false
1069
1073
  VersionAdded: '0.67'
1074
+ AllowMultilineFinalElement: false
1070
1075
 
1071
1076
  Layout/MultilineAssignmentLayout:
1072
1077
  Description: 'Check for a newline after the assignment operator in multi-line assignments.'
@@ -1117,6 +1122,7 @@ Layout/MultilineHashKeyLineBreaks:
1117
1122
  starts on a separate line.
1118
1123
  Enabled: false
1119
1124
  VersionAdded: '0.67'
1125
+ AllowMultilineFinalElement: false
1120
1126
 
1121
1127
  Layout/MultilineMethodArgumentLineBreaks:
1122
1128
  Description: >-
@@ -1124,6 +1130,7 @@ Layout/MultilineMethodArgumentLineBreaks:
1124
1130
  starts on a separate line.
1125
1131
  Enabled: false
1126
1132
  VersionAdded: '0.67'
1133
+ AllowMultilineFinalElement: false
1127
1134
 
1128
1135
  Layout/MultilineMethodCallBraceLayout:
1129
1136
  Description: >-
@@ -1178,6 +1185,7 @@ Layout/MultilineMethodParameterLineBreaks:
1178
1185
  starts on a separate line.
1179
1186
  Enabled: false
1180
1187
  VersionAdded: '1.32'
1188
+ AllowMultilineFinalElement: false
1181
1189
 
1182
1190
  Layout/MultilineOperationIndentation:
1183
1191
  Description: >-
@@ -2444,6 +2452,11 @@ Lint/UselessMethodDefinition:
2444
2452
  VersionChanged: '0.91'
2445
2453
  Safe: false
2446
2454
 
2455
+ Lint/UselessRescue:
2456
+ Description: 'Checks for useless `rescue`s.'
2457
+ Enabled: pending
2458
+ VersionAdded: '1.43'
2459
+
2447
2460
  Lint/UselessRuby2Keywords:
2448
2461
  Description: 'Finds unnecessary uses of `ruby2_keywords`.'
2449
2462
  Enabled: pending
@@ -3418,6 +3431,12 @@ Style/CommentedKeyword:
3418
3431
  VersionAdded: '0.51'
3419
3432
  VersionChanged: '1.19'
3420
3433
 
3434
+ Style/ConcatArrayLiterals:
3435
+ Description: 'Enforces the use of `Array#push(item)` instead of `Array#concat([item])` to avoid redundant array literals.'
3436
+ Enabled: pending
3437
+ Safe: false
3438
+ VersionAdded: '1.41'
3439
+
3421
3440
  Style/ConditionalAssignment:
3422
3441
  Description: >-
3423
3442
  Use the return value of `if` and `case` statements for
@@ -3839,7 +3858,8 @@ Style/HashEachMethods:
3839
3858
  Safe: false
3840
3859
  VersionAdded: '0.80'
3841
3860
  VersionChanged: '1.16'
3842
- AllowedReceivers: []
3861
+ AllowedReceivers:
3862
+ - Thread.current
3843
3863
 
3844
3864
  Style/HashExcept:
3845
3865
  Description: >-
@@ -3887,7 +3907,7 @@ Style/HashSyntax:
3887
3907
  - never
3888
3908
  # accepts both shorthand and explicit use of hash literal value.
3889
3909
  - either
3890
- # like "either", but will avoid mixing styles in a single hash
3910
+ # forces use of the 3.1 syntax only if all values can be omitted in the hash.
3891
3911
  - consistent
3892
3912
  # Force hashes that have a symbol value to use hash rockets
3893
3913
  UseHashRocketsWithSymbolValues: false
@@ -4096,6 +4116,12 @@ Style/MapToHash:
4096
4116
  VersionAdded: '1.24'
4097
4117
  Safe: false
4098
4118
 
4119
+ Style/MapToSet:
4120
+ Description: 'Prefer `to_set` with a block over `map.to_set`.'
4121
+ Enabled: pending
4122
+ Safe: false
4123
+ VersionAdded: '1.42'
4124
+
4099
4125
  Style/MethodCallWithArgsParentheses:
4100
4126
  Description: 'Use parentheses for method calls with arguments.'
4101
4127
  StyleGuide: '#method-invocation-parens'
@@ -4154,6 +4180,12 @@ Style/MinMax:
4154
4180
  Enabled: true
4155
4181
  VersionAdded: '0.50'
4156
4182
 
4183
+ Style/MinMaxComparison:
4184
+ Description: 'Enforces the use of `max` or `min` instead of comparison for greater or less.'
4185
+ Enabled: pending
4186
+ Safe: false
4187
+ VersionAdded: '1.42'
4188
+
4157
4189
  Style/MissingElse:
4158
4190
  Description: >-
4159
4191
  Require if/case expressions to have an else branches.
@@ -4731,6 +4763,11 @@ Style/RedundantConstantBase:
4731
4763
  Enabled: pending
4732
4764
  VersionAdded: '1.40'
4733
4765
 
4766
+ Style/RedundantDoubleSplatHashBraces:
4767
+ Description: 'Checks for redundant uses of double splat hash braces.'
4768
+ Enabled: pending
4769
+ VersionAdded: '1.41'
4770
+
4734
4771
  Style/RedundantEach:
4735
4772
  Description: 'Checks for redundant `each`.'
4736
4773
  Enabled: pending
@@ -5407,6 +5444,19 @@ Style/YodaCondition:
5407
5444
  VersionAdded: '0.49'
5408
5445
  VersionChanged: '0.75'
5409
5446
 
5447
+ Style/YodaExpression:
5448
+ Description: 'Forbid the use of yoda expressions.'
5449
+ Enabled: false
5450
+ Safe: false
5451
+ VersionAdded: '1.42'
5452
+ VersionChanged: '1.43'
5453
+ SupportedOperators:
5454
+ - '*'
5455
+ - '+'
5456
+ - '&'
5457
+ - '|'
5458
+ - '^'
5459
+
5410
5460
  Style/ZeroLengthPredicate:
5411
5461
  Description: 'Use #empty? when testing for objects of length 0.'
5412
5462
  Enabled: true
data/lib/rubocop/cli.rb CHANGED
@@ -7,7 +7,7 @@ module RuboCop
7
7
  STATUS_SUCCESS = 0
8
8
  STATUS_OFFENSES = 1
9
9
  STATUS_ERROR = 2
10
- STATUS_INTERRUPTED = 128 + Signal.list['INT']
10
+ STATUS_INTERRUPTED = Signal.list['INT'] + 128
11
11
  DEFAULT_PARALLEL_OPTIONS = %i[
12
12
  color debug display_style_guide display_time display_only_fail_level_offenses
13
13
  display_only_failed except extra_details fail_level fix_layout format
@@ -21,6 +21,14 @@ module RuboCop
21
21
  DEFAULT_RAILS_VERSION = 5.0
22
22
  attr_reader :loaded_path
23
23
 
24
+ def self.create(hash, path, check: true)
25
+ config = new(hash, path)
26
+ config.check if check
27
+
28
+ config
29
+ end
30
+
31
+ # rubocop:disable Metrics/AbcSize
24
32
  def initialize(hash = {}, loaded_path = nil)
25
33
  @loaded_path = loaded_path
26
34
  @for_cop = Hash.new do |h, cop|
@@ -32,14 +40,11 @@ module RuboCop
32
40
  end
33
41
  @hash = hash
34
42
  @validator = ConfigValidator.new(self)
35
- end
36
43
 
37
- def self.create(hash, path, check: true)
38
- config = new(hash, path)
39
- config.check if check
40
-
41
- config
44
+ @badge_config_cache = {}.compare_by_identity
45
+ @clusivity_config_exists_cache = {}
42
46
  end
47
+ # rubocop:enable Metrics/AbcSize
43
48
 
44
49
  def loaded_features
45
50
  @loaded_features ||= ConfigLoader.loaded_features
@@ -123,8 +128,25 @@ module RuboCop
123
128
  # @return [Config] for the given cop merged with that of its department (if any)
124
129
  # Note: the 'Enabled' attribute is same as that returned by `for_cop`
125
130
  def for_badge(badge)
126
- cop_config = for_cop(badge.to_s)
127
- fetch(badge.department.to_s) { return cop_config }.merge(cop_config)
131
+ @badge_config_cache[badge] ||= begin
132
+ department_config = self[badge.department_name]
133
+ cop_config = for_cop(badge.to_s)
134
+ if department_config
135
+ department_config.merge(cop_config)
136
+ else
137
+ cop_config
138
+ end
139
+ end
140
+ end
141
+
142
+ # @return [Boolean] whether config for this badge has 'Include' or 'Exclude' keys
143
+ # @api private
144
+ def clusivity_config_for_badge?(badge)
145
+ exists = @clusivity_config_exists_cache[badge.to_s]
146
+ return exists unless exists.nil?
147
+
148
+ cop_config = for_badge(badge)
149
+ @clusivity_config_exists_cache[badge.to_s] = cop_config['Include'] || cop_config['Exclude']
128
150
  end
129
151
 
130
152
  # @return [Config] for the given department name.
@@ -273,9 +295,10 @@ module RuboCop
273
295
  return nil unless lock_file_path
274
296
 
275
297
  File.foreach(lock_file_path) do |line|
276
- # If rails is in Gemfile.lock or gems.lock, there should be a line like:
277
- # rails (X.X.X)
278
- result = line.match(/^\s+rails\s+\((\d+\.\d+)/)
298
+ # If Rails (or one of its frameworks) is in Gemfile.lock or gems.lock, there should be
299
+ # a line like:
300
+ # railties (X.X.X)
301
+ result = line.match(/^\s+railties\s+\((\d+\.\d+)/)
279
302
  return result.captures.first.to_f if result
280
303
  end
281
304
  end
@@ -137,6 +137,15 @@ module RuboCop
137
137
  end
138
138
  end
139
139
 
140
+ # @api private
141
+ def inject_defaults!(project_root)
142
+ path = File.join(project_root, 'config', 'default.yml')
143
+ config = load_file(path)
144
+ new_config = ConfigLoader.merge_with_default(config, path)
145
+ puts "configuration from #{path}" if debug?
146
+ @default_configuration = new_config
147
+ end
148
+
140
149
  # Returns the path RuboCop inferred as the root of the project. No file
141
150
  # searches will go past this directory.
142
151
  # @deprecated Use `RuboCop::ConfigFinder.project_root` instead.
@@ -206,7 +206,11 @@ module RuboCop
206
206
  end
207
207
 
208
208
  def base_configs(path, inherit_from, file)
209
- configs = Array(inherit_from).compact.map do |f|
209
+ inherit_froms = Array(inherit_from).compact.flat_map do |f|
210
+ PathUtil.glob?(f) ? Dir.glob(f) : f
211
+ end
212
+
213
+ configs = inherit_froms.map do |f|
210
214
  ConfigLoader.load_file(inherited_file(path, f, file))
211
215
  end
212
216
 
@@ -162,7 +162,7 @@ module RuboCop
162
162
  return unless syntax_config && default_config.merge(syntax_config) != default_config
163
163
 
164
164
  raise ValidationError,
165
- "configuration for Syntax cop found in #{smart_loaded_path}\n" \
165
+ "configuration for Lint/Syntax cop found in #{smart_loaded_path}\n" \
166
166
  'It\'s not possible to disable this cop.'
167
167
  end
168
168
 
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # allow for badge references in source files that omit the department for
11
11
  # RuboCop to infer.
12
12
  class Badge
13
- attr_reader :department, :cop_name
13
+ attr_reader :department, :department_name, :cop_name
14
14
 
15
15
  def self.for(class_name)
16
16
  parts = class_name.split('::')
@@ -18,19 +18,23 @@ module RuboCop
18
18
  new(name_deep_enough ? parts[2..] : parts.last(2))
19
19
  end
20
20
 
21
+ @parse_cache = {}
22
+
21
23
  def self.parse(identifier)
22
- new(identifier.split('/').map { |i| camel_case(i) })
24
+ @parse_cache[identifier] ||= new(identifier.split('/').map! { |i| camel_case(i) })
23
25
  end
24
26
 
25
27
  def self.camel_case(name_part)
26
28
  return 'RSpec' if name_part == 'rspec'
29
+ return name_part unless name_part.match?(/^[a-z]|_[a-z]/)
27
30
 
28
- name_part.gsub(/^\w|_\w/) { |match| match[-1, 1].upcase }
31
+ name_part.gsub(/^[a-z]|_[a-z]/) { |match| match[-1, 1].upcase }
29
32
  end
30
33
 
31
34
  def initialize(class_name_parts)
32
35
  department_parts = class_name_parts[0...-1]
33
36
  @department = (department_parts.join('/').to_sym unless department_parts.empty?)
37
+ @department_name = @department&.to_s
34
38
  @cop_name = class_name_parts.last
35
39
  end
36
40
 
@@ -40,7 +44,8 @@ module RuboCop
40
44
  alias eql? ==
41
45
 
42
46
  def hash
43
- [department, cop_name].hash
47
+ # Do hashing manually to reduce Array allocations.
48
+ department.hash ^ cop_name.hash # rubocop:disable Security/CompoundHash
44
49
  end
45
50
 
46
51
  def match?(other)
@@ -68,6 +68,64 @@ module RuboCop
68
68
  Documentation.url_for(self) if builtin?
69
69
  end
70
70
 
71
+ def self.inherited(subclass)
72
+ super
73
+ Registry.global.enlist(subclass)
74
+ end
75
+
76
+ # Call for abstract Cop classes
77
+ def self.exclude_from_registry
78
+ Registry.global.dismiss(self)
79
+ end
80
+
81
+ # Returns if class supports autocorrect.
82
+ # It is recommended to extend AutoCorrector instead of overriding
83
+ def self.support_autocorrect?
84
+ false
85
+ end
86
+
87
+ ### Naming
88
+
89
+ def self.badge
90
+ @badge ||= Badge.for(name)
91
+ end
92
+
93
+ def self.cop_name
94
+ badge.to_s
95
+ end
96
+
97
+ def self.department
98
+ badge.department
99
+ end
100
+
101
+ def self.lint?
102
+ department == :Lint
103
+ end
104
+
105
+ # Returns true if the cop name or the cop namespace matches any of the
106
+ # given names.
107
+ def self.match?(given_names)
108
+ return false unless given_names
109
+
110
+ given_names.include?(cop_name) || given_names.include?(badge.department_name)
111
+ end
112
+
113
+ # Override and return the Force class(es) you need to join
114
+ def self.joining_forces; end
115
+
116
+ ### Persistence
117
+
118
+ # Override if your cop should be called repeatedly for multiple investigations
119
+ # Between calls to `on_new_investigation` and `on_investigation_end`,
120
+ # the result of `processed_source` will remain constant.
121
+ # You should invalidate any caches that depend on the current `processed_source`
122
+ # in the `on_new_investigation` callback.
123
+ # If your cop does autocorrections, be aware that your instance may be called
124
+ # multiple times with the same `processed_source.path` but different content.
125
+ def self.support_multiple_source?
126
+ false
127
+ end
128
+
71
129
  def initialize(config = nil, options = nil)
72
130
  @config = config || Config.new
73
131
  @options = options || { debug: false }
@@ -92,9 +150,6 @@ module RuboCop
92
150
  # Typically do nothing here
93
151
  end
94
152
 
95
- # Override and return the Force class(es) you need to join
96
- def self.joining_forces; end
97
-
98
153
  # Gets called if no message is specified when calling `add_offense` or
99
154
  # `add_global_offense`
100
155
  # Cops are discouraged to override this; instead pass your message directly
@@ -107,8 +162,7 @@ module RuboCop
107
162
  def add_global_offense(message = nil, severity: nil)
108
163
  severity = find_severity(nil, severity)
109
164
  message = find_message(nil, message)
110
- @current_offenses <<
111
- Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported)
165
+ current_offenses << Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported)
112
166
  end
113
167
 
114
168
  # Adds an offense on the specified range (or node with an expression)
@@ -126,7 +180,7 @@ module RuboCop
126
180
 
127
181
  status, corrector = enabled_line?(range.line) ? correct(range, &block) : :disabled
128
182
 
129
- @current_offenses << Offense.new(severity, range, message, name, status, corrector)
183
+ current_offenses << Offense.new(severity, range, message, name, status, corrector)
130
184
  end
131
185
 
132
186
  # This method should be overridden when a cop's behavior depends
@@ -148,48 +202,6 @@ module RuboCop
148
202
  nil
149
203
  end
150
204
 
151
- def self.inherited(subclass)
152
- super
153
- Registry.global.enlist(subclass)
154
- end
155
-
156
- # Call for abstract Cop classes
157
- def self.exclude_from_registry
158
- Registry.global.dismiss(self)
159
- end
160
-
161
- # Returns if class supports autocorrect.
162
- # It is recommended to extend AutoCorrector instead of overriding
163
- def self.support_autocorrect?
164
- false
165
- end
166
-
167
- ### Naming
168
-
169
- def self.badge
170
- @badge ||= Badge.for(name)
171
- end
172
-
173
- def self.cop_name
174
- badge.to_s
175
- end
176
-
177
- def self.department
178
- badge.department
179
- end
180
-
181
- def self.lint?
182
- department == :Lint
183
- end
184
-
185
- # Returns true if the cop name or the cop namespace matches any of the
186
- # given names.
187
- def self.match?(given_names)
188
- return false unless given_names
189
-
190
- given_names.include?(cop_name) || given_names.include?(department.to_s)
191
- end
192
-
193
205
  def cop_name
194
206
  @cop_name ||= self.class.cop_name
195
207
  end
@@ -225,6 +237,8 @@ module RuboCop
225
237
  end
226
238
 
227
239
  def relevant_file?(file)
240
+ return true unless @config.clusivity_config_for_badge?(self.class.badge)
241
+
228
242
  file == RuboCop::AST::ProcessedSource::STRING_SOURCE_NAME ||
229
243
  (file_name_matches_any?(file, 'Include', true) &&
230
244
  !file_name_matches_any?(file, 'Exclude', false))
@@ -239,19 +253,6 @@ module RuboCop
239
253
  ProcessedSource.new(source, target_ruby_version, path)
240
254
  end
241
255
 
242
- ### Persistence
243
-
244
- # Override if your cop should be called repeatedly for multiple investigations
245
- # Between calls to `on_new_investigation` and `on_investigation_end`,
246
- # the result of `processed_source` will remain constant.
247
- # You should invalidate any caches that depend on the current `processed_source`
248
- # in the `on_new_investigation` callback.
249
- # If your cop does autocorrections, be aware that your instance may be called
250
- # multiple times with the same `processed_source.path` but different content.
251
- def self.support_multiple_source?
252
- false
253
- end
254
-
255
256
  # @api private
256
257
  # Called between investigations
257
258
  def ready
@@ -270,6 +271,7 @@ module RuboCop
270
271
 
271
272
  ### Reserved for Commissioner
272
273
 
274
+ # rubocop:disable Layout/ClassStructure
273
275
  # @api private
274
276
  def callbacks_needed
275
277
  self.class.callbacks_needed
@@ -282,6 +284,7 @@ module RuboCop
282
284
  !Base.method_defined?(m) # exclude standard "callbacks" like 'on_begin_investigation'
283
285
  end
284
286
  end
287
+ # rubocop:enable Layout/ClassStructure
285
288
 
286
289
  private
287
290
 
@@ -292,7 +295,7 @@ module RuboCop
292
295
  end
293
296
 
294
297
  def apply_correction(corrector)
295
- @current_corrector&.merge!(corrector) if corrector
298
+ current_corrector&.merge!(corrector) if corrector
296
299
  end
297
300
 
298
301
  ### Reserved for Commissioner:
@@ -305,28 +308,41 @@ module RuboCop
305
308
  @currently_disabled_lines ||= Set.new
306
309
  end
307
310
 
311
+ def current_corrector
312
+ @current_corrector ||= Corrector.new(@processed_source) if @processed_source.valid_syntax?
313
+ end
314
+
315
+ def current_offenses
316
+ @current_offenses ||= []
317
+ end
318
+
308
319
  private_class_method def self.restrict_on_send
309
320
  @restrict_on_send ||= self::RESTRICT_ON_SEND.to_a.freeze
310
321
  end
311
322
 
312
323
  # Called before any investigation
313
324
  def begin_investigation(processed_source)
314
- @current_offenses = []
325
+ @current_offenses = nil
315
326
  @current_offense_locations = nil
316
327
  @currently_disabled_lines = nil
317
328
  @processed_source = processed_source
318
- @current_corrector = Corrector.new(@processed_source) if @processed_source.valid_syntax?
329
+ @current_corrector = nil
319
330
  end
320
331
 
332
+ EMPTY_OFFENSES = [].freeze
333
+ private_constant :EMPTY_OFFENSES
321
334
  # Called to complete an investigation
322
335
  def complete_investigation
323
- InvestigationReport.new(self, processed_source, @current_offenses, @current_corrector)
336
+ InvestigationReport.new(
337
+ self, processed_source, @current_offenses || EMPTY_OFFENSES, @current_corrector
338
+ )
324
339
  ensure
325
340
  reset_investigation
326
341
  end
327
342
 
328
343
  ### Actually private methods
329
344
 
345
+ # rubocop:disable Layout/ClassStructure
330
346
  def self.builtin?
331
347
  return false unless (m = instance_methods(false).first) # any custom method will do
332
348
 
@@ -334,6 +350,7 @@ module RuboCop
334
350
  path.start_with?(__dir__)
335
351
  end
336
352
  private_class_method :builtin?
353
+ # rubocop:enable Layout/ClassStructure
337
354
 
338
355
  def reset_investigation
339
356
  @currently_disabled_lines = @current_offenses = @processed_source = @current_corrector = nil
@@ -412,7 +429,7 @@ module RuboCop
412
429
  patterns = cop_config[parameter]
413
430
  return default_result unless patterns
414
431
 
415
- patterns = OptimizedPatterns.from(patterns)
432
+ patterns = FilePatterns.from(patterns)
416
433
  patterns.match?(config.path_relative_to_config(file)) || patterns.match?(file)
417
434
  end
418
435
 
@@ -82,7 +82,8 @@ module RuboCop
82
82
  @cops.each { |cop| cop.send :begin_investigation, processed_source }
83
83
  if processed_source.valid_syntax?
84
84
  invoke(:on_new_investigation, @cops)
85
- invoke(:investigate, @forces, processed_source)
85
+ invoke_with_argument(:investigate, @forces, processed_source)
86
+
86
87
  walk(processed_source.ast) unless @cops.empty?
87
88
  invoke(:on_investigation_end, @cops)
88
89
  else
@@ -149,8 +150,12 @@ module RuboCop
149
150
  map
150
151
  end
151
152
 
152
- def invoke(callback, cops, *args)
153
- cops.each { |cop| with_cop_error_handling(cop) { cop.send(callback, *args) } }
153
+ def invoke(callback, cops)
154
+ cops.each { |cop| with_cop_error_handling(cop) { cop.send(callback) } }
155
+ end
156
+
157
+ def invoke_with_argument(callback, cops, arg)
158
+ cops.each { |cop| with_cop_error_handling(cop) { cop.send(callback, arg) } }
154
159
  end
155
160
 
156
161
  # Allow blind rescues here, since we're absorbing and packaging or