rubocop 1.71.2 → 1.73.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +51 -11
  4. data/config/internal_affairs.yml +16 -0
  5. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  6. data/lib/rubocop/comment_config.rb +1 -1
  7. data/lib/rubocop/config.rb +4 -0
  8. data/lib/rubocop/config_loader.rb +44 -8
  9. data/lib/rubocop/config_loader_resolver.rb +23 -9
  10. data/lib/rubocop/config_validator.rb +1 -1
  11. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -2
  12. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  13. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -1
  14. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  15. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  16. data/lib/rubocop/cop/internal_affairs.rb +1 -16
  17. data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
  18. data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
  19. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  20. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +26 -1
  21. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  22. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  23. data/lib/rubocop/cop/layout/line_length.rb +3 -3
  24. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  25. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  26. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  27. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
  28. data/lib/rubocop/cop/lint/float_comparison.rb +1 -6
  29. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  30. data/lib/rubocop/cop/lint/literal_as_condition.rb +104 -7
  31. data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
  32. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  33. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +252 -0
  34. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  35. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +80 -0
  36. data/lib/rubocop/cop/lint/void.rb +6 -0
  37. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  38. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  39. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  40. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  41. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +18 -18
  42. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
  43. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  44. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  45. data/lib/rubocop/cop/mixin/range_help.rb +3 -3
  46. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  47. data/lib/rubocop/cop/mixin/trailing_comma.rb +12 -0
  48. data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
  49. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  50. data/lib/rubocop/cop/naming/variable_name.rb +64 -6
  51. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  52. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
  53. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  54. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  55. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
  56. data/lib/rubocop/cop/style/redundant_condition.rb +34 -0
  57. data/lib/rubocop/cop/style/redundant_format.rb +250 -0
  58. data/lib/rubocop/cop/style/redundant_parentheses.rb +18 -4
  59. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
  60. data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
  61. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  62. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  63. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  64. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  65. data/lib/rubocop/cop/util.rb +1 -1
  66. data/lib/rubocop/cop/utils/format_string.rb +7 -5
  67. data/lib/rubocop/cops_documentation_generator.rb +12 -1
  68. data/lib/rubocop/directive_comment.rb +35 -2
  69. data/lib/rubocop/lsp/runtime.rb +2 -0
  70. data/lib/rubocop/lsp/server.rb +0 -2
  71. data/lib/rubocop/options.rb +26 -11
  72. data/lib/rubocop/path_util.rb +4 -0
  73. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  74. data/lib/rubocop/plugin/load_error.rb +26 -0
  75. data/lib/rubocop/plugin/loader.rb +100 -0
  76. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  77. data/lib/rubocop/plugin.rb +46 -0
  78. data/lib/rubocop/rake_task.rb +4 -1
  79. data/lib/rubocop/rspec/cop_helper.rb +9 -0
  80. data/lib/rubocop/rspec/shared_contexts.rb +15 -0
  81. data/lib/rubocop/rspec/support.rb +1 -0
  82. data/lib/rubocop/server/cache.rb +35 -2
  83. data/lib/rubocop/server/cli.rb +2 -2
  84. data/lib/rubocop/version.rb +17 -2
  85. data/lib/rubocop.rb +5 -1
  86. data/lib/ruby_lsp/rubocop/addon.rb +7 -10
  87. data/lib/ruby_lsp/rubocop/{wraps_built_in_lsp_runtime.rb → runtime_adapter.rb} +5 -8
  88. metadata +35 -10
  89. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d7c6408a777042eced58bec2bc889312b24d8701f5db99da3b471088f589d6f
4
- data.tar.gz: 27423e682d55f04840a3bf3d5e0301556e4a1c419857e3422ced38ec423c0003
3
+ metadata.gz: e3d6b4b7f7dd2a3128259ff94614da64550ae7c4148106a681987a9ee739b905
4
+ data.tar.gz: 023ed07c7e4445c1dc44b3062cf0199321e3cc7fc6d4abf55287d281519bdb11
5
5
  SHA512:
6
- metadata.gz: 8729a8ea3adae11fcb2501bfea338821a8f9894209ea6fb482b62ebfae87019e07ded7bf02d3371c18726b28c2491c79952e7b86c193388a045f886a833b427c
7
- data.tar.gz: 44251afbbbc2aa7c121033ea05f25e1b3447afba7487d04a81f9463347ba28bcea05bdc2e434248f15cd235d9e452cb3f9f378f94adb5507eeb6d5ce58ba4119
6
+ metadata.gz: cfc82c25468c882682017c7ab8f750970896dcacae270fc00fc6482e4a7d12a20c97f7f56509811fec8c811981be457fc450c977c058d72700490ae72a4aff0a
7
+ data.tar.gz: 04cfd985c5527d40ba6fd11e33e64278f37b8fcd78a63cfcdf5fef317bef248bfc8771febfa39a05a474372c1ad56190766dc7a188ea9e17bc72031f16d672da
data/README.md CHANGED
@@ -52,7 +52,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
52
52
  in your `Gemfile`:
53
53
 
54
54
  ```rb
55
- gem 'rubocop', '~> 1.71', require: false
55
+ gem 'rubocop', '~> 1.73', require: false
56
56
  ```
57
57
 
58
58
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -241,9 +241,9 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
241
241
  <a href="https://opencollective.com/rubocop/organization/28/website" target="_blank"><img src="https://opencollective.com/rubocop/organization/28/avatar.svg"></a>
242
242
  <a href="https://opencollective.com/rubocop/organization/29/website" target="_blank"><img src="https://opencollective.com/rubocop/organization/29/avatar.svg"></a>
243
243
 
244
- ## Changelog
244
+ ## Release Notes
245
245
 
246
- RuboCop's changelog is available [here](CHANGELOG.md).
246
+ RuboCop's release notes are available [here](https://github.com/rubocop/rubocop/releases).
247
247
 
248
248
  ## Copyright
249
249
 
data/config/default.yml CHANGED
@@ -1685,6 +1685,11 @@ Lint/ConstantResolution:
1685
1685
  # Restrict this cop from only looking at certain names
1686
1686
  Ignore: []
1687
1687
 
1688
+ Lint/CopDirectiveSyntax:
1689
+ Description: 'Checks that `# rubocop:` directives are strictly formatted.'
1690
+ Enabled: pending
1691
+ VersionAdded: '1.72'
1692
+
1688
1693
  Lint/Debugger:
1689
1694
  Description: 'Check for debugger calls.'
1690
1695
  Enabled: true
@@ -2041,6 +2046,7 @@ Lint/LambdaWithoutLiteralBlock:
2041
2046
  Lint/LiteralAsCondition:
2042
2047
  Description: 'Checks of literals used in conditions.'
2043
2048
  Enabled: true
2049
+ AutoCorrect: contextual
2044
2050
  VersionAdded: '0.51'
2045
2051
 
2046
2052
  Lint/LiteralAssignmentInCondition:
@@ -2254,9 +2260,8 @@ Lint/RedundantRegexpQuantifiers:
2254
2260
  Lint/RedundantRequireStatement:
2255
2261
  Description: 'Checks for unnecessary `require` statement.'
2256
2262
  Enabled: true
2257
- SafeAutoCorrect: false
2258
2263
  VersionAdded: '0.76'
2259
- VersionChanged: '1.57'
2264
+ VersionChanged: '1.73'
2260
2265
 
2261
2266
  Lint/RedundantSafeNavigation:
2262
2267
  Description: 'Checks for redundant safe navigation calls.'
@@ -2285,6 +2290,11 @@ Lint/RedundantStringCoercion:
2285
2290
  VersionAdded: '0.19'
2286
2291
  VersionChanged: '0.77'
2287
2292
 
2293
+ Lint/RedundantTypeConversion:
2294
+ Description: 'Checks for redundantly converting a literal to the same type.'
2295
+ Enabled: pending
2296
+ VersionAdded: '1.72'
2297
+
2288
2298
  Lint/RedundantWithIndex:
2289
2299
  Description: 'Checks for redundant `with_index`.'
2290
2300
  Enabled: true
@@ -2433,6 +2443,12 @@ Lint/SuppressedException:
2433
2443
  VersionAdded: '0.9'
2434
2444
  VersionChanged: '1.12'
2435
2445
 
