rubocop 1.39.0 → 1.41.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +65 -9
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop/comment_config.rb +5 -0
  6. data/lib/rubocop/config.rb +33 -9
  7. data/lib/rubocop/config_loader.rb +14 -5
  8. data/lib/rubocop/config_loader_resolver.rb +1 -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 +26 -17
  12. data/lib/rubocop/cop/commissioner.rb +8 -3
  13. data/lib/rubocop/cop/cop.rb +1 -1
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  15. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  16. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  17. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  18. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  19. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  20. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  21. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  22. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  23. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  24. data/lib/rubocop/cop/layout/indentation_style.rb +3 -1
  25. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  26. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  27. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  28. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  29. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  30. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  31. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  32. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  33. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  34. data/lib/rubocop/cop/layout/trailing_whitespace.rb +6 -2
  35. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  36. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  37. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  38. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  39. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -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/empty_block.rb +1 -5
  43. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  44. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  45. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  46. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  47. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +13 -3
  48. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  49. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +10 -12
  50. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  51. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
  52. data/lib/rubocop/cop/lint/void.rb +6 -6
  53. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  54. data/lib/rubocop/cop/metrics/class_length.rb +10 -5
  55. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  56. data/lib/rubocop/cop/metrics/module_length.rb +10 -5
  57. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +6 -3
  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 +28 -5
  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/require_library.rb +2 -0
  69. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  70. data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
  71. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  72. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  73. data/lib/rubocop/cop/registry.rb +29 -14
  74. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  75. data/lib/rubocop/cop/style/concat_array_literals.rb +66 -0
  76. data/lib/rubocop/cop/style/documentation.rb +1 -1
  77. data/lib/rubocop/cop/style/guard_clause.rb +36 -5
  78. data/lib/rubocop/cop/style/if_with_semicolon.rb +4 -4
  79. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  80. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  81. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  82. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  83. data/lib/rubocop/cop/style/redundant_constant_base.rb +85 -0
  84. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
  85. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  86. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  87. data/lib/rubocop/cop/style/require_order.rb +140 -0
  88. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  89. data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
  90. data/lib/rubocop/cop/style/semicolon.rb +2 -1
  91. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  92. data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
  93. data/lib/rubocop/cop/team.rb +1 -1
  94. data/lib/rubocop/cop/util.rb +32 -5
  95. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  96. data/lib/rubocop/cop/variable_force.rb +20 -29
  97. data/lib/rubocop/cops_documentation_generator.rb +22 -3
  98. data/lib/rubocop/directive_comment.rb +1 -1
  99. data/lib/rubocop/file_patterns.rb +43 -0
  100. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  101. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  102. data/lib/rubocop/formatter.rb +3 -1
  103. data/lib/rubocop/options.rb +8 -0
  104. data/lib/rubocop/path_util.rb +34 -16
  105. data/lib/rubocop/result_cache.rb +1 -1
  106. data/lib/rubocop/rspec/cop_helper.rb +4 -1
  107. data/lib/rubocop/rspec/support.rb +2 -2
  108. data/lib/rubocop/server/core.rb +1 -1
  109. data/lib/rubocop/target_finder.rb +1 -1
  110. data/lib/rubocop/target_ruby.rb +1 -1
  111. data/lib/rubocop/version.rb +1 -1
  112. data/lib/rubocop.rb +16 -6
  113. metadata +10 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 881807be0f0f6eea20bd13bd8f08fdb158a5b155c8d3a22fd748683a68c1fef1
4
- data.tar.gz: 2a8e7d4b02f1ba468e02a4c20f8e3b830ce2a1d8ff0210f86aaeafab597c8c88
3
+ metadata.gz: 77b5fe782c4a109e75c380273e08f38b9c61eb519f11f19a606a380080f1f0a2
4
+ data.tar.gz: fa67b5a3f120d6f1538963f9ddbc8bd0508b7f54763bd7c76da725054c9e0459
5
5
  SHA512:
