rubocop 1.5.1 → 1.8.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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +111 -14
  5. data/config/obsoletion.yml +196 -0
  6. data/lib/rubocop.rb +20 -1
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +19 -19
  8. data/lib/rubocop/comment_config.rb +6 -6
  9. data/lib/rubocop/config.rb +8 -5
  10. data/lib/rubocop/config_loader.rb +10 -6
  11. data/lib/rubocop/config_loader_resolver.rb +21 -4
  12. data/lib/rubocop/config_obsoletion.rb +64 -262
  13. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  14. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  15. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  16. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  17. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  18. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  19. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  20. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  21. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  22. data/lib/rubocop/config_validator.rb +11 -4
  23. data/lib/rubocop/cop/base.rb +17 -15
  24. data/lib/rubocop/cop/cop.rb +2 -2
  25. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  26. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
  27. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  28. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
  29. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
  30. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  31. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +26 -0
  32. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  33. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  34. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  35. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
  36. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
  37. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  38. data/lib/rubocop/cop/layout/space_before_brackets.rb +62 -0
  39. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
  40. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  41. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
  42. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
  43. data/lib/rubocop/cop/lint/deprecated_constants.rb +75 -0
  44. data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
  45. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  46. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  47. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  48. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +48 -0
  49. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
  50. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  51. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  52. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
  53. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  54. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  55. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  56. data/lib/rubocop/cop/mixin/comments_help.rb +1 -10
  57. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  58. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  59. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  60. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
  61. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  62. data/lib/rubocop/cop/naming/variable_number.rb +1 -8
  63. data/lib/rubocop/cop/registry.rb +10 -0
  64. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  65. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  66. data/lib/rubocop/cop/style/collection_methods.rb +14 -1
  67. data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
  68. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  69. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  70. data/lib/rubocop/cop/style/float_division.rb +44 -1
  71. data/lib/rubocop/cop/style/for.rb +2 -0
  72. data/lib/rubocop/cop/style/hash_except.rb +95 -0
  73. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  74. data/lib/rubocop/cop/style/if_inside_else.rb +8 -3
  75. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  76. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  77. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
  78. data/lib/rubocop/cop/style/lambda_call.rb +2 -1
  79. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -0
  80. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
  81. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
  82. data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
  83. data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
  84. data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
  85. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  86. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  87. data/lib/rubocop/cop/style/raise_args.rb +5 -2
  88. data/lib/rubocop/cop/style/redundant_argument.rb +21 -2
  89. data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
  90. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  91. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  92. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  93. data/lib/rubocop/cop/style/single_line_methods.rb +33 -2
  94. data/lib/rubocop/cop/style/sole_nested_conditional.rb +25 -9
  95. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  96. data/lib/rubocop/cop/style/string_concatenation.rb +26 -1
  97. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  98. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  99. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  100. data/lib/rubocop/cop/util.rb +3 -1
  101. data/lib/rubocop/ext/regexp_node.rb +31 -9
  102. data/lib/rubocop/ext/regexp_parser.rb +21 -3
  103. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  104. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  105. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  106. data/lib/rubocop/lockfile.rb +40 -0
  107. data/lib/rubocop/options.rb +9 -9
  108. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  109. data/lib/rubocop/rspec/expect_offense.rb +34 -22
  110. data/lib/rubocop/runner.rb +16 -1
  111. data/lib/rubocop/target_finder.rb +4 -2
  112. data/lib/rubocop/target_ruby.rb +47 -11
  113. data/lib/rubocop/util.rb +16 -0
  114. data/lib/rubocop/version.rb +8 -2
  115. metadata +42 -9
@@ -7,7 +7,7 @@ require 'rainbow'
7
7
  require 'set'
8
8
  require 'forwardable'
9
9
  require 'regexp_parser'
10
- require 'unicode/display_width/no_string_ext'
10
+ require 'unicode/display_width'
11
11
 
12
12
  # we have to require RuboCop's version, before rubocop-ast's
13
13
  require_relative 'rubocop/version'
@@ -28,6 +28,7 @@ require_relative 'rubocop/name_similarity'
28
28
  require_relative 'rubocop/string_interpreter'
29
29
  require_relative 'rubocop/error'
30
30
  require_relative 'rubocop/warning'
31
+ require_relative 'rubocop/util'
31
32
 
32
33
  require_relative 'rubocop/cop/util'
33
34
  require_relative 'rubocop/cop/offense'
@@ -60,6 +61,7 @@ require_relative 'rubocop/cop/mixin/annotation_comment'
60
61
  require_relative 'rubocop/cop/mixin/array_min_size'
61
62
  require_relative 'rubocop/cop/mixin/array_syntax'
