rubocop 1.71.2 → 1.75.2

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 (205) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +118 -21
  4. data/config/internal_affairs.yml +20 -0
  5. data/config/obsoletion.yml +3 -1
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  7. data/lib/rubocop/cli.rb +1 -1
  8. data/lib/rubocop/comment_config.rb +1 -1
  9. data/lib/rubocop/config.rb +39 -6
  10. data/lib/rubocop/config_loader.rb +48 -9
  11. data/lib/rubocop/config_loader_resolver.rb +24 -9
  12. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  13. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  14. data/lib/rubocop/config_obsoletion.rb +46 -2
  15. data/lib/rubocop/config_validator.rb +2 -1
  16. data/lib/rubocop/cop/internal_affairs/example_description.rb +7 -3
  17. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  18. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -1
  19. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +2 -1
  20. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  21. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  22. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  23. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  24. data/lib/rubocop/cop/internal_affairs.rb +2 -16
  25. data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
  26. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  27. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  28. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  29. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  30. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  31. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +3 -3
  32. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +27 -1
  33. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  34. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  35. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  36. data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
  37. data/lib/rubocop/cop/layout/line_length.rb +8 -4
  38. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  39. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  40. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  41. data/lib/rubocop/cop/layout/redundant_line_break.rb +9 -5
  42. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -5
  43. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  44. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  45. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  46. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  47. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  48. data/lib/rubocop/cop/lint/debugger.rb +2 -2
  49. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  50. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -17
  51. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  52. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  53. data/lib/rubocop/cop/lint/float_comparison.rb +1 -6
  54. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  55. data/lib/rubocop/cop/lint/literal_as_condition.rb +103 -9
  56. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  57. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  58. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  59. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  60. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  61. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  62. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  63. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  64. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  65. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  66. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
  67. data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
  68. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  69. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  70. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  71. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  72. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
  73. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -0
  74. data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
  75. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -0
  76. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  77. data/lib/rubocop/cop/lint/void.rb +7 -0
  78. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  79. data/lib/rubocop/cop/metrics/method_length.rb +1 -0
  80. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  81. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  82. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  83. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  84. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  85. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
  86. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  87. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  88. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  89. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  90. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  91. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +0 -1
  92. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +18 -18
  93. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
  94. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  95. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -0
  96. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  97. data/lib/rubocop/cop/mixin/range_help.rb +15 -3
  98. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  99. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  100. data/lib/rubocop/cop/mixin/trailing_comma.rb +12 -0
  101. data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
  102. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  103. data/lib/rubocop/cop/naming/method_name.rb +64 -8
  104. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  105. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  106. data/lib/rubocop/cop/registry.rb +9 -6
  107. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  108. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
  109. data/lib/rubocop/cop/style/array_intersect.rb +39 -28
  110. data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
  111. data/lib/rubocop/cop/style/class_and_module_children.rb +29 -7
  112. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  113. data/lib/rubocop/cop/style/collection_methods.rb +1 -0
  114. data/lib/rubocop/cop/style/combinable_loops.rb +1 -0
  115. data/lib/rubocop/cop/style/commented_keyword.rb +10 -3
  116. data/lib/rubocop/cop/style/comparable_between.rb +75 -0
  117. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -0
  118. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  119. data/lib/rubocop/cop/style/empty_literal.rb +4 -0
  120. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  121. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  122. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  123. data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
  124. data/lib/rubocop/cop/style/for.rb +1 -0
  125. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  126. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  127. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  128. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  129. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -2
  130. data/lib/rubocop/cop/style/hash_fetch_chain.rb +105 -0
  131. data/lib/rubocop/cop/style/hash_syntax.rb +3 -0
  132. data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
  133. data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -2
  134. data/lib/rubocop/cop/style/inverse_methods.rb +9 -5
  135. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  136. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  137. data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
  138. data/lib/rubocop/cop/style/keyword_parameters_order.rb +13 -7
  139. data/lib/rubocop/cop/style/lambda.rb +1 -0
  140. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  141. data/lib/rubocop/cop/style/map_into_array.rb +1 -0
  142. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -4
  143. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
  144. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  145. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  146. data/lib/rubocop/cop/style/next.rb +44 -0
  147. data/lib/rubocop/cop/style/object_then.rb +1 -0
  148. data/lib/rubocop/cop/style/proc.rb +1 -0
  149. data/lib/rubocop/cop/style/raise_args.rb +8 -8
  150. data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
  151. data/lib/rubocop/cop/style/redundant_condition.rb +57 -0
  152. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
  153. data/lib/rubocop/cop/style/redundant_format.rb +257 -0
  154. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  155. data/lib/rubocop/cop/style/redundant_parentheses.rb +20 -5
  156. data/lib/rubocop/cop/style/redundant_self.rb +1 -0
  157. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
  158. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  159. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
  160. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  161. data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
  162. data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
  163. data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
  164. data/lib/rubocop/cop/style/sole_nested_conditional.rb +41 -106
  165. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  166. data/lib/rubocop/cop/style/super_arguments.rb +1 -2
  167. data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
  168. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -0
  169. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  170. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  171. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  172. data/lib/rubocop/cop/util.rb +2 -2
  173. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  174. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  175. data/lib/rubocop/cop/variable_force/variable.rb +2 -7
  176. data/lib/rubocop/cop/variable_force.rb +1 -1
  177. data/lib/rubocop/cops_documentation_generator.rb +12 -1
  178. data/lib/rubocop/directive_comment.rb +36 -3
  179. data/lib/rubocop/ext/regexp_node.rb +0 -1
  180. data/lib/rubocop/lsp/runtime.rb +6 -4
  181. data/lib/rubocop/lsp/server.rb +0 -2
  182. data/lib/rubocop/lsp/stdin_runner.rb +3 -1
  183. data/lib/rubocop/magic_comment.rb +8 -0
  184. data/lib/rubocop/options.rb +26 -11
  185. data/lib/rubocop/path_util.rb +4 -0
  186. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  187. data/lib/rubocop/plugin/load_error.rb +26 -0
  188. data/lib/rubocop/plugin/loader.rb +100 -0
  189. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  190. data/lib/rubocop/plugin.rb +46 -0
  191. data/lib/rubocop/rake_task.rb +4 -1
  192. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  193. data/lib/rubocop/rspec/shared_contexts.rb +35 -0
  194. data/lib/rubocop/rspec/support.rb +3 -0
  195. data/lib/rubocop/runner.rb +5 -1
  196. data/lib/rubocop/server/cache.rb +47 -11
  197. data/lib/rubocop/server/cli.rb +2 -2
  198. data/lib/rubocop/target_finder.rb +1 -1
  199. data/lib/rubocop/target_ruby.rb +1 -1
  200. data/lib/rubocop/version.rb +30 -8
  201. data/lib/rubocop.rb +10 -1
  202. data/lib/ruby_lsp/rubocop/addon.rb +7 -10
  203. data/lib/ruby_lsp/rubocop/{wraps_built_in_lsp_runtime.rb → runtime_adapter.rb} +25 -10
  204. metadata +43 -12
  205. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