6
- metadata.gz: 11ea36bec754b07912e06b5481f964d10a6dbf5bfd56f99d8a8842ca46d56ae03a342a283d843336f977760c28a697ee995aa98268254a55b1218fa57a9fb5c7
7
- data.tar.gz: b5096cb4589d9bafdab0b6ab409ea9e7841dc06b274aeb7f7d5a26e703cb216c2a428d695fb2a087637467f1cdd5ac005398c66ee3e7d28d49cb4b203a87667d
6
+ metadata.gz: 1475ad1af84e34c10ccf4905247b6e1090e0bd2969d6eb5ef2c4f4dec116841d438b42c5f4c84678870ffac0703f663e1f1ea79ce588b74caca27162f5ad6c07
7
+ data.tar.gz: 267189e76baac7ebc2632d3249957987ba9a3db3df26fa1bf7abe4510a7f9baf8cf5bec399b024d1e900accd1b55f2a5c72e8ab3686d1edc656272ef9723bdaf
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.39', require: false
56
+ gem 'rubocop', '~> 1.41', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -161,7 +161,9 @@ AllCops:
161
161
  Bundler/DuplicatedGem:
162
162
  Description: 'Checks for duplicate gem entries in Gemfile.'
163
163
  Enabled: true
164
+ Severity: warning
164
165
  VersionAdded: '0.46'
166
+ VersionChanged: '1.40'
165
167
  Include:
166
168
  - '**/*.gemfile'
167
169
  - '**/Gemfile'
@@ -213,7 +215,9 @@ Bundler/InsecureProtocolSource:
213
215
  because HTTP requests are insecure. Please change your source to
214
216
  'https://rubygems.org' if possible, or 'http://rubygems.org' if not.
215
217
  Enabled: true
218
+ Severity: warning
216
219
  VersionAdded: '0.50'
220
+ VersionChanged: '1.40'
217
221
  AllowHttpProtocol: true
218
222
  Include:
219
223
  - '**/*.gemfile'
@@ -252,14 +256,18 @@ Gemspec/DependencyVersion:
252
256
  Gemspec/DeprecatedAttributeAssignment:
253
257
  Description: Checks that deprecated attribute assignments are not set in a gemspec file.
254
258
  Enabled: pending
259
+ Severity: warning
255
260
  VersionAdded: '1.30'
261
+ VersionChanged: '1.40'
256
262
  Include:
257
263
  - '**/*.gemspec'
258
264
 
259
265
  Gemspec/DuplicatedAssignment:
260
266
  Description: 'An attribute assignment method calls should be listed only once in a gemspec.'
261
267
  Enabled: true
268
+ Severity: warning
262
269
  VersionAdded: '0.52'
270
+ VersionChanged: '1.40'
263
271
  Include:
264
272
  - '**/*.gemspec'
265
273
 
@@ -278,7 +286,9 @@ Gemspec/OrderedDependencies:
278
286
  Gemspec/RequireMFA:
279
287
  Description: 'Checks that the gemspec has metadata to require Multi-Factor Authentication from RubyGems.'
280
288
  Enabled: pending
289
+ Severity: warning
281
290
  VersionAdded: '1.23'
291
+ VersionChanged: '1.40'
282
292
  Reference:
283
293
  - https://guides.rubygems.org/mfa-requirement-opt-in/
284
294
  Include:
@@ -287,8 +297,9 @@ Gemspec/RequireMFA:
287
297
  Gemspec/RequiredRubyVersion:
288
298
  Description: 'Checks that `required_ruby_version` of gemspec is specified and equal to `TargetRubyVersion` of .rubocop.yml.'
289
299
  Enabled: true
300
+ Severity: warning
290
301
  VersionAdded: '0.52'
291
- VersionChanged: '1.22'
302
+ VersionChanged: '1.40'
292
303
  Include:
293
304
  - '**/*.gemspec'
294
305
 
@@ -296,7 +307,9 @@ Gemspec/RubyVersionGlobalsUsage:
296
307
  Description: Checks usage of RUBY_VERSION in gemspec.
297
308
  StyleGuide: '#no-ruby-version-in-the-gemspec'
298
309
  Enabled: true
310
+ Severity: warning
299
311
  VersionAdded: '0.72'