62
63
  require_relative 'rubocop/cop/mixin/alignment'
64
+ require_relative 'rubocop/cop/mixin/allowed_identifiers'
63
65
  require_relative 'rubocop/cop/mixin/allowed_methods'
64
66
  require_relative 'rubocop/cop/mixin/auto_corrector'
65
67
  require_relative 'rubocop/cop/mixin/check_assignment'
@@ -230,6 +232,7 @@ require_relative 'rubocop/cop/layout/space_around_keyword'
230
232
  require_relative 'rubocop/cop/layout/space_around_method_call_operator'
231
233
  require_relative 'rubocop/cop/layout/space_around_operators'
232
234
  require_relative 'rubocop/cop/layout/space_before_block_braces'
235
+ require_relative 'rubocop/cop/layout/space_before_brackets'
233
236
  require_relative 'rubocop/cop/layout/space_before_comma'
234
237
  require_relative 'rubocop/cop/layout/space_before_comment'
235
238
  require_relative 'rubocop/cop/layout/space_before_first_arg'
@@ -247,6 +250,7 @@ require_relative 'rubocop/cop/layout/space_inside_string_interpolation'
247
250
  require_relative 'rubocop/cop/layout/trailing_empty_lines'
248
251
  require_relative 'rubocop/cop/layout/trailing_whitespace'
249
252
 
253
+ require_relative 'rubocop/cop/lint/ambiguous_assignment'
250
254
  require_relative 'rubocop/cop/lint/ambiguous_block_association'
251
255
  require_relative 'rubocop/cop/lint/ambiguous_operator'
252
256
  require_relative 'rubocop/cop/lint/ambiguous_regexp_literal'
@@ -259,6 +263,7 @@ require_relative 'rubocop/cop/lint/constant_definition_in_block'
259
263
  require_relative 'rubocop/cop/lint/constant_resolution'
260
264
  require_relative 'rubocop/cop/lint/debugger'
261
265
  require_relative 'rubocop/cop/lint/deprecated_class_methods'
266
+ require_relative 'rubocop/cop/lint/deprecated_constants'
262
267
  require_relative 'rubocop/cop/lint/deprecated_open_ssl_constant'
263
268
  require_relative 'rubocop/cop/lint/disjunctive_assignment_in_constructor'
264
269
  require_relative 'rubocop/cop/lint/duplicate_branch'
@@ -292,6 +297,7 @@ require_relative 'rubocop/cop/lint/implicit_string_concatenation'
292
297
  require_relative 'rubocop/cop/lint/inherit_exception'
293
298
  require_relative 'rubocop/cop/lint/ineffective_access_modifier'
294
299
  require_relative 'rubocop/cop/lint/interpolation_check'
300
+ require_relative 'rubocop/cop/lint/lambda_without_literal_block'
295
301
  require_relative 'rubocop/cop/lint/literal_as_condition'
296
302
  require_relative 'rubocop/cop/lint/literal_in_interpolation'
297
303
  require_relative 'rubocop/cop/lint/loop'
@@ -315,6 +321,7 @@ require_relative 'rubocop/cop/lint/raise_exception'
315
321
  require_relative 'rubocop/cop/lint/rand_one'
316
322
  require_relative 'rubocop/cop/lint/redundant_cop_disable_directive'
317
323
  require_relative 'rubocop/cop/lint/redundant_cop_enable_directive'
324
+ require_relative 'rubocop/cop/lint/redundant_dir_glob_sort'
318
325
  require_relative 'rubocop/cop/lint/redundant_require_statement'
319
326
  require_relative 'rubocop/cop/lint/redundant_safe_navigation'
320
327
  require_relative 'rubocop/cop/lint/redundant_splat_expansion'
@@ -443,6 +450,7 @@ require_relative 'rubocop/cop/style/empty_else'
443
450
  require_relative 'rubocop/cop/style/empty_lambda_parameter'
444
451
  require_relative 'rubocop/cop/style/empty_literal'
445
452
  require_relative 'rubocop/cop/style/empty_method'
453
+ require_relative 'rubocop/cop/style/endless_method'
446
454
  require_relative 'rubocop/cop/style/encoding'
447
455
  require_relative 'rubocop/cop/style/end_block'
448
456
  require_relative 'rubocop/cop/style/eval_with_location'
@@ -460,6 +468,7 @@ require_relative 'rubocop/cop/style/global_vars'
460
468
  require_relative 'rubocop/cop/style/guard_clause'
461
469
  require_relative 'rubocop/cop/style/hash_as_last_array_item'
462
470
  require_relative 'rubocop/cop/style/hash_each_methods'
471
+ require_relative 'rubocop/cop/style/hash_except'
463
472
  require_relative 'rubocop/cop/style/hash_like_case'