@@ -2,16 +2,35 @@
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
+ plugins = Array(plugins) - ConfigLoader.loaded_plugins.map { |plugin| plugin.about.name }
13
+ return if plugins.empty?
14
+
15
+ Plugin.integrate_plugins(rubocop_config, plugins)
16
+ end
17
+
10
18
  def resolve_requires(path, hash)
11
19
  config_dir = File.dirname(path)
12
20
  hash.delete('require').tap do |loaded_features|
13
21
  Array(loaded_features).each do |feature|
14
- FeatureLoader.load(config_directory_path: config_dir, feature: feature)
22
+ if Plugin.plugin_capable?(feature)
23
+ # NOTE: Compatibility for before plugins style.
24
+ warn Rainbow(<<~MESSAGE).yellow
25
+ #{feature} extension supports plugin, specify `plugins: #{feature}` instead of `require: #{feature}` in #{path}.
26
+ For more information, see https://docs.rubocop.org/rubocop/plugin_migration_guide.html.
27
+ MESSAGE
28
+ rubocop_config = Config.create(hash, path, check: false)
29
+
30
+ resolve_plugins(rubocop_config, feature)
31
+ else
32
+ FeatureLoader.load(config_directory_path: config_dir, feature: feature)
33
+ end
15
34
  end
16
35
  end
