rubocop 1.71.2 → 1.72.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +28 -0
  4. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  5. data/lib/rubocop/comment_config.rb +1 -1
  6. data/lib/rubocop/config.rb +4 -0
  7. data/lib/rubocop/config_loader.rb +40 -8
  8. data/lib/rubocop/config_loader_resolver.rb +21 -7
  9. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  10. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -1
  11. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  12. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  13. data/lib/rubocop/cop/internal_affairs.rb +1 -16
  14. data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
  15. data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
  16. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  17. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  18. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  19. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  20. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  21. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  22. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  23. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +221 -0
  24. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  25. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +74 -0
  26. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  27. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  28. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  29. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +18 -18
  30. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  31. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  32. data/lib/rubocop/cop/mixin/range_help.rb +3 -3
  33. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  34. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  35. data/lib/rubocop/cop/style/redundant_format.rb +222 -0
  36. data/lib/rubocop/cop/style/redundant_parentheses.rb +17 -3
  37. data/lib/rubocop/cop/util.rb +1 -1
  38. data/lib/rubocop/cop/utils/format_string.rb +7 -5
  39. data/lib/rubocop/directive_comment.rb +35 -2
  40. data/lib/rubocop/lsp/runtime.rb +2 -0
  41. data/lib/rubocop/lsp/server.rb +0 -2
  42. data/lib/rubocop/options.rb +26 -11
  43. data/lib/rubocop/path_util.rb +4 -0
  44. data/lib/rubocop/plugin/configuration_integrator.rb +141 -0
  45. data/lib/rubocop/plugin/load_error.rb +35 -0
  46. data/lib/rubocop/plugin/loader.rb +100 -0
  47. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  48. data/lib/rubocop/plugin.rb +39 -0
  49. data/lib/rubocop/rake_task.rb +4 -1
  50. data/lib/rubocop/server/cache.rb +35 -2
  51. data/lib/rubocop/server/cli.rb +2 -2
  52. data/lib/rubocop/version.rb +17 -2
  53. data/lib/rubocop.rb +5 -0
  54. data/lib/ruby_lsp/rubocop/addon.rb +7 -10
  55. data/lib/ruby_lsp/rubocop/{wraps_built_in_lsp_runtime.rb → runtime_adapter.rb} +5 -8
  56. metadata +35 -9
@@ -22,8 +22,6 @@ module RuboCop
22
22
  def initialize(config_store)
23
23
  $PROGRAM_NAME = "rubocop --lsp #{ConfigFinder.project_root}"
24
24
 
25
- RuboCop::LSP.enable
26
-
27
25
  @reader = LanguageServer::Protocol::Transport::Io::Reader.new($stdin)
28
26
  @writer = LanguageServer::Protocol::Transport::Io::Writer.new($stdout)
29
27
  @runtime = RuboCop::LSP::Runtime.new(config_store)
@@ -243,6 +243,7 @@ module RuboCop
243
243
  option(opts, '--init')
244
244
  option(opts, '-c', '--config FILE')
245
245
  option(opts, '-d', '--debug')
246
+ option(opts, '--plugin FILE') { |f| plugin_feature(f) }
246
247
  option(opts, '-r', '--require FILE') { |f| require_feature(f) }
247
248
  option(opts, '--[no-]color')
248
249
  option(opts, '-v', '--version')
@@ -299,11 +300,25 @@ module RuboCop
299
300
  long_opt[2..].sub('[no-]', '').sub(/ .*/, '').tr('-', '_').gsub(/[\[\]]/, '').to_sym
300
301
  end
301
302
 
302
- def require_feature(file)
303
- # If any features were added on the CLI from `--require`,
303
+ def plugin_feature(file)
304
+ # If any features were added on the CLI from `--plugin`,
304
305
  # add them to the config.
305
- ConfigLoader.add_loaded_features(file)
306
- require file
306
+ ConfigLoaderResolver.new.resolve_plugins(Config.new, file)
307
+ end
308
+
309
+ def require_feature(file)
310
+ if Plugin.plugin_capable?(file)
311
+ # NOTE: Compatibility for before plugins style.
312
+ warn Rainbow(<<~MESSAGE).yellow
313
+ #{file} gem supports plugin, use `--plugin` instead of `--require`.
314
+ MESSAGE
315
+ plugin_feature(file)
316
+ else
317
+ # If any features were added on the CLI from `--require`,
318
+ # add them to the config.
319
+ require file
320
+ ConfigLoader.add_loaded_features(file)
321
+ end
307
322
  end