464
473
  require_relative 'rubocop/cop/style/hash_syntax'
465
474
  require_relative 'rubocop/cop/style/hash_transform_keys'
@@ -632,9 +641,19 @@ require_relative 'rubocop/cached_data'
632
641
  require_relative 'rubocop/config'
633
642
  require_relative 'rubocop/config_loader_resolver'
634
643
  require_relative 'rubocop/config_loader'
644
+ require_relative 'rubocop/config_obsoletion/rule'
645
+ require_relative 'rubocop/config_obsoletion/cop_rule'
646
+ require_relative 'rubocop/config_obsoletion/parameter_rule'
647
+ require_relative 'rubocop/config_obsoletion/changed_enforced_styles'
648
+ require_relative 'rubocop/config_obsoletion/changed_parameter'
649
+ require_relative 'rubocop/config_obsoletion/extracted_cop'
650
+ require_relative 'rubocop/config_obsoletion/removed_cop'
651
+ require_relative 'rubocop/config_obsoletion/renamed_cop'
652
+ require_relative 'rubocop/config_obsoletion/split_cop'
635
653
  require_relative 'rubocop/config_obsoletion'
636
654
  require_relative 'rubocop/config_store'
637
655
  require_relative 'rubocop/config_validator'
656
+ require_relative 'rubocop/lockfile'
638
657
  require_relative 'rubocop/target_finder'
639
658
  require_relative 'rubocop/directive_comment'
640
659
  require_relative 'rubocop/comment_config'
@@ -3,7 +3,10 @@
3
3
  module RuboCop
4
4
  class CLI
5
5
  module Command
6
- # Run all the selected cops and report the result.
6
+ # Suggest RuboCop extensions to install based on Gemfile dependencies.
7
+ # Only primary dependencies are evaluated, so if a dependency depends on a
8
+ # gem with an extension, it is not suggested. However, if an extension is
9
+ # a transitive dependency, it will not be suggested.
7
10
  # @api private
8
11
  class SuggestExtensions < Base
9
12
  # Combination of short and long formatter names.
@@ -11,15 +14,6 @@ module RuboCop
11
14
 
12
15
  self.command_name = :suggest_extensions
13
16
 
14
- def self.dependent_gems
15
- return [] unless defined?(Bundler)
16
-
17
- # This only includes gems in Gemfile, not in lockfile
18
- Bundler.load.dependencies.map(&:name)
19
- rescue Bundler::GemfileNotFound
20
- []
21
- end
22
-
23
17
  def run
24
18
  return if skip? || extensions.none?
25
19
 
@@ -58,21 +52,27 @@ module RuboCop
58
52
  end
59
53
 
60
54
  def extensions
61
- return [] unless dependent_gems.any?
55
+ return [] unless lockfile.dependencies.any?
62
56
 
63
- @extensions ||= begin
64
- extensions = @config_store.for_pwd.for_all_cops['SuggestExtensions'] || {}
65
- extensions.select { |_, v| (Array(v) & dependent_gems).any? }.keys - dependent_gems
66
- end
57
+ extensions = @config_store.for_pwd.for_all_cops['SuggestExtensions'] || {}
58
+ extensions.select { |_, v| (Array(v) & dependent_gems).any? }.keys - installed_gems
67
59
  end
68
60
 
69
- def puts(*args)
70
- output = (@options[:stderr] ? $stderr : $stdout)
71
- output.puts(*args)
61
+ def lockfile
62
+ @lockfile ||= Lockfile.new
72
63
  end
73
64
 
74
65
  def dependent_gems
75
- @dependent_gems ||= self.class.dependent_gems
66
+ lockfile.dependencies.map(&:name)
67
+ end
68
+
69
+ def installed_gems
70
+ lockfile.gems.map(&:name)
71
+ end
72
+
73
+ def puts(*args)
74
+ output = (@options[:stderr] ? $stderr : $stdout)
75
+ output.puts(*args)
76
76
  end
77
77
  end
78
78
  end
@@ -47,6 +47,12 @@ module RuboCop
47
47
  )
48
48
  end
49
49
 
50
+ def comment_only_line?(line_number)
51
+ non_comment_token_line_numbers.none? do |non_comment_line_number|
52
+ non_comment_line_number == line_number
53
+ end
54
+ end
55
+
50
56
  private
51
57
 
52
58
  def extra_enabled_comments_with_names(extras:, names:)
@@ -166,12 +172,6 @@ module RuboCop
166
172
  @all_cop_names ||= Cop::Registry.global.names - [REDUNDANT_DISABLE]
167
173
  end
168
174
 