17
36
  end
@@ -105,7 +124,7 @@ module RuboCop
105
124
  elsif merge_hashes?(base_hash, derived_hash, key)
106
125
  result[key] = merge(base_hash[key], derived_hash[key], **opts)
107
126
  elsif should_union?(derived_hash, base_hash, opts[:inherit_mode], key)
108
- result[key] = base_hash[key] | derived_hash[key]
127
+ result[key] = Array(base_hash[key]) | Array(derived_hash[key])
109
128
  elsif opts[:debug]
110
129
  warn_on_duplicate_setting(base_hash, derived_hash, key, **opts)
111
130
  end
@@ -157,7 +176,7 @@ module RuboCop
157
176
  return false if inherited_file.nil? # Not inheritance resolving merge
158
177
  return false if inherited_file.start_with?('..') # Legitimate override
159
178
  return false if base_hash[key] == derived_hash[key] # Same value
160
- return false if remote_file?(inherited_file) # Can't change
179
+ return false if PathUtil.remote_file?(inherited_file) # Can't change
161
180
 
162
181
  Gem.path.none? { |dir| inherited_file.start_with?(dir) } # Can change?
163
182
  end
@@ -187,7 +206,7 @@ module RuboCop
187
206
  end
188
207
 
189
208
  def should_union?(derived_hash, base_hash, root_mode, key)
190
- return false unless base_hash[key].is_a?(Array)
209
+ return false unless base_hash[key].is_a?(Array) || derived_hash[key].is_a?(Array)
191
210
 
192
211
  derived_mode = derived_hash['inherit_mode']
193
212
  return false if should_override?(derived_mode, key)
@@ -225,7 +244,7 @@ module RuboCop
225
244
  end
226
245
 
227
246
  def inherited_file(path, inherit_from, file)
228
- if remote_file?(inherit_from)
247
+ if PathUtil.remote_file?(inherit_from)
229
248
  # A remote configuration, e.g. `inherit_from: http://example.com/rubocop.yml`.
230
249
  RemoteConfig.new(inherit_from, File.dirname(path))
231
250
  elsif Pathname.new(inherit_from).absolute?
@@ -245,10 +264,6 @@ module RuboCop
245
264
  end
246
265
  end
247
266
 
248
- def remote_file?(uri)
249
- uri.start_with?('http://', 'https://')
250
- end
251
-
252
267
  def remote_config?(file)
253
268
  file.is_a?(RemoteConfig)
254
269
  end
@@ -15,7 +15,7 @@ module RuboCop
15
15
  end
16
16
 
17
17
  def violated?
18
- return false if feature_loaded?
18
+ return false if plugin_loaded?
19
19
 
20
20
  affected_cops.any?
21
21
  end
@@ -38,8 +38,9 @@ module RuboCop
38
38
  end
39
39
  end
40
40
 
41
- def feature_loaded?
42
- config.loaded_features.include?(gem)
41
+ def plugin_loaded?
42
+ # Plugins loaded via `require` are included in `loaded_features`.
43
+ config.loaded_plugins.include?(gem) || config.loaded_features.include?(gem)
43
44
  end
44
45
  end
45
46
  end
@@ -6,17 +6,28 @@ module RuboCop
6
6
  # a cop or moving it to a new department.
7
7
  # @api private
8
8
  class RenamedCop < CopRule
9
- attr_reader :new_name
9
+ attr_reader :new_name, :metadata
10
10
 
11
- def initialize(config, old_name, new_name)
11
+ def initialize(config, old_name, name_or_hash)
12
12
  super(config, old_name)
13
- @new_name = new_name
13
+
14
+ if name_or_hash.is_a?(Hash)
15
+ @metadata = name_or_hash
16
+ @new_name = name_or_hash['new_name']
17
+ else
18
+ @metadata = {}
19
+ @new_name = name_or_hash
20
+ end
14
21
  end
