rubocop 1.57.1 → 1.65.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 (266) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -5
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +136 -19
  7. data/lib/rubocop/cached_data.rb +11 -3
  8. data/lib/rubocop/cli/command/auto_generate_config.rb +22 -8
  9. data/lib/rubocop/cli/command/lsp.rb +2 -2
  10. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  11. data/lib/rubocop/cli.rb +10 -1
  12. data/lib/rubocop/config.rb +36 -12
  13. data/lib/rubocop/config_finder.rb +12 -2
  14. data/lib/rubocop/config_loader.rb +1 -2
  15. data/lib/rubocop/config_loader_resolver.rb +9 -3
  16. data/lib/rubocop/config_obsoletion.rb +11 -8
  17. data/lib/rubocop/config_validator.rb +14 -7
  18. data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
  19. data/lib/rubocop/cop/base.rb +63 -16
  20. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  21. data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
  22. data/lib/rubocop/cop/cop.rb +20 -2
  23. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  24. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  25. data/lib/rubocop/cop/documentation.rb +16 -6
  26. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  27. data/lib/rubocop/cop/force.rb +12 -0
  28. data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
  29. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  30. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  31. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  32. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  33. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  34. data/lib/rubocop/cop/internal_affairs/example_description.rb +6 -5
  35. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  36. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  37. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  38. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +123 -29
  39. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  40. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  41. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  42. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  43. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  44. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  45. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  46. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
  47. data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
  48. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  49. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
  50. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +24 -7
  51. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  52. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  53. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  54. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  55. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
  56. data/lib/rubocop/cop/layout/line_length.rb +20 -20
  57. data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -3
  58. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  59. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  60. data/lib/rubocop/cop/layout/space_around_operators.rb +53 -20
  61. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  62. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  63. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  64. data/lib/rubocop/cop/legacy/corrector.rb +12 -2
  65. data/lib/rubocop/cop/lint/assignment_in_condition.rb +6 -6
  66. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  67. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  68. data/lib/rubocop/cop/lint/debugger.rb +29 -3
  69. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  70. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -1
  71. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  72. data/lib/rubocop/cop/lint/empty_conditional_body.rb +2 -2
  73. data/lib/rubocop/cop/lint/empty_when.rb +1 -1
  74. data/lib/rubocop/cop/lint/erb_new_arguments.rb +24 -17
  75. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  76. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  77. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +14 -7
  78. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  79. data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
  80. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  81. data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
  82. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  83. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  84. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  85. data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
  86. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +54 -6
  87. data/lib/rubocop/cop/lint/redundant_with_index.rb +6 -2
  88. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  89. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  90. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
  91. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  92. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  93. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  94. data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
  95. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  96. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -3
  97. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  98. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +3 -2
  99. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -2
  100. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  101. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  102. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  103. data/lib/rubocop/cop/lint/void.rb +53 -12
  104. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  105. data/lib/rubocop/cop/metrics/block_nesting.rb +19 -7
  106. data/lib/rubocop/cop/metrics/class_length.rb +6 -1
  107. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
  108. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  109. data/lib/rubocop/cop/mixin/allowed_methods.rb +7 -1
  110. data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
  111. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  112. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  113. data/lib/rubocop/cop/mixin/comments_help.rb +16 -12
  114. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  115. data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
  116. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +23 -13
  117. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  118. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  119. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  120. data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
  121. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  122. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  123. data/lib/rubocop/cop/naming/block_forwarding.rb +34 -7
  124. data/lib/rubocop/cop/naming/constant_name.rb +1 -2
  125. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  126. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
  127. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  128. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  129. data/lib/rubocop/cop/registry.rb +1 -1
  130. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  131. data/lib/rubocop/cop/security/open.rb +2 -2
  132. data/lib/rubocop/cop/style/access_modifier_declarations.rb +52 -2
  133. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  134. data/lib/rubocop/cop/style/alias.rb +1 -0
  135. data/lib/rubocop/cop/style/arguments_forwarding.rb +155 -21
  136. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  137. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  138. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  139. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  140. data/lib/rubocop/cop/style/class_check.rb +1 -0
  141. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  142. data/lib/rubocop/cop/style/collection_compact.rb +21 -11
  143. data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
  144. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  145. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
  146. data/lib/rubocop/cop/style/conditional_assignment.rb +7 -8
  147. data/lib/rubocop/cop/style/copyright.rb +31 -21
  148. data/lib/rubocop/cop/style/date_time.rb +5 -4
  149. data/lib/rubocop/cop/style/documentation.rb +24 -24
  150. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  151. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  152. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  153. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  154. data/lib/rubocop/cop/style/eval_with_location.rb +6 -15
  155. data/lib/rubocop/cop/style/exact_regexp_match.rb +4 -2
  156. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  157. data/lib/rubocop/cop/style/for.rb +2 -0
  158. data/lib/rubocop/cop/style/format_string.rb +9 -9
  159. data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
  160. data/lib/rubocop/cop/style/hash_except.rb +10 -6
  161. data/lib/rubocop/cop/style/hash_syntax.rb +24 -2
  162. data/lib/rubocop/cop/style/identical_conditional_branches.rb +12 -1
  163. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -3
  164. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  165. data/lib/rubocop/cop/style/invertible_unless_condition.rb +44 -2
  166. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +82 -50
  167. data/lib/rubocop/cop/style/map_into_array.rb +175 -0
  168. data/lib/rubocop/cop/style/map_to_hash.rb +18 -8
  169. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  170. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +19 -5
  171. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  172. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  173. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  174. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  175. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  176. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +5 -3
  177. data/lib/rubocop/cop/style/next.rb +1 -1
  178. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  179. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  180. data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
  181. data/lib/rubocop/cop/style/object_then.rb +5 -3
  182. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  183. data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
  184. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  185. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  186. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  187. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  188. data/lib/rubocop/cop/style/redundant_argument.rb +27 -3
  189. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  190. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  191. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +5 -4
  192. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -10
  193. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  194. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  195. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
  196. data/lib/rubocop/cop/style/redundant_filter_chain.rb +5 -4
  197. data/lib/rubocop/cop/style/redundant_line_continuation.rb +19 -2
  198. data/lib/rubocop/cop/style/redundant_parentheses.rb +50 -19
  199. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  200. data/lib/rubocop/cop/style/redundant_return.rb +7 -1
  201. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  202. data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
  203. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  204. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  205. data/lib/rubocop/cop/style/require_order.rb +1 -1
  206. data/lib/rubocop/cop/style/sample.rb +3 -4
  207. data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
  208. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  209. data/lib/rubocop/cop/style/semicolon.rb +8 -0
  210. data/lib/rubocop/cop/style/send.rb +4 -4
  211. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +104 -0
  212. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  213. data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
  214. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  215. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  216. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  217. data/lib/rubocop/cop/style/strip.rb +7 -4
  218. data/lib/rubocop/cop/style/super_arguments.rb +174 -0
  219. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  220. data/lib/rubocop/cop/style/symbol_proc.rb +75 -5
  221. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  222. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  223. data/lib/rubocop/cop/style/zero_length_predicate.rb +28 -24
  224. data/lib/rubocop/cop/team.rb +13 -0
  225. data/lib/rubocop/cop/util.rb +7 -1
  226. data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
  227. data/lib/rubocop/cops_documentation_generator.rb +16 -4
  228. data/lib/rubocop/directive_comment.rb +10 -8
  229. data/lib/rubocop/ext/regexp_node.rb +9 -4
  230. data/lib/rubocop/ext/regexp_parser.rb +4 -21
  231. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  232. data/lib/rubocop/formatter/disabled_config_formatter.rb +23 -8
  233. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  234. data/lib/rubocop/formatter/html_formatter.rb +37 -14
  235. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  236. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  237. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  238. data/lib/rubocop/formatter.rb +1 -1
  239. data/lib/rubocop/lockfile.rb +56 -7
  240. data/lib/rubocop/lsp/logger.rb +1 -1
  241. data/lib/rubocop/lsp/routes.rb +12 -15
  242. data/lib/rubocop/lsp/runtime.rb +1 -1
  243. data/lib/rubocop/lsp/server.rb +7 -2
  244. data/lib/rubocop/lsp/severity.rb +1 -1
  245. data/lib/rubocop/lsp.rb +36 -0
  246. data/lib/rubocop/magic_comment.rb +1 -1
  247. data/lib/rubocop/options.rb +14 -11
  248. data/lib/rubocop/path_util.rb +6 -2
  249. data/lib/rubocop/rake_task.rb +1 -1
  250. data/lib/rubocop/result_cache.rb +0 -1
  251. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  252. data/lib/rubocop/rspec/expect_offense.rb +16 -8
  253. data/lib/rubocop/rspec/shared_contexts.rb +73 -16
  254. data/lib/rubocop/rspec/support.rb +3 -0
  255. data/lib/rubocop/runner.rb +14 -3
  256. data/lib/rubocop/server/cache.rb +11 -2
  257. data/lib/rubocop/server/client_command/exec.rb +2 -3
  258. data/lib/rubocop/server/client_command/start.rb +1 -1
  259. data/lib/rubocop/server/core.rb +4 -0
  260. data/lib/rubocop/server/server_command/exec.rb +0 -1
  261. data/lib/rubocop/target_finder.rb +84 -78
  262. data/lib/rubocop/target_ruby.rb +82 -80
  263. data/lib/rubocop/version.rb +19 -4
  264. data/lib/rubocop.rb +8 -0
  265. metadata +27 -29
  266. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