308
323
  end
309
324
 
@@ -397,7 +412,7 @@ module RuboCop
397
412
  return if @options[:format] == 'junit'
398
413
 
399
414
  raise OptionArgumentError,
400
- format('--display-only-failed can only be used together with --format junit.')
415
+ '--display-only-failed can only be used together with --format junit.'
401
416
  end
402
417
 
403
418
  def validate_display_only_correctable_and_autocorrect
@@ -415,14 +430,13 @@ module RuboCop
415
430
  !@options.key?(:display_only_safe_correctable)
416
431
 
417
432
  raise OptionArgumentError,
418
- format('--display-only-failed cannot be used together with other display options.')
433
+ '--display-only-failed cannot be used together with other display options.'
419
434
  end
420
435
 
421
436
  def validate_lsp_and_editor_mode
422
437
  return if !@options.key?(:lsp) || !@options.key?(:editor_mode)
423
438
 
424
- raise OptionArgumentError,
425
- format('Do not specify `--editor-mode` as it is redundant in `--lsp`.')
439
+ raise OptionArgumentError, 'Do not specify `--editor-mode` as it is redundant in `--lsp`.'
426
440
  end
427
441
 
428
442
  def validate_autocorrect
@@ -436,7 +450,7 @@ module RuboCop
436
450
  return unless @options.key?(:disable_uncorrectable)
437
451
 
438
452
  raise OptionArgumentError,
439
- format('--disable-uncorrectable can only be used together with --autocorrect.')
453
+ '--disable-uncorrectable can only be used together with --autocorrect.'
440
454
  end
441
455
 
442
456
  def disable_parallel_when_invalid_option_combo
@@ -504,6 +518,7 @@ module RuboCop
504
518
  only_guide_cops: ['Run only cops for rules that link to a',
505
519
  'style guide.'],
506
520
  except: 'Exclude the given cop(s).',
521
+ plugin: 'Load a RuboCop plugin.',
507
522
  require: 'Require Ruby file.',
508
523
  config: 'Specify configuration file.',