2446
+ Lint/SuppressedExceptionInNumberConversion:
2447
+ Description: 'Checks for cases where exceptions unrelated to the numeric constructors may be unintentionally swallowed.'
2448
+ Enabled: pending
2449
+ SafeAutoCorrect: false
2450
+ VersionAdded: '1.72'
2451
+
2436
2452
  Lint/SymbolConversion:
2437
2453
  Description: 'Checks for unnecessary symbol conversions.'
2438
2454
  Enabled: pending
@@ -2588,6 +2604,11 @@ Lint/UselessAssignment:
2588
2604
  VersionAdded: '0.11'
2589
2605
  VersionChanged: '1.66'
2590
2606
 
2607
+ Lint/UselessConstantScoping:
2608
+ Description: 'Checks for useless constant scoping.'
2609
+ Enabled: pending
2610
+ VersionAdded: '1.72'
2611
+
2591
2612
  Lint/UselessDefined:
2592
2613
  Description: 'Checks for calls to `defined?` with strings and symbols. The result of such a call will always be truthy.'
2593
2614
  Enabled: pending
@@ -3041,6 +3062,8 @@ Naming/PredicateName:
3041
3062
  MethodDefinitionMacros:
3042
3063
  - define_method
3043
3064
  - define_singleton_method
3065
+ # Use Sorbet's T::Boolean return type to detect predicate methods.
3066
+ UseSorbetSigs: false
3044
3067
  # Exclude Rspec specs because there is a strong convention to write spec
3045
3068
  # helpers in the form of `have_something` or `be_something`.
3046
3069
  Exclude:
@@ -3058,13 +3081,15 @@ Naming/VariableName:
3058
3081
  StyleGuide: '#snake-case-symbols-methods-vars'
3059
3082
  Enabled: true
3060
3083
  VersionAdded: '0.50'
3061
- VersionChanged: '1.8'
3084
+ VersionChanged: '1.73'
3062
3085
  EnforcedStyle: snake_case
3063
3086
  SupportedStyles:
3064
3087
  - snake_case
3065
3088
  - camelCase
3066
3089
  AllowedIdentifiers: []
3067
3090
  AllowedPatterns: []
3091
+ ForbiddenIdentifiers: []
3092
+ ForbiddenPatterns: []
3068
3093
 
3069
3094
  Naming/VariableNumber:
3070
3095
  Description: 'Use the configured style when numbering symbols, methods and variables.'
@@ -3899,6 +3924,8 @@ Style/EndlessMethod:
3899
3924
  - allow_single_line
3900
3925
  - allow_always
3901
3926
  - disallow
3927
+ - require_single_line
3928
+ - require_always
3902
3929
 
3903
3930
  Style/EnvHome:
3904
3931
  Description: "Checks for consistent usage of `ENV['HOME']`."
@@ -5145,6 +5172,13 @@ Style/RedundantFilterChain:
5145
5172
  VersionAdded: '1.52'
5146
5173
  VersionChanged: '1.57'
5147
5174
 
5175
+ Style/RedundantFormat:
5176
+ Description: 'Checks for usages of `Kernel#format` or `Kernel#sprintf` with only a single argument.'
5177
+ Enabled: pending
5178
+ SafeAutoCorrect: false
5179
+ VersionAdded: '1.72'
5180
+ VersionChanged: '1.72'
5181
+
5148
5182
  Style/RedundantFreeze:
5149
5183
  Description: "Checks usages of Object#freeze on immutable objects."
5150
5184
  Enabled: true
@@ -5671,14 +5705,17 @@ Style/TrailingCommaInArrayLiteral:
5671
5705
  StyleGuide: '#no-trailing-array-commas'
5672
5706
  Enabled: true
5673
5707
  VersionAdded: '0.53'
5674
- # If `comma`, the cop requires a comma after the last item in an array,
5675
- # but only when each item is on its own line.
5676
- # If `consistent_comma`, the cop requires a comma after the last item of all
5677
- # non-empty, multiline array literals.
5708
+ # If `comma`, the cop requires a comma after the last item in an array, but only when each item is
5709
+ # on its own line.
5710
+ # If `consistent_comma`, the cop requires a comma after the last item of all non-empty, multiline
5711
+ # array literals.
5712
+ # If `diff_comma`, the cop requires a comma after the last item of all non-empty, multiline array
5713
+ # literals, but only when that last item immediately precedes a newline.
5678
5714
  EnforcedStyleForMultiline: no_comma