169
- def comment_only_line?(line_number)
170
- non_comment_token_line_numbers.none? do |non_comment_line_number|
171
- non_comment_line_number == line_number
172
- end
173
- end
174
-
175
175
  def non_comment_token_line_numbers
176
176
  @non_comment_token_line_numbers ||= begin
177
177
  non_comment_tokens = processed_source.tokens.reject(&:comment?)
@@ -50,8 +50,8 @@ module RuboCop
50
50
  self
51
51
  end
52
52
 
53
- def_delegators :@hash, :[], :[]=, :delete, :each, :key?, :keys, :each_key,
54
- :fetch, :map, :merge, :to_h, :to_hash, :transform_values
53
+ def_delegators :@hash, :[], :[]=, :delete, :dig, :each, :key?, :keys, :each_key,
54
+ :fetch, :map, :merge, :replace, :to_h, :to_hash, :transform_values
55
55
  def_delegators :@validator, :validate, :target_ruby_version
56
56
 
57
57
  def to_s
@@ -281,6 +281,9 @@ module RuboCop
281
281
  end
282
282
 
283
283
  def enable_cop?(qualified_cop_name, cop_options)
284
+ # If the cop is explicitly enabled, the other checks can be skipped.
285
+ return true if cop_options['Enabled'] == true
286
+
284
287
  department = department_of(qualified_cop_name)
285
288
  cop_enabled = cop_options.fetch('Enabled') do
286
289
  !for_all_cops['DisabledByDefault']
@@ -292,10 +295,10 @@ module RuboCop
292
295
  end
293
296
 
294
297
  def department_of(qualified_cop_name)
295
- cop_department, cop_name = qualified_cop_name.split('/')
296
- return nil if cop_name.nil?
298
+ *cop_department, _ = qualified_cop_name.split('/')
299
+ return nil if cop_department.empty?
297
300
 
298
- self[cop_department]
301
+ self[cop_department.join('/')]
299
302
  end
300
303
  end
301
304
  end
@@ -31,6 +31,7 @@ module RuboCop
31
31
 
32
32
  def clear_options
33
33
  @debug = nil
34
+ @loaded_features = []
34
35
  FileFinder.root_level = nil
35
36
  end
36
37
 
@@ -177,12 +178,9 @@ module RuboCop
177
178
  @loaded_features.flatten.compact
178
179
  end
179
180
 
180
- private
181
-
182
- def file_path(file)
183
- File.absolute_path(file.is_a?(RemoteConfig) ? file.file : file)
184
- end
185
-
181
+ # @api private
182
+ # Used to add features that were required inside a config or from
183
+ # the CLI using `--require`.
186
184
  def add_loaded_features(loaded_features)
187
185
  if instance_variable_defined?(:@loaded_features)
188
186
  instance_variable_get(:@loaded_features) << loaded_features
@@ -191,6 +189,12 @@ module RuboCop
191
189
  end
192
190
  end
193
191
 
192
+ private
193
+
194
+ def file_path(file)
195
+ File.absolute_path(file.is_a?(RemoteConfig) ? file.file : file)
196
+ end
197
+
194
198
  def find_project_dotfile(target_dir)
195
199
  find_file_upwards(DOTFILE, target_dir, project_root)
196
200
  end
@@ -20,12 +20,13 @@ module RuboCop
20
20
  end
21
21
  end
22
22
 
23
- # rubocop:disable Metrics/MethodLength
24
- def resolve_inheritance(path, hash, file, debug)
23
+ def resolve_inheritance(path, hash, file, debug) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
25
24
  inherited_files = Array(hash['inherit_from'])
26
25
  base_configs(path, inherited_files, file)
27
26
  .reverse.each_with_index do |base_config, index|
28
27
  override_department_setting_for_cops(base_config, hash)
28
+ override_enabled_for_disabled_departments(base_config, hash)
29
+
29
30
  base_config.each do |k, v|
30
31
  next unless v.is_a?(Hash)
31
32
 
@@ -39,7 +40,6 @@ module RuboCop
39
40
  end
40
41
  end
41
42
  end
42
- # rubocop:enable Metrics/MethodLength
43
43
 
44
44
  def resolve_inheritance_from_gems(hash)
45
45
  gems = hash.delete('inherit_gem')
@@ -75,6 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  config = handle_disabled_by_default(config, default_configuration) if disabled_by_default
78
+ override_enabled_for_disabled_departments(default_configuration, config)
78
79
 
79
80
  opts = { inherit_mode: config['inherit_mode'] || {},
80
81
  unset_nil: unset_nil }
@@ -122,10 +123,26 @@ module RuboCop
122
123
  end
123
124
  end
124
125
 