312
+ VersionChanged: '1.40'
300
313
  Include:
301
314
  - '**/*.gemspec'
302
315
 
@@ -378,8 +391,9 @@ Layout/AssignmentIndentation:
378
391
  Checks the indentation of the first line of the
379
392
  right-hand-side of a multi-line assignment.
380
393
  Enabled: true
394
+ SafeAutoCorrect: false
381
395
  VersionAdded: '0.49'
382
- VersionChanged: '0.77'
396
+ VersionChanged: '1.40'
383
397
  # By default the indentation width from `Layout/IndentationWidth` is used,
384
398
  # but it can be overridden by setting this parameter.
385
399
  IndentationWidth: ~
@@ -748,6 +762,7 @@ Layout/FirstArrayElementLineBreak:
748
762
  multi-line array.
749
763
  Enabled: false
750
764
  VersionAdded: '0.49'
765
+ AllowMultilineFinalElement: false
751
766
 
752
767
  Layout/FirstHashElementIndentation:
753
768
  Description: 'Checks the indentation of the first key in a hash literal.'
@@ -780,6 +795,7 @@ Layout/FirstHashElementLineBreak:
780
795
  multi-line hash.
781
796
  Enabled: false
782
797
  VersionAdded: '0.49'
798
+ AllowMultilineFinalElement: false
783
799
 
784
800
  Layout/FirstMethodArgumentLineBreak:
785
801
  Description: >-
@@ -787,6 +803,7 @@ Layout/FirstMethodArgumentLineBreak:
787
803
  multi-line method call.
788
804
  Enabled: false
789
805
  VersionAdded: '0.49'
806
+ AllowMultilineFinalElement: false
790
807
 
791
808
  Layout/FirstMethodParameterLineBreak:
792
809
  Description: >-
@@ -794,6 +811,7 @@ Layout/FirstMethodParameterLineBreak:
794
811
  multi-line method parameter definition.
795
812
  Enabled: false
796
813
  VersionAdded: '0.49'
814
+ AllowMultilineFinalElement: false
797
815
 
798
816
  Layout/FirstParameterIndentation:
799
817
  Description: >-
@@ -1053,6 +1071,7 @@ Layout/MultilineArrayLineBreaks:
1053
1071
  starts on a separate line.
1054
1072
  Enabled: false
1055
1073
  VersionAdded: '0.67'
1074
+ AllowMultilineFinalElement: false
1056
1075
 
1057
1076
  Layout/MultilineAssignmentLayout:
1058
1077
  Description: 'Check for a newline after the assignment operator in multi-line assignments.'
@@ -1103,6 +1122,7 @@ Layout/MultilineHashKeyLineBreaks:
1103
1122
  starts on a separate line.
1104
1123
  Enabled: false
1105
1124
  VersionAdded: '0.67'
1125
+ AllowMultilineFinalElement: false
1106
1126
 
1107
1127
  Layout/MultilineMethodArgumentLineBreaks:
1108
1128
  Description: >-
@@ -1110,6 +1130,7 @@ Layout/MultilineMethodArgumentLineBreaks:
1110
1130
  starts on a separate line.
1111
1131
  Enabled: false
1112
1132
  VersionAdded: '0.67'
1133
+ AllowMultilineFinalElement: false
1113
1134
 
1114
1135
  Layout/MultilineMethodCallBraceLayout:
1115
1136
  Description: >-
@@ -1164,6 +1185,7 @@ Layout/MultilineMethodParameterLineBreaks:
1164
1185
  starts on a separate line.
1165
1186
  Enabled: false
1166
1187
  VersionAdded: '1.32'
1188
+ AllowMultilineFinalElement: false
1167
1189
 
1168
1190
  Layout/MultilineOperationIndentation:
1169
1191
  Description: >-
@@ -1643,7 +1665,7 @@ Lint/DeprecatedConstants:
1643
1665
  Description: 'Checks for deprecated constants.'
1644
1666
  Enabled: pending
1645
1667
  VersionAdded: '1.8'