5679
5715
  SupportedStylesForMultiline:
5680
5716
  - comma
5681
5717
  - consistent_comma
5718
+ - diff_comma
5682
5719
  - no_comma
5683
5720
 
5684
5721
  Style/TrailingCommaInBlockArgs:
@@ -5690,14 +5727,17 @@ Style/TrailingCommaInBlockArgs:
5690
5727
  Style/TrailingCommaInHashLiteral:
5691
5728
  Description: 'Checks for trailing comma in hash literals.'
5692
5729
  Enabled: true
5693
- # If `comma`, the cop requires a comma after the last item in a hash,
5694
- # but only when each item is on its own line.
5695
- # If `consistent_comma`, the cop requires a comma after the last item of all
5696
- # non-empty, multiline hash literals.
5730
+ # If `comma`, the cop requires a comma after the last item in a hash, but only when each item is
5731
+ # on its own line.
5732
+ # If `consistent_comma`, the cop requires a comma after the last item of all non-empty, multiline
5733
+ # hash literals.
5734
+ # If `diff_comma`, the cop requires a comma after the last item of all non-empty, multiline hash
5735
+ # literals, but only when that last item immediately precedes a newline.
5697
5736
  EnforcedStyleForMultiline: no_comma
5698
5737
  SupportedStylesForMultiline:
5699
5738
  - comma
5700
5739
  - consistent_comma
5740
+ - diff_comma
5701
5741
  - no_comma
5702
5742
  VersionAdded: '0.53'
5703
5743
 
@@ -6,6 +6,22 @@ InternalAffairs/CopDescription:
6
6
  Include:
7
7
  - 'lib/rubocop/cop/**/*.rb'
8
8
 
9
+ InternalAffairs/ExampleHeredocDelimiter:
10
+ Include:
11
+ - 'spec/rubocop/cop/**/*.rb'
12
+
13
+ InternalAffairs/ExampleDescription:
14
+ Include:
15
+ - 'spec/rubocop/cop/**/*.rb'
16
+
17
+ InternalAffairs/OnSendWithoutOnCSend:
18
+ Include:
19
+ - 'lib/rubocop/cop/**/*.rb'
20
+
21
+ InternalAffairs/UndefinedConfig:
22
+ Include:
23
+ - 'lib/rubocop/cop/**/*.rb'
24
+
9
25
  InternalAffairs/UselessMessageAssertion:
10
26
  Include:
11
27
  - '**/*_spec.rb'
@@ -97,7 +97,13 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def loaded_extensions
100
- @config_store.for_pwd.loaded_features.to_a
100
+ rubocop_config = @config_store.for_pwd
101
+
102
+ plugin_names = rubocop_config.loaded_plugins.map do |plugin|
103
+ plugin.about.name
104
+ end
105
+
106
+ plugin_names + rubocop_config.loaded_features.to_a
101
107
  end
102
108
 
103
109
  def installed_and_not_loaded_extensions
@@ -205,7 +205,7 @@ module RuboCop
205
205
  directive.cop_names.each do |name|
206
206
  if directive.disabled?
207
207
  names[name] += 1
208
- elsif (names[name]).positive?
208
+ elsif names[name].positive?
209
209
  names[name] -= 1
210
210
  else
211
211
  extras[directive.comment] << name
@@ -45,6 +45,10 @@ module RuboCop
45
45
  end
46
46
  # rubocop:enable Metrics/AbcSize
47
47
 
48
+ def loaded_plugins
49
+ @loaded_plugins ||= ConfigLoader.loaded_plugins
50
+ end
51
+
48
52
  def loaded_features
49
53
  @loaded_features ||= ConfigLoader.loaded_features
50
54
  end
@@ -33,13 +33,14 @@ module RuboCop
33
33
  attr_accessor :debug, :ignore_parent_exclusion, :disable_pending_cops, :enable_pending_cops,
34
34
  :ignore_unrecognized_cops
35
35
  attr_writer :default_configuration
36
- attr_reader :loaded_features
36
+ attr_reader :loaded_plugins, :loaded_features
37
37
 
38
38
  alias debug? debug