126
+ # If a cop was previously explicitly enabled, but then superseded by the
127
+ # department being disabled, disable it.
128
+ def override_enabled_for_disabled_departments(base_hash, derived_hash)
129
+ cops_to_disable = derived_hash.each_key.with_object([]) do |key, cops|
130
+ next unless disabled?(derived_hash, key)
131
+
132
+ cops.concat(base_hash.keys.grep(Regexp.new("^#{key}/")))
133
+ end
134
+
135
+ cops_to_disable.each do |cop_name|
136
+ next unless base_hash.dig(cop_name, 'Enabled') == true
137
+
138
+ derived_hash.replace(merge({ cop_name => { 'Enabled' => false } }, derived_hash))
139
+ end
140
+ end
141
+
125
142
  private
126
143
 
127
144
  def disabled?(hash, department)
128
- hash[department] && hash[department]['Enabled'] == false
145
+ hash[department].is_a?(Hash) && hash[department]['Enabled'] == false
129
146
  end
130
147
 
131
148
  def duplicate_setting?(base_hash, derived_hash, key, inherited_file)
@@ -4,233 +4,40 @@ module RuboCop
4
4
  # This class handles obsolete configuration.
5
5
  # @api private
6
6
  class ConfigObsoletion
7
- RENAMED_COPS = {
8
- 'Layout/AlignArguments' => 'Layout/ArgumentAlignment',
9
- 'Layout/AlignArray' => 'Layout/ArrayAlignment',
10
- 'Layout/AlignHash' => 'Layout/HashAlignment',
11
- 'Layout/AlignParameters' => 'Layout/ParameterAlignment',
12
- 'Layout/IndentArray' => 'Layout/FirstArrayElementIndentation',
13
- 'Layout/IndentAssignment' => 'Layout/AssignmentIndentation',
14
- 'Layout/IndentFirstArgument' => 'Layout/FirstArgumentIndentation',
15
- 'Layout/IndentFirstArrayElement' => 'Layout/FirstArrayElementIndentation',
16
- 'Layout/IndentFirstHashElement' => 'Layout/FirstHashElementIndentation',
17
- 'Layout/IndentFirstParameter' => 'Layout/FirstParameterIndentation',
18
- 'Layout/IndentHash' => 'Layout/FirstHashElementIndentation',
19
- 'Layout/IndentHeredoc' => 'Layout/HeredocIndentation',
20
- 'Layout/LeadingBlankLines' => 'Layout/LeadingEmptyLines',
21
- 'Layout/Tab' => 'Layout/IndentationStyle',
22
- 'Layout/TrailingBlankLines' => 'Layout/TrailingEmptyLines',
23
- 'Lint/DuplicatedKey' => 'Lint/DuplicateHashKey',
24
- 'Lint/EndInMethod' => 'Style/EndBlock',
25
- 'Lint/HandleExceptions' => 'Lint/SuppressedException',
26
- 'Lint/MultipleCompare' => 'Lint/MultipleComparison',
27
- 'Lint/StringConversionInInterpolation' => 'Lint/RedundantStringCoercion',
28
- 'Lint/UnneededCopDisableDirective' => 'Lint/RedundantCopDisableDirective',
29
- 'Lint/UnneededCopEnableDirective' => 'Lint/RedundantCopEnableDirective',
30
- 'Lint/UnneededRequireStatement' => 'Lint/RedundantRequireStatement',
31
- 'Lint/UnneededSplatExpansion' => 'Lint/RedundantSplatExpansion',
32
- 'Naming/UncommunicativeBlockParamName' => 'Naming/BlockParameterName',
33
- 'Naming/UncommunicativeMethodParamName' => 'Naming/MethodParameterName',
34
- 'Style/DeprecatedHashMethods' => 'Style/PreferredHashMethods',
35
- 'Style/MethodCallParentheses' => 'Style/MethodCallWithoutArgsParentheses',
36
- 'Style/OpMethod' => 'Naming/BinaryOperatorParameterName',
37
- 'Style/SingleSpaceBeforeFirstArg' => 'Layout/SpaceBeforeFirstArg',
38
- 'Style/UnneededCapitalW' => 'Style/RedundantCapitalW',
39
- 'Style/UnneededCondition' => 'Style/RedundantCondition',
40
- 'Style/UnneededInterpolation' => 'Style/RedundantInterpolation',
41
- 'Style/UnneededPercentQ' => 'Style/RedundantPercentQ',
42
- 'Style/UnneededSort' => 'Style/RedundantSort'
43
- }.map do |old_name, new_name|
44
- [old_name, "The `#{old_name}` cop has been renamed to `#{new_name}`."]
45
- end
46
-
47
- MOVED_COPS = {
48
- 'Security' => 'Lint/Eval',
49
- 'Naming' => %w[Style/ClassAndModuleCamelCase Style/ConstantName
50
- Style/FileName Style/MethodName Style/PredicateName
51
- Style/VariableName Style/VariableNumber
52
- Style/AccessorMethodName Style/AsciiIdentifiers],
53
- 'Layout' => %w[Lint/BlockAlignment Lint/EndAlignment
54
- Lint/DefEndAlignment Metrics/LineLength],
55
- 'Lint' => 'Style/FlipFlop'
56
- }.map do |new_department, old_names|
57
- Array(old_names).map do |old_name|
58
- [old_name, "The `#{old_name}` cop has been moved to " \
59
- "`#{new_department}/#{old_name.split('/').last}`."]
7
+ DEFAULT_RULES_FILE = File.join(ConfigLoader::RUBOCOP_HOME, 'config', 'obsoletion.yml')
8
+ COP_RULE_CLASSES = {
9
+ 'renamed' => RenamedCop,
10
+ 'removed' => RemovedCop,
11
+ 'split' => SplitCop,
12
+ 'extracted' => ExtractedCop
13
+ }.freeze
14
+ PARAMETER_RULE_CLASSES = {
15
+ 'changed_parameters' => ChangedParameter,
16
+ 'changed_enforced_styles' => ChangedEnforcedStyles
17
+ }.freeze
18
+
19
+ attr_reader :rules, :warnings
20
+
21
+ class << self
22
+ attr_accessor :files
23
+
24
+ def legacy_cop_names
25
+ # Used by DepartmentName#qualified_legacy_cop_name
26
+ new(Config.new).rules.select(&:cop_rule?).map(&:old_name)
60
27
  end