-
5
3
  # FIXME: Moving Rails department code to RuboCop Rails will remove
6
4
  # the following rubocop:disable comment.
7
5
  # rubocop:disable Metrics/ClassLength
@@ -246,6 +244,10 @@ module RuboCop
246
244
  end
247
245
  end
248
246
 
247
+ def parser_engine
248
+ @parser_engine ||= for_all_cops.fetch('ParserEngine', :parser_whitequark).to_sym
249
+ end
250
+
249
251
  def target_rails_version
250
252
  @target_rails_version ||=
251
253
  if for_all_cops['TargetRailsVersion']
@@ -261,6 +263,7 @@ module RuboCop
261
263
  PathUtil.smart_path(@loaded_path)
262
264
  end
263
265
 
266
+ # @return [String, nil]
264
267
  def bundler_lock_file_path
265
268
  return nil unless loaded_path
266
269
 
@@ -284,27 +287,48 @@ module RuboCop
284
287
  end
285
288
  end
286
289
 
290
+ # Returns target's locked gem versions (i.e. from Gemfile.lock or gems.locked)
291
+ # @returns [Hash{String => Gem::Version}] The locked gem versions, keyed by the gems' names.
292
+ def gem_versions_in_target
293
+ @gem_versions_in_target ||= read_gem_versions_from_target_lockfile
294
+ end
295
+
287
296
  def inspect # :nodoc:
288
297
  "#<#{self.class.name}:#{object_id} @loaded_path=#{loaded_path}>"
289
298
  end
290
299
 
291
300
  private
292
301
 
302
+ # @return [Float, nil] The Rails version as a `major.minor` Float.
293
303
  def target_rails_version_from_bundler_lock_file
294
304
  @target_rails_version_from_bundler_lock_file ||= read_rails_version_from_bundler_lock_file
295
305
  end
296
306
 
307
+ # @return [Float, nil] The Rails version as a `major.minor` Float.
297
308
  def read_rails_version_from_bundler_lock_file
298
- lock_file_path = bundler_lock_file_path
299
- return nil unless lock_file_path
300
-
301
- File.foreach(lock_file_path) do |line|
302
- # If Rails (or one of its frameworks) is in Gemfile.lock or gems.lock, there should be
303
- # a line like:
304
- # railties (X.X.X)
305
- result = line.match(/^\s+railties\s+\((\d+\.\d+)/)
306
- return result.captures.first.to_f if result
307
- end
309
+ return nil unless gem_versions_in_target
310
+
311
+ # Look for `railties` instead of `rails`, to support apps that only use a subset of `rails`
312
+ # See https://github.com/rubocop/rubocop/pull/11289
313
+ rails_version_in_target = gem_versions_in_target['railties']
314
+ return nil unless rails_version_in_target
315
+
316
+ gem_version_to_major_minor_float(rails_version_in_target)
317
+ end
318
+
319
+ # @param [Gem::Version] gem_version an object like `Gem::Version.new("7.1.2.3")`
320
+ # @return [Float] The major and minor version, like `7.1`
321
+ def gem_version_to_major_minor_float(gem_version)
322
+ segments = gem_version.segments
323
+ Float("#{segments[0]}.#{segments[1]}")
324
+ end
325
+
326
+ # @returns [Hash{String => Gem::Version}] The locked gem versions, keyed by the gems' names.
327
+ def read_gem_versions_from_target_lockfile
328
+ lockfile_path = bundler_lock_file_path
329
+ return nil unless lockfile_path
330
+
331
+ Lockfile.new(lockfile_path).gem_versions
308
332
  end
309
333
 
310
334
  def enable_cop?(qualified_cop_name, cop_options)
@@ -17,8 +17,8 @@ module RuboCop
17
17
  attr_writer :project_root
18
18
 
19
19
  def find_config_path(target_dir)
20
- find_project_dotfile(target_dir) || find_user_dotfile || find_user_xdg_config ||
21
- DEFAULT_FILE
20
+ find_project_dotfile(target_dir) || find_project_root_dot_config ||
21
+ find_user_dotfile || find_user_xdg_config || DEFAULT_FILE
22
22
  end
23
23
 
24
24
  # Returns the path RuboCop inferred as the root of the project. No file
@@ -41,6 +41,16 @@ module RuboCop
41
41
  find_file_upwards(DOTFILE, target_dir, project_root)
42
42
  end
43
43
 
44
+ def find_project_root_dot_config
45
+ return unless project_root
46
+
47
+ dotfile = File.join(project_root, '.config', DOTFILE)
48
+ return dotfile if File.exist?(dotfile)
49
+
50
+ xdg_config = File.join(project_root, '.config', 'rubocop', XDG_CONFIG)
51
+ xdg_config if File.exist?(xdg_config)
52
+ end
53
+
44
54
  def find_user_dotfile
45
55
  return unless ENV.key?('HOME')
46
56
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'erb'
4
- require 'pathname'
5
4
  require 'yaml'
6
5
  require_relative 'config_finder'
7
6
 
@@ -165,7 +164,7 @@ module RuboCop
165
164
  # searches will go past this directory.
166
165
  # @deprecated Use `RuboCop::ConfigFinder.project_root` instead.
167
166
  def project_root
168
- warn Rainbow(<<~WARNING).yellow
167
+ warn Rainbow(<<~WARNING).yellow, uplevel: 1
169
168
  `RuboCop::ConfigLoader.project_root` is deprecated and will be removed in RuboCop 2.0. \
170
169
  Use `RuboCop::ConfigFinder.project_root` instead.
171
170
  WARNING
@@ -6,7 +6,7 @@ require 'yaml'
6
6
  module RuboCop
7
7
  # A help class for ConfigLoader that handles configuration resolution.
8
8
  # @api private
9
- class ConfigLoaderResolver
9
+ class ConfigLoaderResolver # rubocop:disable Metrics/ClassLength
10
10
  def resolve_requires(path, hash)
11
11
  config_dir = File.dirname(path)
12
12
  hash.delete('require').tap do |loaded_features|
@@ -267,8 +267,14 @@ module RuboCop
267
267
 
268
268
  def gem_config_path(gem_name, relative_config_path)
269
269
  if defined?(Bundler)
270
- gem = Bundler.load.specs[gem_name].first
271
- gem_path = gem.full_gem_path if gem
270
+ begin
271
+ gem = Bundler.load.specs[gem_name].first
272
+ gem_path = gem.full_gem_path if gem
273
+ rescue Bundler::GemfileNotFound
274
+ # No Gemfile found. Bundler may be loaded manually
275
+ rescue Bundler::GitError
276
+ # The Gemfile exists but contains an uninstalled git source
277
+ end
272
278
  end
273
279
 
274
280
  gem_path ||= Gem::Specification.find_by_name(gem_name).gem_dir
@@ -15,6 +15,8 @@ module RuboCop
15
15
  'changed_parameters' => ChangedParameter,
16
16
  'changed_enforced_styles' => ChangedEnforcedStyles
17
17
  }.freeze