1646
- VersionChanged: '1.22'
1668
+ VersionChanged: '1.40'
1647
1669
  # You can configure deprecated constants.
1648
1670
  # If there is an alternative method, you can set alternative value as `Alternative`.
1649
1671
  # And you can set the deprecated version as `DeprecatedVersion`.
@@ -1670,6 +1692,12 @@ Lint/DeprecatedConstants:
1670
1692
  'Random::DEFAULT':
1671
1693
  Alternative: 'Random.new'
1672
1694
  DeprecatedVersion: '3.0'
1695
+ 'Struct::Group':
1696
+ Alternative: 'Etc::Group'
1697
+ DeprecatedVersion: '3.0'
1698
+ 'Struct::Passwd':
1699
+ Alternative: 'Etc::Passwd'
1700
+ DeprecatedVersion: '3.0'
1673
1701
 
1674
1702
  Lint/DeprecatedOpenSSLConstant:
1675
1703
  Description: "Don't use algorithm constants for `OpenSSL::Cipher` and `OpenSSL::Digest`."
@@ -1894,11 +1922,11 @@ Lint/InheritException:
1894
1922
  - runtime_error
1895
1923
 
1896
1924
  Lint/InterpolationCheck:
1897
- Description: 'Raise warning for interpolation in single q strs.'
1925
+ Description: 'Checks for interpolation in a single quoted string.'
1898
1926
  Enabled: true
1899
- Safe: false
1927
+ SafeAutoCorrect: false
1900
1928
  VersionAdded: '0.50'
1901
- VersionChanged: '0.87'
1929
+ VersionChanged: '1.40'
1902
1930
 
1903
1931
  Lint/LambdaWithoutLiteralBlock:
1904
1932
  Description: 'Checks uses of lambda without a literal block.'
@@ -2806,6 +2834,7 @@ Naming/MethodParameterName:
2806
2834
  - as
2807
2835
  - at
2808
2836
  - by
2837
+ - cc
2809
2838
  - db
2810
2839
  - id
2811
2840
  - if
@@ -3013,6 +3042,11 @@ Style/ArrayCoercion:
3013
3042
  Enabled: false
3014
3043
  VersionAdded: '0.88'
3015
3044
 
3045
+ Style/ArrayIntersect:
3046
+ Description: 'Use `array1.intersect?(array2)` instead of `(array1 & array2).any?`.'
3047
+ Enabled: 'pending'
3048
+ VersionAdded: '1.40'
3049
+
3016
3050
  Style/ArrayJoin:
3017
3051
  Description: 'Use Array#join instead of Array#*.'
3018
3052
  StyleGuide: '#array-join'
@@ -3392,6 +3426,11 @@ Style/CommentedKeyword:
3392
3426
  VersionAdded: '0.51'
3393
3427
  VersionChanged: '1.19'
3394
3428
 
3429
+ Style/ConcatArrayLiterals:
3430
+ Description: 'Enforces the use of `Array#push(item)` instead of `Array#concat([item])` to avoid redundant array literals.'
3431
+ Enabled: pending
3432
+ VersionAdded: '1.41'
3433
+
3395
3434
  Style/ConditionalAssignment:
3396
3435
  Description: >-
3397
3436
  Use the return value of `if` and `case` statements for
@@ -4660,10 +4699,12 @@ Style/RedundantArgument:
4660
4699
  Enabled: pending
4661
4700
  Safe: false
4662
4701
  VersionAdded: '1.4'
4663
- VersionChanged: '1.7'
4702
+ VersionChanged: '1.40'
4664
4703
  Methods:
4665
4704
  # Array#join
4666
4705
  join: ''
4706
+ # Array#sum
4707
+ sum: 0
4667
4708
  # String#split
4668
4709
  split: ' '
4669
4710
  # String#chomp
@@ -4698,6 +4739,16 @@ Style/RedundantConditional:
4698
4739
  Enabled: true
4699
4740
  VersionAdded: '0.50'
4700
4741
 