61
28
  end
62
29
 
63
- REMOVED_COPS = {
64
- 'Layout/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
65
- 'Layout/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
66
- 'Lint/RescueWithoutErrorClass' => 'Style/RescueStandardError',
67
- 'Style/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
68
- 'Style/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
69
- 'Style/TrailingComma' => 'Style/TrailingCommaInArguments, ' \
70
- 'Style/TrailingCommaInArrayLiteral, and/or ' \
71
- 'Style/TrailingCommaInHashLiteral',
72
- 'Style/TrailingCommaInLiteral' => 'Style/TrailingCommaInArrayLiteral ' \
73
- 'and/or ' \
74
- 'Style/TrailingCommaInHashLiteral',
75
- 'Style/BracesAroundHashParameters' => nil
76
- }.map do |old_name, other_cops|
77
- if other_cops
78
- more = ". Please use #{other_cops} instead".gsub(%r{[A-Z]\w+/\w+},
79
- '`\&`')
80
- end
81
- [old_name, "The `#{old_name}` cop has been removed#{more}."]
82
- end
83
-
84
- REMOVED_COPS_WITH_REASON = {
85
- 'Lint/InvalidCharacterLiteral' => 'it was never being actually triggered',
86
- 'Lint/SpaceBeforeFirstArg' =>
87
- 'it was a duplicate of `Layout/SpaceBeforeFirstArg`. Please use ' \
88
- '`Layout/SpaceBeforeFirstArg` instead',
89
- 'Style/MethodMissingSuper' => 'it has been superseded by `Lint/MissingSuper`. Please use ' \
90
- '`Lint/MissingSuper` instead',
91
- 'Lint/UselessComparison' => 'it has been superseded by '\
92
- '`Lint/BinaryOperatorWithIdenticalOperands`. Please use '\
93
- '`Lint/BinaryOperatorWithIdenticalOperands` instead'
94
- }.map do |cop_name, reason|
95
- [cop_name, "The `#{cop_name}` cop has been removed since #{reason}."]
96
- end
97
-
98
- SPLIT_COPS = {
99
- 'Style/MethodMissing' =>
100
- 'The `Style/MethodMissing` cop has been split into ' \
101
- '`Style/MethodMissingSuper` and `Style/MissingRespondToMissing`.'
102
- }.to_a
103
-
104
- OBSOLETE_COPS = Hash[*(RENAMED_COPS + MOVED_COPS + REMOVED_COPS +
105
- REMOVED_COPS_WITH_REASON + SPLIT_COPS).flatten]
106
-
107
- # Parameters can be deprecated but not disabled by setting `severity: :warning`
108
- OBSOLETE_PARAMETERS = [
109
- {
110
- cops: %w[Layout/SpaceAroundOperators Style/SpaceAroundOperators],
111
- parameters: 'MultiSpaceAllowedForOperators',
112
- alternative: 'If your intention was to allow extra spaces for ' \
113
- 'alignment, please use AllowForAlignment: true instead.'
114
- },
115
- {
116
- cops: 'Style/Encoding',
117
- parameters: %w[EnforcedStyle SupportedStyles
118
- AutoCorrectEncodingComment],
119
- alternative: 'Style/Encoding no longer supports styles. ' \
120
- 'The "never" behavior is always assumed.'
121
- },
122
- {
123
- cops: 'Style/IfUnlessModifier',
124
- parameters: 'MaxLineLength',
125
- alternative: '`Style/IfUnlessModifier: MaxLineLength` has been ' \
126
- 'removed. Use `Layout/LineLength: Max` instead'
127
- },
128
- {
129
- cops: 'Style/WhileUntilModifier',
130
- parameters: 'MaxLineLength',
131
- alternative: '`Style/WhileUntilModifier: MaxLineLength` has been ' \
132
- 'removed. Use `Layout/LineLength: Max` instead'
133
- },
134
- {
135
- cops: 'AllCops',
136
- parameters: 'RunRailsCops',
137
- alternative: "Use the following configuration instead:\n" \
138
- "Rails:\n Enabled: true"
139
- },
140
- {
141
- cops: 'Layout/CaseIndentation',
142
- parameters: 'IndentWhenRelativeTo',
143
- alternative: '`IndentWhenRelativeTo` has been renamed to ' \
144
- '`EnforcedStyle`'
145
- },
146
- {
147
- cops: %w[Lint/BlockAlignment Layout/BlockAlignment Lint/EndAlignment
148
- Layout/EndAlignment Lint/DefEndAlignment
149
- Layout/DefEndAlignment],
150
- parameters: 'AlignWith',
151
- alternative: '`AlignWith` has been renamed to `EnforcedStyleAlignWith`'
152
- },
153
- {
154
- cops: 'Rails/UniqBeforePluck',
155
- parameters: 'EnforcedMode',
156
- alternative: '`EnforcedMode` has been renamed to `EnforcedStyle`'
157
- },
158
- {
159
- cops: 'Style/MethodCallWithArgsParentheses',
160
- parameters: 'IgnoredMethodPatterns',
161
- alternative: '`IgnoredMethodPatterns` has been renamed to ' \
162
- '`IgnoredPatterns`'
163
- },
164
- {
165
- cops: %w[Performance/Count Performance/Detect],
166
- parameters: 'SafeMode',
167
- alternative: '`SafeMode` has been removed. ' \
168
- 'Use `SafeAutoCorrect` instead.'
169
- },
170
- {
171
- cops: 'Bundler/GemComment',
172
- parameters: 'Whitelist',
173
- alternative: '`Whitelist` has been renamed to `IgnoredGems`.'
174
- },
175
- {
176
- cops: %w[
177
- Lint/SafeNavigationChain Lint/SafeNavigationConsistency
178
- Style/NestedParenthesizedCalls Style/SafeNavigation
179
- Style/TrivialAccessors
180
- ],
181
- parameters: 'Whitelist',
182
- alternative: '`Whitelist` has been renamed to `AllowedMethods`.'
183
- },
184
- {
185
- cops: 'Style/IpAddresses',
186
- parameters: 'Whitelist',
187
- alternative: '`Whitelist` has been renamed to `AllowedAddresses`.'
188
- },
189
- {
190
- cops: 'Naming/HeredocDelimiterNaming',
191
- parameters: 'Blacklist',
192
- alternative: '`Blacklist` has been renamed to `ForbiddenDelimiters`.'
193
- },
194
- {
195
- cops: 'Naming/PredicateName',
196
- parameters: 'NamePrefixBlacklist',
197
- alternative: '`NamePrefixBlacklist` has been renamed to ' \
198
- '`ForbiddenPrefixes`.'
199
- },
200
- {
201
- cops: 'Naming/PredicateName',
202
- parameters: 'NameWhitelist',
203
- alternative: '`NameWhitelist` has been renamed to ' \
204
- '`AllowedMethods`.'
205
- },
206
- {
207
- cops: %w[Metrics/BlockLength Metrics/MethodLength],
208
- parameters: 'ExcludedMethods',
209
- alternative: '`ExcludedMethods` has been renamed to `IgnoredMethods`.',
210
- severity: :warning
211
- }
212
- ].freeze
213
-
214
- OBSOLETE_ENFORCED_STYLES = [
215
- {
216
- cop: 'Layout/IndentationConsistency',
217
- parameter: 'EnforcedStyle',
218
- enforced_style: 'rails',
219
- alternative: '`EnforcedStyle: rails` has been renamed to ' \
220
- '`EnforcedStyle: indented_internal_methods`'
221
- }
222
- ].freeze
223
-
224
- attr_reader :warnings
30
+ # Can be extended by extension libraries to add their own obsoletions
31
+ self.files = [DEFAULT_RULES_FILE]
225
32
 