18
+ LOAD_RULES_CACHE = {} # rubocop:disable Style/MutableConstant
19
+ private_constant :LOAD_RULES_CACHE
18
20
 
19
21
  attr_reader :rules, :warnings
20
22
 
@@ -48,16 +50,17 @@ module RuboCop
48
50
  # Default rules for obsoletions are in config/obsoletion.yml
49
51
  # Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
50
52
  def load_rules # rubocop:disable Metrics/AbcSize
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
- case first
54
- when Hash
55
- first.merge(second)
56
- when Array
57
- first.concat(second)
53
+ rules = LOAD_RULES_CACHE[self.class.files] ||=
54
+ self.class.files.each_with_object({}) do |filename, hash|
55
+ hash.merge!(YAML.safe_load(File.read(filename)) || {}) do |_key, first, second|
56
+ case first
57
+ when Hash
58
+ first.merge(second)
59
+ when Array
60
+ first.concat(second)
61
+ end
58
62
  end
59
63
  end
60
- end
61
64
 
62
65
  cop_rules = rules.slice(*COP_RULE_CLASSES.keys)
63
66
  parameter_rules = rules.slice(*PARAMETER_RULE_CLASSES.keys)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
-
5
3
  module RuboCop
6
4
  # Handles validation of configuration, for example cop names, parameter
7
5
  # names, and Ruby versions.
@@ -20,6 +18,7 @@ module RuboCop
20
18
  # @api private