509
524
  auto_gen_config: ['Generate a configuration file acting as a',
@@ -542,8 +557,8 @@ module RuboCop
542
557
  only_recognized_file_types: ['Inspect files given on the command line only if',
543
558
  'they are listed in `AllCops/Include` parameters',
544
559
  'of user configuration or default configuration.'],
545
- ignore_disable_comments: ['Run cops even when they are disabled locally',
546
- 'by a `rubocop:disable` directive.'],
560
+ ignore_disable_comments: ['Report offenses even if they have been manually disabled',
561
+ 'with a `rubocop:disable` or `rubocop:todo` directive.'],
547
562
  ignore_parent_exclusion: ['Prevent from inheriting `AllCops/Exclude` from',
548
563
  'parent folders.'],
549
564
  ignore_unrecognized_cops: ['Ignore unrecognized cops or departments in the config.'],
@@ -28,6 +28,10 @@ module RuboCop
28
28
  end
29
29
  end
30
30
 
31
+ def remote_file?(uri)
32
+ uri.start_with?('http://', 'https://')
33
+ end
34
+
31
35
  SMART_PATH_CACHE = {} # rubocop:disable Style/MutableConstant
32
36
  private_constant :SMART_PATH_CACHE
33
37
 
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lint_roller/context'
4
+ require_relative 'not_supported_error'
5
+
6
+ module RuboCop
7
+ module Plugin
8
+ # A class for integrating plugin configurations into RuboCop.
9
+ # Handles configuration merging, validation, and compatibility for plugins.
10
+ # @api private
11
+ class ConfigurationIntegrator
12
+ class << self
13
+ def integrate_plugins_into_rubocop_config(rubocop_config, plugins)
14
+ default_config = ConfigLoader.default_configuration
15
+ runner_context = create_context(rubocop_config)
16
+
17
+ validate_plugins!(plugins, runner_context)
18
+
19
+ plugin_config = combine_rubocop_configs(default_config, runner_context, plugins).to_h
20
+
21
+ merge_plugin_config_into_all_cops!(default_config, plugin_config)
22
+ merge_plugin_config_into_default_config!(default_config, plugin_config)
23
+ end
24
+
25
+ private
26
+
27
+ def create_context(rubocop_config)
28
+ LintRoller::Context.new(
29
+ runner: :rubocop,
30
+ runner_version: Version.version,
31
+ engine: :rubocop,
32
+ engine_version: Version.version,
33
+ target_ruby_version: rubocop_config.target_ruby_version
34
+ )
35
+ end
36
+
37
+ def validate_plugins!(plugins, runner_context)
38
+ unsupported_plugins = plugins.reject { |plugin| plugin.supported?(runner_context) }
39
+ return if unsupported_plugins.none?
40
+
41
+ raise Plugin::NotSupportedError, unsupported_plugins
42
+ end
43
+
44
+ def combine_rubocop_configs(default_config, runner_context, plugins)
45
+ fake_out_rubocop_default_configuration(default_config) do |fake_config|
46
+ all_cop_keys_configured_by_plugins = []
47
+
48
+ plugins.reduce(fake_config) do |combined_config, plugin|
49
+ RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, combined_config)
50
+
51
+ print 'Plugin ' if ConfigLoader.debug
52
+
53
+ plugin_config, plugin_config_path = load_plugin_rubocop_config(plugin, runner_context)
54
+
55
+ plugin_config['AllCops'], all_cop_keys_configured_by_plugins = merge_all_cop_settings(
56
+ combined_config['AllCops'], plugin_config['AllCops'],
57
+ all_cop_keys_configured_by_plugins
58
+ )
59
+
60
+ ConfigLoader.merge_with_default(plugin_config, plugin_config_path)
61
+ end
62
+ end
63
+ end
64
+
65
+ def merge_plugin_config_into_all_cops!(rubocop_config, plugin_config)
66
+ rubocop_config['AllCops'].merge!(plugin_config['AllCops'])
67
+ end
68
+
69
+ def merge_plugin_config_into_default_config!(default_config, plugin_config)
70
+ plugin_config.each do |key, value|
71
+ default_config[key] = if default_config[key].is_a?(Hash)
72
+ resolver.merge(default_config[key], value)
73
+ else
74
+ value
75
+ end
76
+ end
77
+ end
78
+
79
+ def fake_out_rubocop_default_configuration(default_config)
80
+ orig_default_config = ConfigLoader.instance_variable_get(:@default_configuration)
81
+
82
+ result = yield default_config
83
+
84
+ ConfigLoader.instance_variable_set(:@default_configuration, orig_default_config)
85
+
86
+ result
87
+ end
88
+
89
+ # rubocop:disable Metrics/AbcSize
90
+ def load_plugin_rubocop_config(plugin, runner_context)
91
+ rules = plugin.rules(runner_context)
92
+
93
+ case rules.type
94
+ when :path
95
+ [ConfigLoader.load_file(rules.value, check: false), rules.value]
96
+ when :object
97
+ path = plugin.method(:rules).source_location[0]
98
+ [Config.create(rules.value, path, check: true), path]
99
+ when :error
100
+ plugin_name = plugin.about&.name || plugin.inspect
101
+ error_message = rules.value.respond_to?(:message) ? rules.value.message : rules.value
102
+
103
+ raise "Plugin `#{plugin_name}' failed to load with error: #{error_message}"
104
+ end
105
+ end
106
+ # rubocop:enable Metrics/AbcSize
107
+
108
+ # This is how we ensure "first-in wins": plugins can override AllCops settings that are
109
+ # set by RuboCop's default configuration, but once a plugin sets an AllCop setting, they
110
+ # have exclusive first-in-wins rights to that setting.
111
+ #
112
+ # The one exception to this are array fields, because we don't want to
113
+ # overwrite the AllCops defaults but rather munge the arrays (`existing |
114
+ # new`) to allow plugins to add to the array, for example Include and
115
+ # Exclude paths and patterns.
116
+ def merge_all_cop_settings(existing_all_cops, new_all_cops, already_configured_keys)
117
+ return [existing_all_cops, already_configured_keys] unless new_all_cops.is_a?(Hash)
118
+
119
+ combined_all_cops = existing_all_cops.dup
120
+ combined_configured_keys = already_configured_keys.dup
121
+
122
+ new_all_cops.each do |key, value|
123
+ if combined_all_cops[key].is_a?(Array) && value.is_a?(Array)
124
+ combined_all_cops[key] |= value
125
+ combined_configured_keys |= [key]
126
+ elsif !combined_configured_keys.include?(key)
127
+ combined_all_cops[key] = value
128
+ combined_configured_keys << key
129
+ end
130
+ end
131
+
132
+ [combined_all_cops, combined_configured_keys]
133
+ end
134
+
135
+ def resolver
136
+ @resolver ||= ConfigLoaderResolver.new
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Plugin
5
+ # An exception raised when a plugin fails to load.
6
+ # @api private
7
+ class LoadError < Error
8
+ def initialize(plugin_name)
9
+ super
10
+
11
+ @plugin_name = plugin_name
12
+ end
13
+
14
+ def message
15
+ <<~MESSAGE
16
+ Failed loading plugin `#{@plugin_name}` because we couldn't determine the corresponding plugin class to instantiate.
17
+ First, try upgrading it. If the issue persists, please check with the developer regarding the following points.
18
+
19
+ RuboCop plugin class names must either be:
20
+
21
+ - If the plugin is a gem, defined in the gemspec as `default_lint_roller_plugin'
22
+
23
+ spec.metadata['default_lint_roller_plugin'] = 'MyModule::Plugin'
24
+
25
+ - Set in YAML as `plugin_class_name'; example:
26
+
27
+ plugins:
28
+ - incomplete:
29
+ require_path: my_module/plugin
30
+ plugin_class_name: "MyModule::Plugin"
31
+ MESSAGE
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../feature_loader'
4
+ require_relative 'load_error'
5
+
6
+ module RuboCop
7
+ module Plugin
8
+ # A class for loading and resolving plugins.
9
+ # @api private
10
+ class Loader
11
+ # rubocop:disable Layout/LineLength
12
+ DEFAULT_PLUGIN_CONFIG = {
13
+ 'enabled' => true,
14
+ 'require_path' => nil, # If not set, will be set to the plugin name
15
+ 'plugin_class_name' => nil # If not set, looks for gemspec `spec.metadata["default_lint_roller_plugin"]`
16
+ }.freeze
17
+
18
+ # rubocop:enable Layout/LineLength
19
+ class << self
20
+ def load(plugins)
21
+ normalized_plugin_configs = normalize(plugins)
22
+ normalized_plugin_configs.filter_map do |plugin_name, plugin_config|
23
+ next unless plugin_config['enabled']
24
+
25
+ plugin_class = constantize_plugin_from(plugin_name, plugin_config)
26
+
27
+ plugin_class.new(plugin_config)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # rubocop:disable Metrics/MethodLength
34
+ def normalize(plugin_configs)
35
+ plugin_configs.to_h do |plugin_config|
36
+ if plugin_config == Plugin::OBSOLETE_INTERNAL_AFFAIRS_PLUGIN_NAME
37
+ warn Rainbow(<<~MESSAGE).yellow
38
+ Specify `rubocop-internal_affairs` instead of `rubocop/cop/internal_affairs` in your configuration.
39
+ MESSAGE
40
+ plugin_config = Plugin::INTERNAL_AFFAIRS_PLUGIN_NAME
41
+ end
42
+
43
+ if plugin_config.is_a?(Hash)
44
+ plugin_name = plugin_config.keys.first
45
+
46
+ [
47
+ plugin_name, DEFAULT_PLUGIN_CONFIG.merge(
48
+ { 'require_path' => plugin_name }, plugin_config.values.first
49
+ )
50
+ ]
51
+ # NOTE: Compatibility is maintained when `require: rubocop/cop/internal_affairs` remains
52
+ # specified in `.rubocop.yml`.
53
+ elsif (builtin_plugin_config = Plugin::BUILTIN_INTERNAL_PLUGINS[plugin_config])
54
+ [plugin_config, builtin_plugin_config]
55
+ else
56
+ [plugin_config, DEFAULT_PLUGIN_CONFIG.merge('require_path' => plugin_config)]
57
+ end
58
+ end
59
+ end
60
+
61
+ def constantize_plugin_from(plugin_name, plugin_config)
62
+ if plugin_name.is_a?(String) || plugin_name.is_a?(Symbol)
63
+ constantize(plugin_name, plugin_config)
64
+ else
65
+ plugin_name
66
+ end
67
+ end
68
+
69
+ # rubocop:enable Metrics/MethodLength
70
+ def constantize(plugin_name, plugin_config)
71
+ require_plugin(plugin_config['require_path'])
72
+
73
+ if (constant_name = plugin_config['plugin_class_name'])
74
+ begin
75
+ Kernel.const_get(constant_name)
76
+ rescue StandardError
77
+ raise <<~MESSAGE
78
+ Failed while configuring plugin `#{plugin_name}': no constant with name `#{constant_name}' was found.
79
+ MESSAGE
80
+ end
81
+ else
82
+ constantize_plugin_from_gemspec_metadata(plugin_name)
83
+ end
84
+ end
85
+
86
+ def require_plugin(require_path)
87
+ FeatureLoader.load(config_directory_path: Dir.pwd, feature: require_path)
88
+ end
89
+
90
+ def constantize_plugin_from_gemspec_metadata(plugin_name)
91
+ plugin_class_name = Gem.loaded_specs[plugin_name].metadata['default_lint_roller_plugin']
92
+
93
+ Kernel.const_get(plugin_class_name)
94
+ rescue LoadError, StandardError
95
+ raise Plugin::LoadError, plugin_name
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Plugin
5
+ # An exception raised when a plugin is not supported by the RuboCop engine.
6
+ # @api private
7
+ class NotSupportedError < Error
8
+ def initialize(unsupported_plugins)
9
+ super
10
+
11
+ @unsupported_plugins = unsupported_plugins
12
+ end
13
+
14
+ def message
15
+ if @unsupported_plugins.one?
16
+ about = @unsupported_plugins.first.about
17
+
18
+ "#{about.name} #{about.version} is not a plugin supported by RuboCop engine."
19
+ else
20
+ unsupported_plugin_names = @unsupported_plugins.map do |plugin|
21
+ "#{plugin.about.name} #{plugin.about.version}"
22
+ end.join(', ')
23
+
24
+ "#{unsupported_plugin_names} are not plugins supported by RuboCop engine."
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'plugin/configuration_integrator'
4
+ require_relative 'plugin/loader'
5
+
6
+ module RuboCop
7
+ # Provides a plugin for RuboCop extensions that conform to lint_roller.
8
+ # https://github.com/standardrb/lint_roller
9
+ # @api private
10
+ module Plugin
11
+ BUILTIN_INTERNAL_PLUGINS = {
12
+ 'rubocop-internal_affairs' => {
13
+ 'enabled' => true,
14
+ 'require_path' => 'rubocop/cop/internal_affairs/plugin',
15
+ 'plugin_class_name' => 'RuboCop::InternalAffairs::Plugin'
16
+ }
17
+ }.freeze
18
+ INTERNAL_AFFAIRS_PLUGIN_NAME = Plugin::BUILTIN_INTERNAL_PLUGINS.keys.first
19
+ OBSOLETE_INTERNAL_AFFAIRS_PLUGIN_NAME = 'rubocop/cop/internal_affairs'
20
+
21
+ class << self
22
+ def plugin_capable?(feature_name)
23
+ return true if BUILTIN_INTERNAL_PLUGINS.key?(feature_name)
24
+ return true if feature_name == OBSOLETE_INTERNAL_AFFAIRS_PLUGIN_NAME
25
+ return false unless (gem = Gem.loaded_specs[feature_name])
26
+
27
+ !!gem.metadata['default_lint_roller_plugin']
28
+ end
29
+
30
+ def integrate_plugins(rubocop_config, plugins)
31
+ plugins = Plugin::Loader.load(plugins)
32
+
33
+ ConfigurationIntegrator.integrate_plugins_into_rubocop_config(rubocop_config, plugins)
34
+
35
+ plugins
36
+ end
37
+ end
38
+ end
39
+ end
@@ -12,7 +12,8 @@ module RuboCop
12
12
  # Use global Rake namespace here to avoid namespace issues with custom