39
39
  alias ignore_parent_exclusion? ignore_parent_exclusion
40
40
 
41
41
  def clear_options
42
42
  @debug = nil
43
+ @loaded_plugins = Set.new
43
44
  @loaded_features = Set.new
44
45
  @disable_pending_cops = nil
45
46
  @enable_pending_cops = nil
@@ -48,11 +49,17 @@ module RuboCop
48
49
  FileFinder.root_level = nil
49
50
  end
50
51
 
52
+ # rubocop:disable Metrics/AbcSize
51
53
  def load_file(file, check: true)
52
54
  path = file_path(file)
53
55
 
54
56
  hash = load_yaml_configuration(path)
55
57
 
58
+ rubocop_config = Config.create(hash, path, check: false)
59
+ plugins = hash.delete('plugins')
60
+ loaded_plugins = resolver.resolve_plugins(rubocop_config, plugins)
61
+ add_loaded_plugins(loaded_plugins)
62
+
56
63
  loaded_features = resolver.resolve_requires(path, hash)
57
64
  add_loaded_features(loaded_features)
58
65
 
@@ -67,6 +74,7 @@ module RuboCop
67
74
 
68
75
  Config.create(hash, path, check: check)
69
76
  end
77
+ # rubocop:enable Metrics/AbcSize
70
78
 
71
79
  def load_yaml_configuration(absolute_path)
72
80
  file_contents = read_file(absolute_path)
@@ -155,14 +163,35 @@ module RuboCop
155
163
  end
156
164
  end
157
165
 
158
- # @api private
159
- def inject_defaults!(project_root)
160
- path = File.join(project_root, 'config', 'default.yml')
161
- config = load_file(path)
162
- new_config = ConfigLoader.merge_with_default(config, path)
163
- puts "configuration from #{path}" if debug?
164
- @default_configuration = new_config
166
+ # This API is primarily intended for testing and documenting plugins.
167
+ # When testing a plugin using `rubocop/rspec/support`, the plugin is loaded automatically,
168
+ # so this API is usually not needed. It is intended to be used only when implementing tests
169
+ # that do not use `rubocop/rspec/support`.
170
+ # rubocop:disable Metrics/MethodLength
171
+ def inject_defaults!(config_yml_path)
172
+ if Pathname(config_yml_path).directory?
173
+ # TODO: Since the warning noise is expected to be high until some time after the release,
174
+ # warnings will only be issued when `RUBYOPT=-w` is specified.
175
+ # To proceed step by step, the next step is to remove `$VERBOSE` and always issue warning.
176
+ # Eventually, `project_root` will no longer be accepted.
177
+ if $VERBOSE
178
+ warn Rainbow(<<~MESSAGE).yellow, uplevel: 1
179
+ Use config YAML file path instead of project root directory.
180
+ e.g., `path/to/config/default.yml`
181
+ MESSAGE
182
+ end
183
+ # NOTE: For compatibility.
184
+ project_root = config_yml_path
185
+ path = File.join(project_root, 'config', 'default.yml')
186
+ config = load_file(path)
187
+ else
188
+ hash = ConfigLoader.load_yaml_configuration(config_yml_path.to_s)
189
+ config = Config.new(hash, config_yml_path).tap(&:make_excludes_absolute)
190
+ end
191
+
192
+ @default_configuration = ConfigLoader.merge_with_default(config, path)
165
193
  end
194
+ # rubocop:enable Metrics/MethodLength
166
195
 
167
196
  # Returns the path RuboCop inferred as the root of the project. No file
168
197
  # searches will go past this directory.
@@ -196,6 +225,13 @@ module RuboCop
196
225
  resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
197
226
  end
198
227
 
228
+ # @api private
229
+ # Used to add plugins that were required inside a config or from
230
+ # the CLI using `--plugin`.
231
+ def add_loaded_plugins(loaded_plugins)
232
+ @loaded_plugins.merge(Array(loaded_plugins))
233
+ end
234
+
199
235
  # @api private
200
236
  # Used to add features that were required inside a config or from
201
237
  # the CLI using `--require`.
@@ -2,16 +2,34 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'yaml'
5
+ require_relative 'plugin'
5
6
 
6
7
  module RuboCop