21
19
  CONFIG_CHECK_KEYS = %w[Enabled Safe SafeAutoCorrect AutoCorrect].to_set.freeze
22
20
  CONFIG_CHECK_DEPARTMENTS = %w[pending override_department].freeze
21
+ CONFIG_CHECK_AUTOCORRECTS = %w[always contextual disabled].freeze
23
22
  private_constant :CONFIG_CHECK_KEYS, :CONFIG_CHECK_DEPARTMENTS
24
23
 
25
24
  def_delegators :@config, :smart_loaded_path, :for_all_cops
@@ -250,23 +249,31 @@ module RuboCop
250
249
  end
251
250
  end
252
251
 
252
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
253
253
  def check_cop_config_value(hash, parent = nil)
254
254
  hash.each do |key, value|
255
255
  check_cop_config_value(value, key) if value.is_a?(Hash)
256
256
 
257
257
  next unless CONFIG_CHECK_KEYS.include?(key) && value.is_a?(String)
258
258
 
259
- next if key == 'Enabled' && CONFIG_CHECK_DEPARTMENTS.include?(value)
259
+ if key == 'Enabled' && !CONFIG_CHECK_DEPARTMENTS.include?(value)
260
+ supposed_values = 'a boolean'
261
+ elsif key == 'AutoCorrect' && !CONFIG_CHECK_AUTOCORRECTS.include?(value)
262
+ supposed_values = '`always`, `contextual`, `disabled`, or a boolean'
263
+ else
264
+ next
265
+ end
260
266
 
261
- raise ValidationError, msg_not_boolean(parent, key, value)
267
+ raise ValidationError, param_error_message(parent, key, value, supposed_values)
262
268
  end
263
269
  end
270
+ # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
264
271
 
265
272
  # FIXME: Handling colors in exception messages like this is ugly.
266
- def msg_not_boolean(parent, key, value)
273
+ def param_error_message(parent, key, value, supposed_values)
267
274
  "#{Rainbow('').reset}" \
268
- "Property #{Rainbow(key).yellow} of cop #{Rainbow(parent).yellow} " \
269
- "is supposed to be a boolean and #{Rainbow(value).yellow} is not."
275
+ "Property #{Rainbow(key).yellow} of #{Rainbow(parent).yellow} cop " \
276
+ "is supposed to be #{supposed_values} and #{Rainbow(value).yellow} is not."
270
277
  end
271
278
  end
272
279
  end
@@ -32,7 +32,12 @@ module RuboCop
32
32
  # allow turning off autocorrect on a cop by cop basis
33
33
  return true unless cop_config
34
34
 
35
- return false if cop_config['AutoCorrect'] == false
35
+ # `false` is the same as `disabled` for backward compatibility.
36
+ return false if ['disabled', false].include?(cop_config['AutoCorrect'])
37
+
38
+ # When LSP is enabled, it is considered as editing source code,
39
+ # and autocorrection with `AutoCorrect: contextual` will not be performed.
40
+ return false if contextual_autocorrect? && LSP.enabled?
36
41
 
37
42
  # :safe_autocorrect is a derived option based on several command-line
38
43
  # arguments - see RuboCop::Options#add_autocorrection_options
@@ -60,16 +60,20 @@ module RuboCop
60
60
  []
61
61
  end
62
62
 
63
- # Cops (other than builtin) are encouraged to implement this
63
+ # Returns an url to view this cops documentation online.
64
+ # Requires 'DocumentationBaseURL' to be set for your department.
65
+ # Will follow the convention of RuboCops own documentation structure,
66
+ # overwrite this method to accommodate your custom layout.
64
67
  # @return [String, nil]
65
68
  #
66
69
  # @api public
67
- def self.documentation_url
68
- Documentation.url_for(self) if builtin?
70
+ def self.documentation_url(config = nil)
71
+ Documentation.url_for(self, config)
69
72
  end
70
73
 
71
74
  def self.inherited(subclass)
72
75
  super
76
+ subclass.instance_variable_set(:@gem_requirements, gem_requirements.dup)
73
77
  Registry.global.enlist(subclass)
74
78
  end
75
79
 
@@ -126,6 +130,29 @@ module RuboCop
126
130
  false
127
131
  end
128
132
 