13
13
  # rubocop-rake tasks
14
14
  class RakeTask < ::Rake::TaskLib
15
- attr_accessor :name, :verbose, :fail_on_error, :patterns, :formatters, :requires, :options
15
+ attr_accessor :name, :verbose, :fail_on_error, :patterns, :formatters, :plugins, :requires,
16
+ :options
16
17
 
17
18
  def initialize(name = :rubocop, *args, &task_block)
18
19
  super()
@@ -54,6 +55,7 @@ module RuboCop
54
55
 
55
56
  def full_options
56
57
  formatters.map { |f| ['--format', f] }.flatten
58
+ .concat(plugins.map { |plugin| ['--plugin', plugin] }.flatten)
57
59
  .concat(requires.map { |r| ['--require', r] }.flatten)
58
60
  .concat(options.flatten)
59
61
  .concat(patterns)
@@ -64,6 +66,7 @@ module RuboCop
64
66
  @verbose = true
65
67
  @fail_on_error = true
66
68
  @patterns = []
69
+ @plugins = []
67
70
  @requires = []
68
71
  @options = []
69
72
  @formatters = []
@@ -2,8 +2,10 @@
2
2
 
3
3
  require 'digest'
4
4
  require 'pathname'
5
+ require 'yaml'
5
6
  require_relative '../cache_config'