226
33
  def initialize(config)
227
34
  @config = config
35
+ @rules = load_rules
228
36
  @warnings = []
229
37
  end
230
38
 
231
- def reject_obsolete_cops_and_parameters
232
- messages = [obsolete_cops, obsolete_parameters,
233
- obsolete_enforced_style].flatten.compact
39
+ def reject_obsolete!
40
+ messages = obsoletions.flatten.compact
234
41
  return if messages.empty?
235
42
 
236
43
  raise ValidationError, messages.join("\n")
@@ -238,64 +45,59 @@ module RuboCop
238
45
 
239
46
  private
240
47
 
241
- def obsolete_cops
242
- OBSOLETE_COPS.map do |cop_name, message|
243
- next unless @config.key?(cop_name) ||
244
- @config.key?(Cop::Badge.parse(cop_name).cop_name)
245
-
246
- message + "\n(obsolete configuration found in " \
247
- "#{smart_loaded_path}, please update it)"
48
+ # Default rules for obsoletions are in config/obsoletion.yml
49
+ # Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
50
+ def load_rules
51
+ rules = self.class.files.each_with_object({}) do |filename, hash|
52
+ hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
53
+ first.merge(second)
54
+ end
248
55
  end
249
- end
250
56
 
251
- def obsolete_enforced_style
252
- OBSOLETE_ENFORCED_STYLES.map do |params|
253
- obsolete_enforced_style_message(params[:cop], params[:parameter],
254
- params[:enforced_style],
255
- params[:alternative])
256
- end
257
- end
57
+ cop_rules = rules.slice(*COP_RULE_CLASSES.keys)
58
+ parameter_rules = rules.slice(*PARAMETER_RULE_CLASSES.keys)
258
59
 