133
+ ## Gem requirements
134
+
135
+ @gem_requirements = {}
136
+
137
+ class << self
138
+ attr_reader :gem_requirements
139
+
140
+ # Register a version requirement for the given gem name.
141
+ # This cop will be skipped unless the target satisfies *all* requirements.
142
+ # @param [String] gem_name
143
+ # @param [Array<String>] version_requirements The version requirements,
144
+ # using the same syntax as a Gemfile, e.g. ">= 1.2.3"
145
+ #
146
+ # If omitted, any version of the gem will be accepted.
147
+ #
148
+ # https://guides.rubygems.org/patterns/#declaring-dependencies
149
+ #
150
+ # @api public
151
+ def requires_gem(gem_name, *version_requirements)
152
+ @gem_requirements[gem_name] = Gem::Requirement.new(version_requirements)
153
+ end
154
+ end
155
+
129
156
  def initialize(config = nil, options = nil)
130
157
  @config = config || Config.new
131
158
  @options = options || { debug: false }
@@ -162,7 +189,9 @@ module RuboCop
162
189
  def add_global_offense(message = nil, severity: nil)
163
190
  severity = find_severity(nil, severity)
164
191
  message = find_message(nil, message)
165
- current_offenses << Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported)
192
+ range = Offense::NO_LOCATION
193
+ status = enabled_line?(range.line) ? :unsupported : :disabled
194
+ current_offenses << Offense.new(severity, range, message, name, status)
166
195
  end
167
196
 
168
197
  # Adds an offense on the specified range (or node with an expression)
@@ -232,6 +261,10 @@ module RuboCop
232
261
  @config.target_ruby_version
233
262
  end
234
263
 
264
+ def parser_engine
265
+ @config.parser_engine
266
+ end
267
+
235
268
  def target_rails_version
236
269
  @config.target_rails_version
237
270
  end
@@ -241,6 +274,7 @@ module RuboCop
241
274
  end
242
275
 
243
276
  def relevant_file?(file)
277
+ return false unless target_satisfies_all_gem_version_requirements?
244
278
  return true unless @config.clusivity_config_for_badge?(self.class.badge)
245
279
 
246
280
  file == RuboCop::AST::ProcessedSource::STRING_SOURCE_NAME ||
@@ -254,7 +288,7 @@ module RuboCop
254
288
 
255
289
  # There should be very limited reasons for a Cop to do it's own parsing
256
290
  def parse(source, path = nil)
257
- ProcessedSource.new(source, target_ruby_version, path)
291
+ ProcessedSource.new(source, target_ruby_version, path, parser_engine: parser_engine)
258
292
  end
259
293
 
260
294
  # @api private
@@ -305,6 +339,17 @@ module RuboCop
305
339
  @current_original = original
306
340
  end
307
341
 
342
+ # @api private
343
+ def always_autocorrect?
344
+ # `true` is the same as `'always'` for backward compatibility.
345
+ ['always', true].include?(cop_config.fetch('AutoCorrect', 'always'))
346
+ end
347
+
348
+ # @api private
349
+ def contextual_autocorrect?
350
+ cop_config.fetch('AutoCorrect', 'always') == 'contextual'
351
+ end
352
+
308
353
  def inspect # :nodoc:
309
354
  "#<#{self.class.name}:#{object_id} @config=#{@config} @options=#{@options}>"
310
355
  end
@@ -356,16 +401,6 @@ module RuboCop
356
401
 
357
402
  ### Actually private methods
358
403
 
359
- # rubocop:disable Layout/ClassStructure
360
- def self.builtin?
361
- return false unless (m = instance_methods(false).first) # any custom method will do
362
-
363
- path, _line = instance_method(m).source_location
364
- path.start_with?(__dir__)
365
- end
366
- private_class_method :builtin?
367
- # rubocop:enable Layout/ClassStructure
368
-
369
404
  def reset_investigation
370
405
  @currently_disabled_lines = @current_offenses = @processed_source = @current_corrector = nil
371
406
  end
@@ -389,7 +424,7 @@ module RuboCop
389
424
  def use_corrector(range, corrector)
390
425
  if autocorrect?
391
426
  attempt_correction(range, corrector)
392
- elsif corrector && cop_config.fetch('AutoCorrect', true)
427
+ elsif corrector && (always_autocorrect? || (contextual_autocorrect? && !LSP.enabled?))
393
428
  :uncorrected
394
429
  else
395
430
  :unsupported
@@ -481,6 +516,18 @@ module RuboCop
481
516
  range.end_pos + @current_offset
482
517
  )
483
518
  end
519
+
520
+ def target_satisfies_all_gem_version_requirements?
521
+ self.class.gem_requirements.all? do |gem_name, version_req|
522
+ all_gem_versions_in_target = @config.gem_versions_in_target
523
+ next false unless all_gem_versions_in_target
524
+
525
+ gem_version_in_target = all_gem_versions_in_target[gem_name]
526
+ next false unless gem_version_in_target
527
+
528
+ version_req.satisfied_by?(gem_version_in_target)
529
+ end
530
+ end
484
531
  end