6
7
  require_relative '../config_finder'
8
+ require_relative '../path_util'
7
9
 
8
10
  #
9
11
  # This code is based on https://github.com/fohte/rubocop-daemon.
@@ -50,9 +52,11 @@ module RuboCop
50
52
  end.find(&:exist?)
51
53
  version_data = lockfile_path&.read || RuboCop::Version::STRING
52
54
  config_data = Pathname(ConfigFinder.find_config_path(Dir.pwd)).read
53
- todo_data = (rubocop_todo = Pathname('.rubocop_todo.yml')).exist? ? rubocop_todo.read : ''
55
+ yaml = YAML.safe_load(config_data, permitted_classes: [Regexp, Symbol], aliases: true)
56
+ inherit_from_data = inherit_from_data(yaml)
57
+ require_data = require_data(yaml)
54
58
 
55
- Digest::SHA1.hexdigest(version_data + config_data + todo_data)
59
+ Digest::SHA1.hexdigest(version_data + config_data + inherit_from_data + require_data)
56
60
  end
57
61
  # rubocop:enable Metrics/AbcSize
58
62
 
@@ -164,6 +168,35 @@ module RuboCop
164
168
  def write_version_file(version)
165
169
  version_path.write(version)
166
170
  end
171
+
172
+ def inherit_from_data(yaml)
173
+ return '' unless (inherit_from_paths = yaml['inherit_from'])
174
+
175
+ Array(inherit_from_paths).map do |path|
176
+ next if PathUtil.remote_file?(path)
177
+
178
+ path = Pathname(path)
179
+
180
+ path.exist? ? path.read : ''
181
+ end.join
182
+ end
183
+
184
+ def require_data(yaml)
185
+ return '' unless (require_paths = yaml['require'])
186
+
187
+ Array(require_paths).map do |path|
188
+ # NOTE: This targets only relative or absolute path specifications.
189
+ # For example, specifications like `require: rubocop-performance`,
190
+ # which can be loaded from `$LOAD_PATH`, are ignored.
191
+ next unless path.start_with?('.', '/')
192
+
193
+ # NOTE: `.so` files are not typically specified, so only `.rb` files are targeted.
194
+ path = "#{path}.rb" unless path.end_with?('.rb')
195
+ path = Pathname(path)
196
+
197
+ path.exist? ? path.read : ''
198
+ end.join
199
+ end
167
200
  end