4742
+ Style/RedundantConstantBase:
4743
+ Description: Avoid redundant `::` prefix on constant.
4744
+ Enabled: pending
4745
+ VersionAdded: '1.40'
4746
+
4747
+ Style/RedundantDoubleSplatHashBraces:
4748
+ Description: 'Checks for redundant uses of double splat hash braces.'
4749
+ Enabled: pending
4750
+ VersionAdded: '1.41'
4751
+
4701
4752
  Style/RedundantEach:
4702
4753
  Description: 'Checks for redundant `each`.'
4703
4754
  Enabled: pending
@@ -4838,6 +4889,12 @@ Style/RegexpLiteral:
4838
4889
  # are found in the regexp string.
4839
4890
  AllowInnerSlashes: false
4840
4891
 
4892
+ Style/RequireOrder:
4893
+ Description: Sort `require` and `require_relative` in alphabetical order.
4894
+ Enabled: false
4895
+ SafeAutoCorrect: false
4896
+ VersionAdded: '1.40'
4897
+
4841
4898
  Style/RescueModifier:
4842
4899
  Description: 'Avoid using rescue in its modifier form.'
4843
4900
  StyleGuide: '#no-rescue-modifiers'
@@ -5122,12 +5179,11 @@ Style/SymbolProc:
5122
5179
  Enabled: true
5123
5180
  Safe: false
5124
5181
  VersionAdded: '0.26'
5125
- VersionChanged: '1.28'
5182
+ VersionChanged: '1.40'
5126
5183
  AllowMethodsWithArguments: false
5127
5184
  # A list of method names to be always allowed by the check.
5128
5185
  # The names should be fairly unique, otherwise you'll end up ignoring lots of code.
5129
5186
  AllowedMethods:
5130
- - respond_to
5131
5187
  - define_method
5132
5188
  AllowedPatterns: []
5133
5189
  IgnoredMethods: [] # deprecated
data/exe/rubocop CHANGED
@@ -11,8 +11,8 @@ exit exit_status if server_cli.exit?
11
11
  if RuboCop::Server.running?
12
12
  exit_status = RuboCop::Server::ClientCommand::Exec.new.run
13
13
  else
14
- require 'rubocop'
15
14
  require 'benchmark'
15
+ require 'rubocop'
16
16
 
17
17
  cli = RuboCop::CLI.new
18
18
 
@@ -31,6 +31,7 @@ module RuboCop
31
31
 
32
32
  def initialize(processed_source)
33
33
  @processed_source = processed_source
34
+ @no_directives = !processed_source.raw_source.include?('rubocop')
34
35
  end
35
36
 
36
37
  def cop_enabled_at_line?(cop, line_number)
@@ -74,6 +75,8 @@ module RuboCop
74
75
  end
75
76
 
76
77
  def analyze # rubocop:todo Metrics/AbcSize
78
+ return {} if @no_directives
79
+
77
80
  analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
78
81
  inject_disabled_cops_directives(analyses)
79
82
 
@@ -146,6 +149,8 @@ module RuboCop
146
149
  end
147
150
 
148
151
  def each_directive
152
+ return if @no_directives
153
+
149
154
  processed_source.comments.each do |comment|
150
155
  directive = DirectiveComment.new(comment)
151
156
  yield directive if directive.cop_names
@@ -21,17 +21,23 @@ module RuboCop
21
21
  DEFAULT_RAILS_VERSION = 5.0
22
22
  attr_reader :loaded_path
23
23
 
24
+ # rubocop:disable Metrics/AbcSize
24
25
  def initialize(hash = {}, loaded_path = nil)
25
26
  @loaded_path = loaded_path
26
27
  @for_cop = Hash.new do |h, cop|
27
- qualified_cop_name = Cop::Registry.qualified_cop_name(cop, loaded_path)
28
+ cop_name = cop.respond_to?(:cop_name) ? cop.cop_name : cop
29
+ qualified_cop_name = Cop::Registry.qualified_cop_name(cop_name, loaded_path)
28
30
  cop_options = self[qualified_cop_name].dup || {}
29
31
  cop_options['Enabled'] = enable_cop?(qualified_cop_name, cop_options)