15
22
 
16
23
  def rule_message
17
24
  "The `#{old_name}` cop has been #{verb} to `#{new_name}`."
18
25
  end
19
26
 
27
+ def warning?
28
+ severity == 'warning'
29
+ end
30
+
20
31
  private
21
32
 
22
33
  def moved?
@@ -29,6 +40,10 @@ module RuboCop
29
40
  def verb
30
41
  moved? ? 'moved' : 'renamed'
31
42
  end
43
+
44
+ def severity
45
+ metadata['severity']
46
+ end
32
47
  end
33
48
  end
34
49
  end
@@ -23,9 +23,40 @@ module RuboCop
23
23
  class << self
24
24
  attr_accessor :files
25
25
 
26
+ def global
27
+ @global ||= new(Config.new)
28
+ end
29
+
30
+ def reset!
31
+ @global = nil
32
+ @deprecated_names = {}
33
+ LOAD_RULES_CACHE[rules_cache_key] = nil
34
+ end
35
+
36
+ def rules_cache_key
37
+ files.hash
38
+ end
39
+
26
40
  def legacy_cop_names
27
41
  # Used by DepartmentName#qualified_legacy_cop_name
28
- new(Config.new).rules.select(&:cop_rule?).map(&:old_name)
42
+ global.legacy_cop_names
43
+ end
44
+
45
+ def deprecated_cop_name?(name)
46
+ global.deprecated_cop_name?(name)
47
+ end
48
+
49
+ def deprecated_names_for(cop)
50
+ @deprecated_names ||= {}
51
+ return @deprecated_names[cop] if @deprecated_names.key?(cop)
52
+
53
+ @deprecated_names[cop] = global.rules.filter_map do |rule|
54
+ next unless rule.cop_rule?
55
+ next unless rule.respond_to?(:new_name)
56
+ next unless rule.new_name == cop
57
+
58
+ rule.old_name
59
+ end
29
60
  end
30
61
  end
31
62
 
@@ -45,12 +76,21 @@ module RuboCop
45
76
  raise ValidationError, messages.join("\n")
46
77
  end
47
78
 
79
+ def legacy_cop_names
80
+ # Used by DepartmentName#qualified_legacy_cop_name
81
+ cop_rules.map(&:old_name)
82
+ end
83
+
84
+ def deprecated_cop_name?(name)
85
+ legacy_cop_names.include?(name)
86
+ end
87
+
48
88
  private
49
89
 
50
90
  # Default rules for obsoletions are in config/obsoletion.yml
51
91
  # Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
52
92
  def load_rules # rubocop:disable Metrics/AbcSize
53
- rules = LOAD_RULES_CACHE[self.class.files] ||=
93
+ rules = LOAD_RULES_CACHE[self.class.rules_cache_key] ||=
54
94
  self.class.files.each_with_object({}) do |filename, hash|
55
95
  hash.merge!(YAML.safe_load(File.read(filename)) || {}) do |_key, first, second|
56
96
  case first
@@ -107,5 +147,9 @@ module RuboCop
107
147
  rule.message
108
148
  end
109
149
  end
150
+
151
+ def cop_rules
152
+ rules.select(&:cop_rule?)
153
+ end
110
154
  end
111
155
  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
@@ -118,6 +118,7 @@ module RuboCop
118
118
  invalid_cop_names.each do |name|
119
119
  # There could be a custom cop with this name. If so, don't warn
120
120
  next if Cop::Registry.global.contains_cop_matching?([name])
121
+ next if ConfigObsoletion.deprecated_cop_name?(name)
121
122
 
122
123
  # Special case for inherit_mode, which is a directive that we keep in
123
124
  # the configuration (even though it's not a cop), because it's easier
@@ -50,10 +50,12 @@ module RuboCop
50
50
  }.freeze
51
51
 
52
52
  EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
53
- /\A(auto[- ]?)?correct/ => 'does not correct'
53
+ /\A(auto[- ]?)?corrects?/ => 'does not correct',
54
+ /\band (auto[- ]?)?corrects/ => 'but does not correct'
54
55
  }.freeze