7
8
  # A help class for ConfigLoader that handles configuration resolution.
8
9
  # @api private
9
10
  class ConfigLoaderResolver # rubocop:disable Metrics/ClassLength
11
+ def resolve_plugins(rubocop_config, plugins)
12
+ return if (plugins = Array(plugins)).empty?
13
+
14
+ Plugin.integrate_plugins(rubocop_config, plugins)
15
+ end
16
+
10
17
  def resolve_requires(path, hash)
11
18
  config_dir = File.dirname(path)
12
19
  hash.delete('require').tap do |loaded_features|
13
20
  Array(loaded_features).each do |feature|
14
- FeatureLoader.load(config_directory_path: config_dir, feature: feature)
21
+ if Plugin.plugin_capable?(feature)
22
+ # NOTE: Compatibility for before plugins style.
23
+ warn Rainbow(<<~MESSAGE).yellow
24
+ #{feature} extension supports plugin, specify `plugins: #{feature}` instead of `require: #{feature}` in #{path}.
25
+ For more information, see https://docs.rubocop.org/rubocop/plugin_migration_guide.html.
26
+ MESSAGE
27
+ rubocop_config = Config.create(hash, path, check: false)
28
+
29
+ resolve_plugins(rubocop_config, feature)
30
+ else
31
+ FeatureLoader.load(config_directory_path: config_dir, feature: feature)
32
+ end
15
33
  end
16
34
  end
17
35
  end
@@ -105,7 +123,7 @@ module RuboCop
105
123
  elsif merge_hashes?(base_hash, derived_hash, key)
106
124
  result[key] = merge(base_hash[key], derived_hash[key], **opts)
107
125
  elsif should_union?(derived_hash, base_hash, opts[:inherit_mode], key)
108
- result[key] = base_hash[key] | derived_hash[key]
126
+ result[key] = Array(base_hash[key]) | Array(derived_hash[key])
109
127
  elsif opts[:debug]
110
128
  warn_on_duplicate_setting(base_hash, derived_hash, key, **opts)
111
129
  end
@@ -157,7 +175,7 @@ module RuboCop
157
175
  return false if inherited_file.nil? # Not inheritance resolving merge
158
176
  return false if inherited_file.start_with?('..') # Legitimate override
159
177
  return false if base_hash[key] == derived_hash[key] # Same value
160
- return false if remote_file?(inherited_file) # Can't change
178
+ return false if PathUtil.remote_file?(inherited_file) # Can't change
161
179
 
162
180
  Gem.path.none? { |dir| inherited_file.start_with?(dir) } # Can change?
163
181
  end
@@ -187,7 +205,7 @@ module RuboCop
187
205
  end
188
206
 
189
207
  def should_union?(derived_hash, base_hash, root_mode, key)
190
- return false unless base_hash[key].is_a?(Array)
208
+ return false unless base_hash[key].is_a?(Array) || derived_hash[key].is_a?(Array)
191
209
 
192
210
  derived_mode = derived_hash['inherit_mode']
193
211
  return false if should_override?(derived_mode, key)
@@ -225,7 +243,7 @@ module RuboCop
225
243
  end
226
244
 
227
245
  def inherited_file(path, inherit_from, file)
228
- if remote_file?(inherit_from)
246
+ if PathUtil.remote_file?(inherit_from)
229
247
  # A remote configuration, e.g. `inherit_from: http://example.com/rubocop.yml`.
230
248
  RemoteConfig.new(inherit_from, File.dirname(path))
231
249
  elsif Pathname.new(inherit_from).absolute?
@@ -245,10 +263,6 @@ module RuboCop
245
263
  end
246
264
  end
247
265
 
248
- def remote_file?(uri)
249
- uri.start_with?('http://', 'https://')
250
- end
251
-
252
266
  def remote_config?(file)
253
267
  file.is_a?(RemoteConfig)
254
268
  end
@@ -9,7 +9,7 @@ module RuboCop
9
9
 
10
10
  # @api private
11
11
  COMMON_PARAMS = %w[Exclude Include Severity inherit_mode AutoCorrect StyleGuide Details
12
- Enabled].freeze
12
+ Enabled Reference].freeze
13
13
  # @api private