30
- h[cop] = cop_options
32
+ h[cop] = h[cop_name] = cop_options
31
33
  end
32
34
  @hash = hash
33
35
  @validator = ConfigValidator.new(self)
36
+
37
+ @badge_config_cache = {}.compare_by_identity
38
+ @clusivity_config_exists_cache = {}
34
39
  end
40
+ # rubocop:enable Metrics/AbcSize
35
41
 
36
42
  def self.create(hash, path, check: true)
37
43
  config = new(hash, path)
@@ -116,14 +122,31 @@ module RuboCop
116
122
  # Note: the 'Enabled' attribute is calculated according to the department's
117
123
  # and 'AllCops' configuration; other attributes are not inherited.
118
124
  def for_cop(cop)
119
- @for_cop[cop.respond_to?(:cop_name) ? cop.cop_name : cop]
125
+ @for_cop[cop]
120
126
  end
121
127
 
122
128
  # @return [Config] for the given cop merged with that of its department (if any)
123
129
  # Note: the 'Enabled' attribute is same as that returned by `for_cop`
124
130
  def for_badge(badge)
125
- cop_config = for_cop(badge.to_s)
126
- 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']
127
150
  end
128
151
 
129
152
  # @return [Config] for the given department name.
@@ -215,7 +238,7 @@ module RuboCop
215
238
  # directory since that wouldn't work.
216
239
  def base_dir_for_path_parameters
217
240
  @base_dir_for_path_parameters ||=
218
- if File.basename(loaded_path).start_with?('.rubocop') &&
241
+ if loaded_path && File.basename(loaded_path).start_with?('.rubocop') &&
219
242
  loaded_path != File.join(Dir.home, ConfigLoader::DOTFILE)
220
243
  File.expand_path(File.dirname(loaded_path))
221
244
  else
@@ -272,9 +295,10 @@ module RuboCop
272
295
  return nil unless lock_file_path
273
296
 
274
297
  File.foreach(lock_file_path) do |line|
275
- # If rails is in Gemfile.lock or gems.lock, there should be a line like:
276
- # rails (X.X.X)
277
- 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+)/)
278
302
  return result.captures.first.to_f if result
279
303
  end
280
304
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'erb'
4
- require 'yaml'
5
4
  require 'pathname'
5
+ require 'yaml'
6
6
  require_relative 'config_finder'
7
7
 
8
8
  module RuboCop
@@ -42,18 +42,18 @@ module RuboCop
42
42
 
43
43
  hash = load_yaml_configuration(path)
44
44
 
45
- # Resolve requires first in case they define additional cops
46
45
  loaded_features = resolver.resolve_requires(path, hash)
47
46
  add_loaded_features(loaded_features)
48
47
 
49
- add_missing_namespaces(path, hash)
50
-
51
48
  resolver.override_department_setting_for_cops({}, hash)
52
49
  resolver.resolve_inheritance_from_gems(hash)
53
50
  resolver.resolve_inheritance(path, hash, file, debug?)
54
-
55
51
  hash.delete('inherit_from')
56
52
 
53
+ # Adding missing namespaces only after resolving requires & inheritance,
54
+ # since both can introduce new cops that need to be considered here.
55
+ add_missing_namespaces(path, hash)
56
+
57
57
  Config.create(hash, path, check: check)
58
58
  end
59
59
 
@@ -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.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
3
  require 'pathname'
4
+ require 'yaml'
5
5
 
6
6
  module RuboCop
7
7
  # A help class for ConfigLoader that handles configuration resolution.
@@ -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)
@@ -107,8 +107,7 @@ module RuboCop
107
107
  def add_global_offense(message = nil, severity: nil)
108
108
  severity = find_severity(nil, severity)
109
109
  message = find_message(nil, message)
110
- @current_offenses <<
111
- Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported)
110
+ current_offenses << Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported)
112
111
  end
113
112
 
114
113
  # Adds an offense on the specified range (or node with an expression)
@@ -126,7 +125,7 @@ module RuboCop
126
125
 
127
126
  status, corrector = enabled_line?(range.line) ? correct(range, &block) : :disabled