485
532
  end
486
533
  end
@@ -161,9 +161,9 @@ module RuboCop
161
161
  end
162
162
 
163
163
  def gem_options(node)
164
- return [] unless node.arguments.last&.type == :hash
164
+ return [] unless node.last_argument&.type == :hash
165
165
 
166
- node.arguments.last.keys.map(&:value)
166
+ node.last_argument.keys.map(&:value)
167
167
  end
168
168
  end
169
169
  end
@@ -90,13 +90,11 @@ module RuboCop
90
90
  Array(cop_config['AllowedGems'])
91
91
  end
92
92
 
93
- def message(range)
94
- gem_specification = range.source
95
-
93
+ def message(_range)
96
94
  if required_style?
97
- format(REQUIRED_MSG, gem_specification: gem_specification)
95
+ REQUIRED_MSG
98
96
  elsif forbidden_style?
99
- format(FORBIDDEN_MSG, gem_specification: gem_specification)
97
+ FORBIDDEN_MSG
100
98
  end
101
99
  end
102
100
 
@@ -37,16 +37,28 @@ module RuboCop
37
37
 
38
38
  # @deprecated Use Registry.global
39
39
  def self.registry
40
+ warn Rainbow(<<~WARNING).yellow, uplevel: 1
41
+ `Cop.registry` is deprecated. Use `Registry.global` instead.
42
+ WARNING
43
+
40
44
  Registry.global
41
45
  end
42
46
 
43
47
  # @deprecated Use Registry.all
44
48
  def self.all
49
+ warn Rainbow(<<~WARNING).yellow, uplevel: 1
50
+ `Cop.all` is deprecated. Use `Registry.all` instead.
51
+ WARNING
52
+
45
53
  Registry.all
46
54
  end
47
55
 
48
56
  # @deprecated Use Registry.qualified_cop_name
49
57
  def self.qualified_cop_name(name, origin)
58
+ warn Rainbow(<<~WARNING).yellow, uplevel: 1
59
+ `Cop.qualified_cop_name` is deprecated. Use `Registry.qualified_cop_name` instead.
60
+ WARNING
61
+
50
62
  Registry.qualified_cop_name(name, origin)
51
63
  end
52
64
 
@@ -74,13 +86,19 @@ module RuboCop
74
86
 
75
87
  # @deprecated Use class method
76
88
  def support_autocorrect?
77
- # warn 'deprecated, use cop.class.support_autocorrect?' TODO
89
+ warn Rainbow(<<~WARNING).yellow, uplevel: 1
90
+ `support_autocorrect?` is deprecated. Use `cop.class.support_autocorrect?`.
91
+ WARNING
92
+
78
93
  self.class.support_autocorrect?
79
94
  end
80
95
 
81
96
  # @deprecated
82
97
  def corrections
83
- # warn 'Cop#corrections is deprecated' TODO
98
+ warn Rainbow(<<~WARNING).yellow, uplevel: 1
99
+ `Cop#corrections` is deprecated.
100
+ WARNING
101
+
84
102
  return [] unless @last_corrector
85
103
 
86
104
  Legacy::CorrectionsProxy.new(@last_corrector)
@@ -34,18 +34,14 @@ module RuboCop
34
34
  end
35
35
 
36
36
  def offending_range
37
+ begin_range = block_node.source_range.begin
38
+
37
39
  if block_node.arguments?
38
- replacement_range(argument_node.source_range.end_pos)
40
+ begin_range.join(argument_node.source_range.end)
39
41
  else
40
- replacement_range(block_node.loc.begin.end_pos)
42
+ begin_range.join(block_node.loc.begin.end)
41
43
  end
42
44
  end
43
-
44
- def replacement_range(end_pos)
45
- Parser::Source::Range.new(block_node.source_range.source_buffer,
46
- block_node.source_range.begin_pos,
47
- end_pos)
48
- end
49
45
  end
50
46
  end
51
47
  end
@@ -15,6 +15,8 @@ module RuboCop
15
15
  end
16
16
 
17
17
  def call(corrector)
18
+ offending_range = for_node.source_range.begin.join(end_range)
19
+
18
20
  corrector.replace(offending_range, correction)
19
21
  end
20
22
 
@@ -40,11 +42,11 @@ module RuboCop
40
42
  collection_node.range_type? || collection_node.or_type? || collection_node.and_type?