168
201
  end
169
202
  end
@@ -86,7 +86,7 @@ module RuboCop
86
86
  end
87
87
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
88
88
 
89
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength:
89
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
90
90
  def run_command(server_command, detach:)
91
91
  case server_command
92
92
  when '--server'
@@ -107,7 +107,7 @@ module RuboCop
107
107
  Server::ClientCommand::Status.new.run
108
108
  end
109
109
  end
110
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength:
110
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
111
111
 
112
112
  def fetch_cache_root_path_from(arguments)
113
113
  cache_root = arguments.detect { |argument| argument.start_with?('--cache-root') }
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.71.2'
6
+ STRING = '1.72.0'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
@@ -63,9 +63,21 @@ module RuboCop
63
63
  end
64
64
 
65
65
  # @api private
66
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
66
67
  def self.extension_versions(env)
68
+ plugins = config_for_pwd(env).loaded_plugins
69
+ plugin_versions = plugins.filter_map do |plugin|
70
+ next if Plugin::BUILTIN_INTERNAL_PLUGINS.key?(plugin.about.name)
71
+ next unless (plugin_name = plugin.about.name)
72
+
73
+ " - #{plugin_name} #{plugin.about.version}"
74
+ end
75
+
76
+ # TODO: It needs to be maintained for a while to ensure compatibility with extensions that
77
+ # don't support plugins. It should be removed in future once the old style becomes obsolete.
67
78
  features = config_for_pwd(env).loaded_features.sort