55
56
 
56
57
  EXPECT_CORRECTION_DESCRIPTION_MAPPING = {
58
+ /\bbut (does not|doesn't) (auto[- ]?)?correct/ => 'and autocorrects',
57
59
  /\b(does not|doesn't) (auto[- ]?)?correct/ => 'autocorrects'
58
60
  }.freeze
59
61
 
@@ -90,8 +92,10 @@ module RuboCop
90
92
  description_text = string_contents(current_description)
91
93
  return unless (new_description = correct_description(description_text, description_map))
92
94
 
95
+ quote = current_description.dstr_type? ? '"' : "'"
96
+
93
97
  add_offense(current_description, message: message) do |corrector|
94
- corrector.replace(current_description, "'#{new_description}'")
98
+ corrector.replace(current_description, "#{quote}#{new_description}#{quote}")
95
99
  end
96
100
  end
97
101
 
@@ -106,7 +110,7 @@ module RuboCop
106
110
  end
107
111
 
108
112
  def string_contents(node)
109
- node.str_type? ? node.value : node.source
113
+ node.type?(:str, :dstr) ? node.value : node.source
110
114
  end
111
115
  end
112
116
  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
@@ -27,7 +27,8 @@ module RuboCop
27
27
  MSG = 'Replace `%<names>s` in node pattern union with `%<replacement>s`.'
28
28
  RESTRICT_ON_SEND = %i[def_node_matcher def_node_search].freeze
29
29
  NODE_GROUPS = {
30
- any_block: %i[block numblock],
30
+ any_block: %i[block numblock itblock],
31
+ any_def: %i[def defs],
31
32
  argument: %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg forward_arg shadowarg],
32
33
  boolean: %i[true false],
33
34
  call: %i[send csend],
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks that node types are checked against their group when all types of a
7
+ # group are checked.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # node.type?(:irange, :erange)
12
+ #
13
+ # # good
14
+ # node.range_type?
15
+ #
16
+ # # bad
17
+ # node.type?(:irange, :erange, :send, :csend)
18
+ #
19
+ # # good
20
+ # node.type?(:range, :call)
21
+ #
22
+ class NodeTypeGroup < Base
23
+ extend AutoCorrector
24
+ include RangeHelp
25
+
26
+ MSG = 'Use `:%<group>s` instead of individually listing group types.'
27
+
28
+ RESTRICT_ON_SEND = %i[type? each_ancestor each_child_node each_descendant each_node].freeze
29
+
30
+ def on_send(node)
31
+ return unless node.receiver
32
+
33
+ symbol_args = node.arguments.select(&:sym_type?)
34
+ return if symbol_args.none?
35
+
36
+ NodePatternGroups::NODE_GROUPS.each do |group_name, group_types|
37
+ next unless group_satisfied?(group_types, symbol_args)
38
+
39
+ offense_range = arguments_range(node)
40
+ add_offense(offense_range, message: format(MSG, group: group_name)) do |corrector|
41
+ autocorrect(corrector, node, symbol_args, group_name, group_types)
42
+ end
43
+ end
44
+ end
45
+ alias on_csend on_send
46
+
47
+ private
48
+
49
+ def arguments_range(node)
50
+ range_between(
51
+ node.first_argument.source_range.begin_pos,
52
+ node.last_argument.source_range.end_pos
53
+ )
54
+ end
55
+
56
+ def group_satisfied?(group_types, symbol_args)
57
+ group_types.all? { |type| symbol_args.any? { |arg| arg.value == type } }
58
+ end
59
+
60
+ def autocorrect(corrector, node, symbol_args, group_name, group_types)
61
+ if node.method?(:type?) && node.arguments.count == group_types.count
62
+ autocorrect_to_explicit_predicate(corrector, node, group_name)
63
+ else
64
+ autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
65
+ end
66
+ end
67
+
68
+ def autocorrect_to_explicit_predicate(corrector, node, group_name)
69
+ corrector.replace(node.selector, "#{group_name}_type?")
70
+ corrector.remove(arguments_range(node))
71
+ end
72
+
73
+ def autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
74
+ first_replaced = false
75
+ symbol_args.each do |arg|
76
+ next unless group_types.include?(arg.value)
77
+
78
+ if first_replaced
79
+ range = range_with_surrounding_space(arg.source_range)
80
+ range = range_with_surrounding_comma(range, :left)
81
+ corrector.remove(range)
82
+ else
83
+ first_replaced = true
84
+ corrector.replace(arg, ":#{group_name}")
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -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
@@ -38,23 +38,24 @@ module RuboCop
38
38
 
39
39
  describe = find_describe_method_node(node)
40
40
 
41
- unless (exist_config = describe.last_argument.source == ':config')
42
- additional_message = ' and specify `:config` in `describe`'
43
- end
41
+ should_append_config = describe && describe.last_argument.source != ':config'
42
+ additional_message = ' and specify `:config` in `describe`' if should_append_config
44
43
 
45
44
  message = format(MSG, additional_message: additional_message)
46
45
 
47
46
  add_offense(node, message: message) do |corrector|
48
47
  corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
49
48
 
50
- corrector.insert_after(describe.last_argument, ', :config') unless exist_config
49
+ corrector.insert_after(describe.last_argument, ', :config') if should_append_config
51
50
  end
52
51
  end
53
52
 
54
53
  private
55
54
 
56
55
  def find_describe_method_node(block_node)
57
- block_node.ancestors.find { |node| node.block_type? && node.method?(:describe) }.send_node
56
+ block_node.ancestors.find do |node|
57
+ node.block_type? && node.method?(:describe)
58
+ end&.send_node
58
59
  end
59
60
  end
60
61
  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'
@@ -16,6 +17,7 @@ require_relative 'internal_affairs/node_destructuring'
16
17
  require_relative 'internal_affairs/node_first_or_last_argument'
17
18
  require_relative 'internal_affairs/node_matcher_directive'
18
19
  require_relative 'internal_affairs/node_pattern_groups'
20
+ require_relative 'internal_affairs/node_type_group'
19
21
  require_relative 'internal_affairs/node_type_multiple_predicates'
20
22
  require_relative 'internal_affairs/node_type_predicate'
21
23
  require_relative 'internal_affairs/numblock_handler'
@@ -36,19 +38,3 @@ require_relative 'internal_affairs/style_detected_api_use'
36
38
  require_relative 'internal_affairs/undefined_config'
37
39
  require_relative 'internal_affairs/useless_message_assertion'
38
40
  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,7 @@ 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
+ any_def
76
77
  splat
77
78
  and
78
79
  or
@@ -85,6 +86,7 @@ module RuboCop
85
86
  end
86
87
 
87
88
  alias on_numblock on_block
89
+ alias on_itblock on_block
88
90
 
89
91
  def style_parameter_name
90
92
  'EnforcedStyleAlignWith'
@@ -43,6 +43,7 @@ module RuboCop
43
43
  end
44
44
 
45
45
  alias on_numblock on_block
46
+ alias on_itblock on_block
46
47
 
47
48
  private
48
49
 
@@ -155,10 +155,10 @@ module RuboCop
155
155
  end
156
156
 
157
157
  def all_elements_aligned?(elements)
158
- elements.flat_map do |e|
159
- if e.hash_type?
160
- e.each_child_node.map { |child| child.loc.column }
161
- else
158
+ if elements.first.hash_type?
159
+ elements.first.each_child_node.map { |child| child.loc.column }
160
+ else
161
+ elements.flat_map do |e|
162
162
  e.loc.column
163
163
  end
164
164
  end.uniq.count == 1
@@ -48,7 +48,7 @@ module RuboCop
48
48
  def on_send(node)
49
49
  return unless node.def_modifier?
50
50
 
51
- method_def = node.each_descendant(:def, :defs).first
51
+ method_def = node.each_descendant(:any_def).first
52
52
  expr = node.source_range
53
53
 
54
54
  line_start = range_between(expr.begin_pos, method_def.loc.keyword.end_pos)