259
- def obsolete_enforced_style_message(cop, param, enforced_style, alternative)
260
- style = @config[cop]&.detect { |key, _| key.start_with?(param) }
60
+ load_cop_rules(cop_rules).concat(load_parameter_rules(parameter_rules))
61
+ end
261
62
 
262
- return unless style && style[1] == enforced_style
63
+ # Cop rules are keyed by the name of the original cop
64
+ def load_cop_rules(rules)
65
+ rules.flat_map do |rule_type, data|
66
+ data.map do |cop_name, configuration|
67
+ next unless configuration # allow configurations to be disabled with `CopName: ~`
263
68
 
264
- "obsolete `#{param}: #{enforced_style}` (for #{cop}) found in " \
265
- "#{smart_loaded_path}\n#{alternative}"
69
+ COP_RULE_CLASSES[rule_type].new(@config, cop_name, configuration)
70
+ end.compact
71
+ end
266
72
  end
267
73
 
268
- def obsolete_parameters
269
- OBSOLETE_PARAMETERS.collect do |params|
270
- messages = obsolete_parameter_message(params[:cops], params[:parameters],
271
- params[:alternative])
272
-
273
- # Warnings are collected separately and not added to the error message
274
- if messages && params.fetch(:severity, :error) == :warning
275
- @warnings.concat(messages)
276
- next
74
+ # Parameter rules may apply to multiple cops and multiple parameters
75
+ # and are given as an array. Each combination is turned into a separate
76
+ # rule object.
77
+ def load_parameter_rules(rules)
78
+ rules.flat_map do |rule_type, data|
79
+ data.flat_map do |configuration|
80
+ cops = Array(configuration['cops'])
81
+ parameters = Array(configuration['parameters'])
82
+
83
+ cops.product(parameters).map do |cop, parameter|
84
+ PARAMETER_RULE_CLASSES[rule_type].new(@config, cop, parameter, configuration)
85
+ end
277
86
  end
278
-
279
- messages
280
87
  end
281
88
  end
282
89
 
283
- def obsolete_parameter_message(cops, parameters, alternative)
284
- Array(cops).map do |cop|
285
- obsolete_parameters = Array(parameters).select do |param|
286
- @config[cop]&.key?(param)
287
- end
288
- next if obsolete_parameters.empty?
90
+ def obsoletions
91
+ rules.map do |rule|
92
+ next unless rule.violated?
289
93
 
290
- obsolete_parameters.map do |parameter|
291
- "obsolete parameter #{parameter} (for #{cop}) found in " \
292
- "#{smart_loaded_path}\n#{alternative}"
94
+ if rule.warning?
95
+ @warnings.push(rule.message)
96
+ next
293
97
  end
294
- end
295
- end
296
98
 
297
- def smart_loaded_path
298
- PathUtil.smart_path(@config.loaded_path)
99
+ rule.message
100
+ end
299
101
  end
300
102
  end
301
103
  end