68
- features.filter_map do |loaded_feature|
79
+ features -= plugins.map { |plugin| plugin.about.name }
80
+ feature_versions = features.filter_map do |loaded_feature|
69
81
  next unless (match = loaded_feature.match(/rubocop-(?<feature>.*)/))
70
82
 
71
83
  # Get the expected name of the folder containing the extension code.
@@ -84,7 +96,10 @@ module RuboCop
84
96
 
85
97
  " - #{loaded_feature} #{feature_version}"
86
98
  end
99
+
100
+ plugin_versions + feature_versions
87
101
  end
102
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
88
103
 
89
104
  # @api private
90
105
  def self.target_ruby_version(env)
data/lib/rubocop.rb CHANGED
@@ -304,6 +304,7 @@ require_relative 'rubocop/cop/lint/constant_definition_in_block'
304
304
  require_relative 'rubocop/cop/lint/constant_overwritten_in_rescue'
305
305
  require_relative 'rubocop/cop/lint/constant_reassignment'
306
306
  require_relative 'rubocop/cop/lint/constant_resolution'
307
+ require_relative 'rubocop/cop/lint/cop_directive_syntax'
307
308
  require_relative 'rubocop/cop/lint/debugger'
308
309
  require_relative 'rubocop/cop/lint/deprecated_class_methods'
309
310
  require_relative 'rubocop/cop/lint/deprecated_constants'
@@ -384,6 +385,7 @@ require_relative 'rubocop/cop/lint/redundant_require_statement'
384
385
  require_relative 'rubocop/cop/lint/redundant_safe_navigation'
385
386
  require_relative 'rubocop/cop/lint/redundant_splat_expansion'
386
387
  require_relative 'rubocop/cop/lint/redundant_string_coercion'
388
+ require_relative 'rubocop/cop/lint/redundant_type_conversion'
387
389
  require_relative 'rubocop/cop/lint/redundant_with_index'
388
390
  require_relative 'rubocop/cop/lint/redundant_with_object'
389
391
  require_relative 'rubocop/cop/lint/refinement_import_methods'
@@ -405,6 +407,7 @@ require_relative 'rubocop/cop/lint/shadowed_exception'
405
407
  require_relative 'rubocop/cop/lint/shadowing_outer_local_variable'
406
408
  require_relative 'rubocop/cop/lint/struct_new_override'
407
409
  require_relative 'rubocop/cop/lint/suppressed_exception'
410
+ require_relative 'rubocop/cop/lint/suppressed_exception_in_number_conversion'
408
411
  require_relative 'rubocop/cop/lint/symbol_conversion'
409
412
  require_relative 'rubocop/cop/lint/syntax'
410
413
  require_relative 'rubocop/cop/lint/to_enum_arguments'
@@ -425,6 +428,7 @@ require_relative 'rubocop/cop/lint/uri_escape_unescape'
425
428
  require_relative 'rubocop/cop/lint/uri_regexp'
426
429
  require_relative 'rubocop/cop/lint/useless_access_modifier'
427
430
  require_relative 'rubocop/cop/lint/useless_assignment'
431
+ require_relative 'rubocop/cop/lint/useless_constant_scoping'
428
432
  require_relative 'rubocop/cop/lint/useless_defined'
429
433
  require_relative 'rubocop/cop/lint/useless_else_without_rescue'
430
434
  require_relative 'rubocop/cop/lint/useless_method_definition'
@@ -604,6 +608,7 @@ require_relative 'rubocop/cop/style/redundant_each'
604
608
  require_relative 'rubocop/cop/style/redundant_fetch_block'
605
609
  require_relative 'rubocop/cop/style/redundant_file_extension_in_require'
606
610
  require_relative 'rubocop/cop/style/redundant_filter_chain'
611
+ require_relative 'rubocop/cop/style/redundant_format'
607
612
  require_relative 'rubocop/cop/style/redundant_heredoc_delimiter_quotes'
608
613
  require_relative 'rubocop/cop/style/redundant_initialize'
609
614
  require_relative 'rubocop/cop/style/redundant_interpolation_unfreeze'