41
43
  end
42
44
 
43
- def end_position
45
+ def end_range
44
46
  if for_node.do?
45
- keyword_begin.end_pos
47
+ keyword_begin.end
46
48
  else
47
- collection_end.end_pos
49
+ collection_end.end
48
50
  end
49
51
  end
50
52
 
@@ -59,16 +61,6 @@ module RuboCop
59
61
  collection_node.source_range
60
62
  end
61
63
  end
62
-
63
- def offending_range
64
- replacement_range(end_position)
65
- end
66
-
67
- def replacement_range(end_pos)
68
- Parser::Source::Range.new(for_node.source_range.source_buffer,
69
- for_node.source_range.begin_pos,
70
- end_pos)
71
- end
72
64
  end
73
65
  end
74
66
  end
@@ -17,23 +17,33 @@ module RuboCop
17
17
  fragment = cop_class.cop_name.downcase.gsub(/[^a-z]/, '')
18
18
  base_url = base_url_for(cop_class, config)
19
19
 
20
- "#{base_url}/#{base}.html##{fragment}"
20
+ "#{base_url}/#{base}.html##{fragment}" if base_url
21
21
  end
22
22
 
23
23
  # @api private
24
24
  def base_url_for(cop_class, config)
25
- return default_base_url unless config
25
+ if config
26
+ department_name = cop_class.department.to_s
27
+ url = config.for_department(department_name)['DocumentationBaseURL']
28
+ return url if url
29
+ end
26
30
 
27
- department_name = cop_class.department.to_s
28
-
29
- config.for_department(department_name)['DocumentationBaseURL'] ||
30
- config.for_all_cops['DocumentationBaseURL']
31
+ default_base_url if builtin?(cop_class)
31
32
  end
32
33
 
33
34
  # @api private
34
35
  def default_base_url
35
36
  'https://docs.rubocop.org/rubocop'
36
37
  end
38
+
39
+ # @api private
40
+ def builtin?(cop_class)
41
+ # any custom method will do
42
+ return false unless (m = cop_class.instance_methods(false).first)
43
+
44
+ path, _line = cop_class.instance_method(m).source_location
45
+ path.start_with?(__dir__)
46
+ end
37
47
  end
38
48
  end
39
49
  end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # The parameter name given is transformed into a method name (eg. `Max`
9
9
  # becomes `self.max=` and `MinDigits` becomes `self.min_digits=`).
10
10
  def exclude_limit(parameter_name, method_name: transform(parameter_name))
11
- define_method("#{method_name}=") do |value|
11
+ define_method(:"#{method_name}=") do |value|
12
12
  cfg = config_to_allow_offenses
13
13
  cfg[:exclude_limit] ||= {}
14
14
  current_max = cfg[:exclude_limit][parameter_name]
@@ -4,6 +4,16 @@ module RuboCop
4
4
  module Cop
5
5
  # A scaffold for concrete forces.
6
6
  class Force
7
+ # @api private
8
+ class HookError < StandardError
9
+ attr_reader :joining_cop
10
+
11
+ def initialize(joining_cop)
12
+ super
13
+ @joining_cop = joining_cop
14
+ end
15
+ end
16
+
7
17
  attr_reader :cops
8
18
 
9
19
  def self.all
@@ -32,6 +42,8 @@ module RuboCop
32
42
  next unless cop.respond_to?(method_name)
33
43
 
34
44
  cop.public_send(method_name, *args)
45
+ rescue StandardError
46
+ raise HookError, cop
35
47
  end
36
48
  end
37
49
 
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Gemspec
6
+ # Prefer `add_dependency` over `add_runtime_dependency` as the latter is
7
+ # considered soft-deprecated.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Gem::Specification.new do |spec|
13
+ # spec.add_runtime_dependency('rubocop')
14
+ # end
15
+ #
16
+ # # good
17
+ # Gem::Specification.new do |spec|
18
+ # spec.add_dependency('rubocop')
19
+ # end
20
+ #
21
+ class AddRuntimeDependency < Base
22
+ extend AutoCorrector
23
+
24
+ MSG = 'Use `add_dependency` instead of `add_runtime_dependency`.'
25
+
26
+ RESTRICT_ON_SEND = %i[add_runtime_dependency].freeze
27
+
28
+ def on_send(node)
29
+ return if !node.receiver || node.arguments.empty?
30
+
31
+ add_offense(node.loc.selector) do |corrector|
32
+ corrector.replace(node.loc.selector, 'add_dependency')
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end