128
127
 
129
- @current_offenses << Offense.new(severity, range, message, name, status, corrector)
128
+ current_offenses << Offense.new(severity, range, message, name, status, corrector)
130
129
  end
131
130
 
132
131
  # This method should be overridden when a cop's behavior depends
@@ -187,7 +186,7 @@ module RuboCop
187
186
  def self.match?(given_names)
188
187
  return false unless given_names
189
188
 
190
- given_names.include?(cop_name) || given_names.include?(department.to_s)
189
+ given_names.include?(cop_name) || given_names.include?(badge.department_name)
191
190
  end
192
191
 
193
192
  def cop_name
@@ -225,6 +224,8 @@ module RuboCop
225
224
  end
226
225
 
227
226
  def relevant_file?(file)
227
+ return true unless @config.clusivity_config_for_badge?(self.class.badge)
228
+
228
229
  file == RuboCop::AST::ProcessedSource::STRING_SOURCE_NAME ||
229
230
  (file_name_matches_any?(file, 'Include', true) &&
230
231
  !file_name_matches_any?(file, 'Exclude', false))
@@ -292,7 +293,7 @@ module RuboCop
292
293
  end
293
294
 
294
295
  def apply_correction(corrector)
295
- @current_corrector&.merge!(corrector) if corrector
296
+ current_corrector&.merge!(corrector) if corrector
296
297
  end
297
298
 
298
299
  ### Reserved for Commissioner:
@@ -305,22 +306,37 @@ module RuboCop
305
306
  @currently_disabled_lines ||= Set.new
306
307
  end
307
308
 
309
+ def current_corrector
310
+ @current_corrector ||= Corrector.new(@processed_source) if @processed_source.valid_syntax?
311
+ end
312
+
313
+ def current_offenses
314
+ @current_offenses ||= []
315
+ end
316
+
308
317
  private_class_method def self.restrict_on_send
309
318
  @restrict_on_send ||= self::RESTRICT_ON_SEND.to_a.freeze
310
319
  end
311
320
 
312
321
  # Called before any investigation
313
322
  def begin_investigation(processed_source)
314
- @current_offenses = []
323
+ @current_offenses = nil
315
324
  @current_offense_locations = nil
316
325
  @currently_disabled_lines = nil
317
326
  @processed_source = processed_source
318
- @current_corrector = Corrector.new(@processed_source) if @processed_source.valid_syntax?
327
+ @current_corrector = nil
319
328
  end
320
329
 
330
+ # rubocop:disable Layout/ClassStructure
331
+ EMPTY_OFFENSES = [].freeze
332
+ private_constant :EMPTY_OFFENSES
333
+ # rubocop:enable Layout/ClassStructure
334
+
321
335
  # Called to complete an investigation
322
336
  def complete_investigation
323
- InvestigationReport.new(self, processed_source, @current_offenses, @current_corrector)
337
+ InvestigationReport.new(
338
+ self, processed_source, @current_offenses || EMPTY_OFFENSES, @current_corrector
339
+ )
324
340
  ensure
325
341
  reset_investigation
326
342
  end
@@ -412,15 +428,8 @@ module RuboCop
412
428
  patterns = cop_config[parameter]
413
429
  return default_result unless patterns
414
430
 
415
- path = nil
416
- patterns.any? do |pattern|
417
- # Try to match the absolute path, as Exclude properties are absolute.
418
- next true if match_path?(pattern, file)
419
-
420
- # Try with relative path.
421
- path ||= config.path_relative_to_config(file)
422
- match_path?(pattern, path)
423
- end
431
+ patterns = FilePatterns.from(patterns)
432
+ patterns.match?(config.path_relative_to_config(file)) || patterns.match?(file)
424
433
  end
425
434
 
426
435
  def enabled_line?(line_number)
@@ -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
@@ -97,7 +97,7 @@ module RuboCop
97
97
 
98
98
  def begin_investigation(processed_source)
99
99
  super
100
- @offenses = @current_offenses
100
+ @offenses = current_offenses
101
101
  @last_corrector = @current_corrector
102
102
  end
103
103