14
14
  INTERNAL_PARAMS = %w[Description StyleGuide
15
15
  VersionAdded VersionChanged VersionRemoved
@@ -90,8 +90,10 @@ module RuboCop
90
90
  description_text = string_contents(current_description)
91
91
  return unless (new_description = correct_description(description_text, description_map))
92
92
 
93
+ quote = current_description.dstr_type? ? '"' : "'"
94
+
93
95
  add_offense(current_description, message: message) do |corrector|
94
- corrector.replace(current_description, "'#{new_description}'")
96
+ corrector.replace(current_description, "#{quote}#{new_description}#{quote}")
95
97
  end
96
98
  end
97
99
 
@@ -106,7 +108,7 @@ module RuboCop
106
108
  end
107
109
 
108
110
  def string_contents(node)
109
- node.str_type? ? node.value : node.source
111
+ node.type?(:str, :dstr) ? node.value : node.source
110
112
  end
111
113
  end
112
114
  end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # When a node location may not exist, `Node#loc?` or `Node#loc_is?`
7
+ # can be used instead of calling `Node#respond_to?` before using
8
+ # the value.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # node.loc.respond_to?(:begin) && node.loc.begin
13
+ #
14
+ # # good
15
+ # node.loc?(:begin)
16
+ #
17
+ # # bad
18
+ # node.loc.respond_to?(:begin) && node.loc.begin.is?('(')
19
+ #
20
+ # # good
21
+ # node.loc_is?(:begin, '(')
22
+ #
23
+ # # bad
24
+ # node.loc.respond_to?(:begin) && node.loc.begin.source == '('
25
+ #
26
+ # # good
27
+ # node.loc_is?(:begin, '(')
28
+ #
29
+ class LocationExists < Base
30
+ extend AutoCorrector
31
+
32
+ MSG = 'Use `%<replacement>s` instead of `%<source>s`.'
33
+
34
+ # @!method replaceable_with_loc_is(node)
35
+ def_node_matcher :replaceable_with_loc_is, <<~PATTERN
36
+ (and
37
+ (call
38
+ (call $_receiver :loc) :respond_to?
39
+ $(sym _location))
40
+ {
41
+ (call
42
+ (call
43
+ (call _receiver :loc) _location) :is?
44
+ $(str _))
45
+ (call
46
+ (call
47
+ (call
48
+ (call _receiver :loc) _location) :source) :==
49
+ $(str _))
50
+ })
51
+ PATTERN
52
+
53
+ # @!method replaceable_with_loc(node)
54
+ def_node_matcher :replaceable_with_loc, <<~PATTERN
55
+ (and
56
+ (call
57
+ (call $_receiver :loc) :respond_to?
58
+ $(sym _location))
59
+ (call
60
+ (call _receiver :loc) _location))
61
+ PATTERN
62
+
63
+ def on_and(node)
64
+ replace_with_loc(node) || replace_with_loc_is(node)
65
+ end
66
+
67
+ private
68
+
69
+ def replace_with_loc(node)
70
+ replaceable_with_loc(node) do |receiver, location|
71
+ if node.parent&.assignment?
72
+ register_offense(node, replace_assignment(receiver, location))
73
+ else
74
+ register_offense(node, replacement(receiver, "loc?(#{location.source})"))
75
+ end
76
+ end
77
+ end
78
+
79
+ def replace_with_loc_is(node)
80
+ replaceable_with_loc_is(node) do |receiver, location, value|
81
+ replacement = replacement(receiver, "loc_is?(#{location.source}, #{value.source})")
82
+ register_offense(node, replacement)
83
+ end
84
+ end
85
+
86
+ def register_offense(node, replacement)
87
+ message = format(MSG, replacement: replacement, source: node.source)
88
+
89
+ add_offense(node, message: message) do |corrector|
90
+ corrector.replace(node, replacement)
91
+ end
92
+ end
93
+
94
+ def replacement(receiver, rest)
95
+ "#{replace_receiver(receiver)}#{rest}"
96
+ end
97
+
98
+ def replace_assignment(receiver, location)
99
+ prefix = replace_receiver(receiver)
100
+
101
+ "#{prefix}loc#{dot(receiver)}#{location.value} if #{prefix}loc?(#{location.source})"
102
+ end
103
+
104
+ def replace_receiver(receiver)
105
+ return '' unless receiver
106
+
107
+ "#{receiver.source}#{dot(receiver)}"
108
+ end
109
+
110
+ def dot(node)
111
+ node.parent.loc.dot.source
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module InternalAffairs
6
- # rubocop:disable InternalAffairs/RedundantSourceRange - node here is a `NodePattern::Node`
6
+ # rubocop:disable InternalAffairs/RedundantSourceRange -- node here is a `NodePattern::Node`
7
7
  class NodePatternGroups
8
8
  # Walks an AST that has been processed by `InternalAffairs::NodePatternGroups::Processor`
9
9
  # in order to find `node_type` and `node_sequence` nodes that can be replaced with a node
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lint_roller'
4
+
5
+ module RuboCop
6
+ module InternalAffairs
7
+ # A Plugin for `InternalAffairs` department, which has internal cops.
8
+ class Plugin < LintRoller::Plugin
9
+ def about
10
+ LintRoller::About.new(
11
+ name: 'rubocop-internal_affairs',
12
+ version: Version::STRING,
13
+ homepage: 'https://github.com/rubocop/rubocop/tree/master/lib/rubocop/cop/internal_affairs',
14
+ description: 'A collection of RuboCop cops to check for internal affairs.'
15
+ )
16
+ end
17
+
18
+ def supported?(context)
19
+ context.engine == :rubocop
20
+ end
21
+
22
+ def rules(_context)
23
+ require_relative '../internal_affairs'
24
+
25
+ LintRoller::Rules.new(
26
+ type: :path,
27
+ config_format: :rubocop,
28
+ value: Pathname.new(__dir__).join('../../../../config/internal_affairs.yml')
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
@@ -17,7 +17,13 @@ module RuboCop
17
17
  'in `config/default.yml`.'
18
18
  CONFIG_PATH = find_file_upwards('config/default.yml', Dir.pwd)
19
19
  CONFIG = if CONFIG_PATH
20
- ConfigLoader.load_yaml_configuration(CONFIG_PATH)
20
+ begin
21
+ original_debug = ConfigLoader.debug
22
+ ConfigLoader.debug = false
23
+ ConfigLoader.load_yaml_configuration(CONFIG_PATH)
24
+ ensure
25
+ ConfigLoader.debug = original_debug
26
+ end
21
27
  else
22
28
  {}
23
29
  end
@@ -8,6 +8,7 @@ require_relative 'internal_affairs/example_description'
8
8
  require_relative 'internal_affairs/example_heredoc_delimiter'
9
9
  require_relative 'internal_affairs/inherit_deprecated_cop_class'
10
10
  require_relative 'internal_affairs/lambda_or_proc'
11
+ require_relative 'internal_affairs/location_exists'
11
12
  require_relative 'internal_affairs/location_expression'
12
13
  require_relative 'internal_affairs/location_line_equality_comparison'
13
14
  require_relative 'internal_affairs/method_name_end_with'
@@ -36,19 +37,3 @@ require_relative 'internal_affairs/style_detected_api_use'
36
37
  require_relative 'internal_affairs/undefined_config'
37
38
  require_relative 'internal_affairs/useless_message_assertion'
38
39
  require_relative 'internal_affairs/useless_restrict_on_send'
39
-
40
- module RuboCop
41
- # Patch in the InternalAffairs specific config values
42
- module InternalAffairs
43
- def self.inject!
44
- path = File.join(ConfigLoader::RUBOCOP_HOME, 'config', 'internal_affairs.yml')
45
- hash = ConfigLoader.load_yaml_configuration(path)
46
- config = Config.new(hash, path)
47
- puts "configuration from #{path}" if ConfigLoader.debug?
48
- config = ConfigLoader.merge_with_default(config, path)
49
- ConfigLoader.instance_variable_set(:@default_configuration, config)
50
- end
51
- end
52
- end
53
-
54
- RuboCop::InternalAffairs.inject!
@@ -73,6 +73,8 @@ module RuboCop
73
73
  # @!method block_end_align_target?(node, child)
74
74
  def_node_matcher :block_end_align_target?, <<~PATTERN
75
75
  {assignment?
76
+ def
77
+ defs
76
78
  splat
77
79
  and
78
80
  or