rubocop 0.72.0 → 0.76.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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/bin/console +1 -0
  4. data/config/default.yml +93 -56
  5. data/lib/rubocop.rb +21 -10
  6. data/lib/rubocop/ast/builder.rb +1 -0
  7. data/lib/rubocop/ast/node.rb +12 -14
  8. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +4 -4
  9. data/lib/rubocop/ast/node/return_node.rb +24 -0
  10. data/lib/rubocop/ast/traversal.rb +3 -3
  11. data/lib/rubocop/cli.rb +7 -4
  12. data/lib/rubocop/comment_config.rb +5 -4
  13. data/lib/rubocop/config.rb +28 -537
  14. data/lib/rubocop/config_loader.rb +21 -3
  15. data/lib/rubocop/config_loader_resolver.rb +4 -3
  16. data/lib/rubocop/config_obsoletion.rb +222 -0
  17. data/lib/rubocop/config_validator.rb +248 -0
  18. data/lib/rubocop/cop/autocorrect_logic.rb +71 -1
  19. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +1 -1
  20. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  21. data/lib/rubocop/cop/commissioner.rb +18 -16
  22. data/lib/rubocop/cop/cop.rb +49 -14
  23. data/lib/rubocop/cop/corrector.rb +10 -10
  24. data/lib/rubocop/cop/correctors/alignment_corrector.rb +43 -17
  25. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +2 -2
  26. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  27. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  28. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  29. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  30. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +1 -1
  31. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  32. data/lib/rubocop/cop/generator.rb +4 -4
  33. data/lib/rubocop/cop/generator/configuration_injector.rb +9 -4
  34. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  35. data/lib/rubocop/cop/internal_affairs/node_destructuring.rb +2 -2
  36. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +1 -1
  37. data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +2 -2
  38. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -1
  39. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +2 -2
  40. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -2
  41. data/lib/rubocop/cop/layout/align_hash.rb +6 -2
  42. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  43. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  44. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  45. data/lib/rubocop/cop/layout/comment_indentation.rb +10 -13
  46. data/lib/rubocop/cop/layout/empty_comment.rb +7 -16
  47. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +22 -7
  48. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +2 -2
  49. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +2 -2
  50. data/lib/rubocop/cop/layout/end_of_line.rb +8 -3
  51. data/lib/rubocop/cop/layout/extra_spacing.rb +14 -59
  52. data/lib/rubocop/cop/layout/indent_assignment.rb +10 -1
  53. data/lib/rubocop/cop/layout/indent_first_argument.rb +10 -8
  54. data/lib/rubocop/cop/layout/indent_first_hash_element.rb +1 -1
  55. data/lib/rubocop/cop/layout/indent_heredoc.rb +4 -3
  56. data/lib/rubocop/cop/layout/indentation_width.rb +20 -6
  57. data/lib/rubocop/cop/layout/leading_comment_space.rb +28 -0
  58. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  59. data/lib/rubocop/cop/layout/multiline_block_layout.rb +24 -2
  60. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +20 -4
  61. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +5 -1
  62. data/lib/rubocop/cop/layout/space_around_operators.rb +42 -23
  63. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -7
  64. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +8 -5
  65. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +21 -2
  66. data/lib/rubocop/cop/layout/space_inside_parens.rb +6 -6
  67. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +24 -40
  68. data/lib/rubocop/cop/layout/tab.rb +10 -22
  69. data/lib/rubocop/cop/layout/trailing_whitespace.rb +18 -2
  70. data/lib/rubocop/cop/lint/assignment_in_condition.rb +17 -4
  71. data/lib/rubocop/cop/lint/big_decimal_new.rb +1 -1
  72. data/lib/rubocop/cop/lint/debugger.rb +4 -6
  73. data/lib/rubocop/cop/lint/duplicate_methods.rb +3 -3
  74. data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
  75. data/lib/rubocop/cop/lint/empty_interpolation.rb +4 -4
  76. data/lib/rubocop/cop/lint/erb_new_arguments.rb +62 -5
  77. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -37
  78. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
  79. data/lib/rubocop/cop/lint/inherit_exception.rb +1 -1
  80. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +7 -8
  81. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +2 -2
  82. data/lib/rubocop/cop/lint/multiple_compare.rb +1 -1
  83. data/lib/rubocop/cop/lint/nested_method_definition.rb +3 -3
  84. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  85. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  86. data/lib/rubocop/cop/lint/number_conversion.rb +3 -3
  87. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  88. data/lib/rubocop/cop/lint/{unneeded_cop_disable_directive.rb → redundant_cop_disable_directive.rb} +24 -24
  89. data/lib/rubocop/cop/lint/{unneeded_cop_enable_directive.rb → redundant_cop_enable_directive.rb} +6 -8
  90. data/lib/rubocop/cop/lint/{unneeded_require_statement.rb → redundant_require_statement.rb} +2 -2
  91. data/lib/rubocop/cop/lint/{unneeded_splat_expansion.rb → redundant_splat_expansion.rb} +12 -7
  92. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
  93. data/lib/rubocop/cop/lint/redundant_with_object.rb +1 -1
  94. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +10 -11
  95. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  96. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +91 -0
  97. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +6 -6
  98. data/lib/rubocop/cop/lint/unified_integer.rb +1 -1
  99. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  100. data/lib/rubocop/cop/lint/unused_block_argument.rb +22 -6
  101. data/lib/rubocop/cop/lint/unused_method_argument.rb +23 -5
  102. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +1 -1
  103. data/lib/rubocop/cop/lint/uri_regexp.rb +2 -2
  104. data/lib/rubocop/cop/lint/useless_access_modifier.rb +6 -6
  105. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
  106. data/lib/rubocop/cop/lint/void.rb +7 -26
  107. data/lib/rubocop/cop/message_annotator.rb +16 -7
  108. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  109. data/lib/rubocop/cop/metrics/class_length.rb +1 -1
  110. data/lib/rubocop/cop/metrics/line_length.rb +7 -4
  111. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  112. data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
  113. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +23 -6
  114. data/lib/rubocop/cop/migration/department_name.rb +44 -0
  115. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  116. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  117. data/lib/rubocop/cop/mixin/documentation_comment.rb +0 -2
  118. data/lib/rubocop/cop/mixin/empty_parameter.rb +1 -1
  119. data/lib/rubocop/cop/mixin/enforce_superclass.rb +4 -4
  120. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  121. data/lib/rubocop/cop/mixin/interpolation.rb +27 -0
  122. data/lib/rubocop/cop/mixin/method_complexity.rb +3 -2
  123. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -3
  124. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +87 -0
  125. data/lib/rubocop/cop/mixin/safe_mode.rb +2 -0
  126. data/lib/rubocop/cop/mixin/statement_modifier.rb +5 -2
  127. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -5
  128. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -6
  129. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  130. data/lib/rubocop/cop/naming/constant_name.rb +2 -2
  131. data/lib/rubocop/cop/naming/file_name.rb +12 -5
  132. data/lib/rubocop/cop/naming/method_name.rb +12 -1
  133. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  134. data/lib/rubocop/cop/naming/variable_name.rb +1 -0
  135. data/lib/rubocop/cop/offense.rb +18 -7
  136. data/lib/rubocop/cop/registry.rb +22 -1
  137. data/lib/rubocop/cop/security/eval.rb +1 -1
  138. data/lib/rubocop/cop/security/json_load.rb +1 -1
  139. data/lib/rubocop/cop/security/marshal_load.rb +1 -1
  140. data/lib/rubocop/cop/security/open.rb +1 -1
  141. data/lib/rubocop/cop/security/yaml_load.rb +1 -1
  142. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -0
  143. data/lib/rubocop/cop/style/alias.rb +1 -1
  144. data/lib/rubocop/cop/style/attr.rb +2 -2
  145. data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
  146. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +35 -16
  147. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  148. data/lib/rubocop/cop/style/colon_method_call.rb +1 -1
  149. data/lib/rubocop/cop/style/comment_annotation.rb +5 -5
  150. data/lib/rubocop/cop/style/commented_keyword.rb +16 -30
  151. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -8
  152. data/lib/rubocop/cop/style/constant_visibility.rb +14 -3
  153. data/lib/rubocop/cop/style/copyright.rb +11 -7
  154. data/lib/rubocop/cop/style/date_time.rb +3 -3
  155. data/lib/rubocop/cop/style/dir.rb +1 -1
  156. data/lib/rubocop/cop/style/documentation_method.rb +45 -1
  157. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +55 -0
  158. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  159. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  160. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -2
  161. data/lib/rubocop/cop/style/empty_literal.rb +2 -2
  162. data/lib/rubocop/cop/style/empty_method.rb +5 -5
  163. data/lib/rubocop/cop/style/eval_with_location.rb +2 -2
  164. data/lib/rubocop/cop/style/even_odd.rb +1 -1
  165. data/lib/rubocop/cop/style/expand_path_arguments.rb +4 -4
  166. data/lib/rubocop/cop/style/float_division.rb +4 -4
  167. data/lib/rubocop/cop/style/format_string.rb +17 -14
  168. data/lib/rubocop/cop/style/format_string_token.rb +19 -68
  169. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +28 -33
  170. data/lib/rubocop/cop/style/guard_clause.rb +39 -10
  171. data/lib/rubocop/cop/style/hash_syntax.rb +4 -4
  172. data/lib/rubocop/cop/style/if_unless_modifier.rb +58 -15
  173. data/lib/rubocop/cop/style/infinite_loop.rb +5 -4
  174. data/lib/rubocop/cop/style/inverse_methods.rb +21 -15
  175. data/lib/rubocop/cop/style/lambda.rb +0 -2
  176. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -10
  177. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -25
  178. data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -9
  179. data/lib/rubocop/cop/style/min_max.rb +1 -1
  180. data/lib/rubocop/cop/style/mixin_usage.rb +12 -2
  181. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  182. data/lib/rubocop/cop/style/multiline_when_then.rb +55 -0
  183. data/lib/rubocop/cop/style/multiple_comparison.rb +1 -1
  184. data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
  185. data/lib/rubocop/cop/style/nested_modifier.rb +22 -4
  186. data/lib/rubocop/cop/style/non_nil_check.rb +21 -9
  187. data/lib/rubocop/cop/style/numeric_predicate.rb +3 -3
  188. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  189. data/lib/rubocop/cop/style/or_assignment.rb +8 -3
  190. data/lib/rubocop/cop/style/parentheses_around_condition.rb +15 -1
  191. data/lib/rubocop/cop/style/random_with_offset.rb +6 -6
  192. data/lib/rubocop/cop/style/{unneeded_capital_w.rb → redundant_capital_w.rb} +1 -1
  193. data/lib/rubocop/cop/style/{unneeded_condition.rb → redundant_condition.rb} +3 -3
  194. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -2
  195. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  196. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  197. data/lib/rubocop/cop/style/{unneeded_interpolation.rb → redundant_interpolation.rb} +1 -1
  198. data/lib/rubocop/cop/style/redundant_parentheses.rb +15 -6
  199. data/lib/rubocop/cop/style/{unneeded_percent_q.rb → redundant_percent_q.rb} +1 -1
  200. data/lib/rubocop/cop/style/redundant_return.rb +37 -21
  201. data/lib/rubocop/cop/style/redundant_self.rb +18 -1
  202. data/lib/rubocop/cop/style/{unneeded_sort.rb → redundant_sort.rb} +4 -4
  203. data/lib/rubocop/cop/style/redundant_sort_by.rb +1 -1
  204. data/lib/rubocop/cop/style/rescue_modifier.rb +24 -0
  205. data/lib/rubocop/cop/style/rescue_standard_error.rb +2 -2
  206. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  207. data/lib/rubocop/cop/style/safe_navigation.rb +24 -4
  208. data/lib/rubocop/cop/style/sample.rb +1 -1
  209. data/lib/rubocop/cop/style/semicolon.rb +13 -2
  210. data/lib/rubocop/cop/style/single_line_methods.rb +8 -1
  211. data/lib/rubocop/cop/style/special_global_vars.rb +5 -7
  212. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  213. data/lib/rubocop/cop/style/string_hash_keys.rb +2 -2
  214. data/lib/rubocop/cop/style/strip.rb +1 -1
  215. data/lib/rubocop/cop/style/struct_inheritance.rb +3 -3
  216. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  217. data/lib/rubocop/cop/style/ternary_parentheses.rb +20 -1
  218. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +4 -6
  219. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  220. data/lib/rubocop/cop/style/unpack_first.rb +1 -1
  221. data/lib/rubocop/cop/style/variable_interpolation.rb +6 -16
  222. data/lib/rubocop/cop/style/zero_length_predicate.rb +5 -5
  223. data/lib/rubocop/cop/team.rb +15 -14
  224. data/lib/rubocop/cop/util.rb +1 -1
  225. data/lib/rubocop/cop/utils/format_string.rb +120 -0
  226. data/lib/rubocop/cop/variable_force.rb +7 -5
  227. data/lib/rubocop/cop/variable_force/variable.rb +15 -2
  228. data/lib/rubocop/core_ext/string.rb +0 -24
  229. data/lib/rubocop/error.rb +23 -0
  230. data/lib/rubocop/formatter/clang_style_formatter.rb +8 -3
  231. data/lib/rubocop/formatter/emacs_style_formatter.rb +22 -9
  232. data/lib/rubocop/formatter/file_list_formatter.rb +1 -1
  233. data/lib/rubocop/formatter/formatter_set.rb +16 -15
  234. data/lib/rubocop/formatter/pacman_formatter.rb +80 -0
  235. data/lib/rubocop/formatter/simple_text_formatter.rb +16 -4
  236. data/lib/rubocop/formatter/tap_formatter.rb +17 -4
  237. data/lib/rubocop/magic_comment.rb +4 -0
  238. data/lib/rubocop/node_pattern.rb +5 -3
  239. data/lib/rubocop/options.rb +33 -21
  240. data/lib/rubocop/path_util.rb +1 -1
  241. data/lib/rubocop/processed_source.rb +4 -0
  242. data/lib/rubocop/result_cache.rb +1 -1
  243. data/lib/rubocop/rspec/expect_offense.rb +4 -1
  244. data/lib/rubocop/rspec/shared_contexts.rb +12 -0
  245. data/lib/rubocop/runner.rb +42 -31
  246. data/lib/rubocop/target_finder.rb +12 -4
  247. data/lib/rubocop/version.rb +1 -1
  248. metadata +21 -12
  249. data/lib/rubocop/cop/mixin/ignored_method_patterns.rb +0 -19
@@ -46,7 +46,7 @@ module RuboCop
46
46
 
47
47
  add_missing_namespaces(path, hash)
48
48
 
49
- resolver.resolve_inheritance_from_gems(hash, hash.delete('inherit_gem'))
49
+ resolver.resolve_inheritance_from_gems(hash)
50
50
  resolver.resolve_inheritance(path, hash, file, debug?)
51
51
 
52
52
  hash.delete('inherit_from')
@@ -199,6 +199,8 @@ module RuboCop
199
199
  raise(TypeError, "Malformed configuration in #{absolute_path}")
200
200
  end
201
201
 
202
+ check_cop_config_value(hash)
203
+
202
204
  hash
203
205
  end
204
206
 
@@ -220,6 +222,22 @@ module RuboCop
220
222
  end
221
223
  end
222
224
 
225
+ def check_cop_config_value(hash, parent = nil)
226
+ hash.each do |key, value|
227
+ check_cop_config_value(value, key) if value.is_a?(Hash)
228
+
229
+ next unless %w[Enabled
230
+ Safe
231
+ SafeAutoCorrect
232
+ AutoCorrect].include?(key) && value.is_a?(String)
233
+
234
+ abort(
235
+ "Property #{Rainbow(key).yellow} of cop #{Rainbow(parent).yellow}" \
236
+ " is supposed to be a boolean and #{Rainbow(value).yellow} is not."
237
+ )
238
+ end
239
+ end
240
+
223
241
  # Read the specified file, or exit with a friendly, concise message on
224
242
  # stderr. Care is taken to use the standard OS exit code for a "file not
225
243
  # found" error.
@@ -240,11 +258,11 @@ module RuboCop
240
258
  yaml_code,
241
259
  permitted_classes: [Regexp, Symbol],
242
260
  permitted_symbols: [],
243
- aliases: false,
261
+ aliases: true,
244
262
  filename: filename
245
263
  )
246
264
  else
247
- YAML.safe_load(yaml_code, [Regexp, Symbol], [], false, filename)
265
+ YAML.safe_load(yaml_code, [Regexp, Symbol], [], true, filename)
248
266
  end
249
267
  end
250
268
  end
@@ -35,7 +35,8 @@ module RuboCop
35
35
  end
36
36
  end
37
37
 
38
- def resolve_inheritance_from_gems(hash, gems)
38
+ def resolve_inheritance_from_gems(hash)
39
+ gems = hash.delete('inherit_gem')
39
40
  (gems || {}).each_pair do |gem_name, config_path|
40
41
  if gem_name == 'rubocop'
41
42
  raise ArgumentError,
@@ -73,7 +74,7 @@ module RuboCop
73
74
 
74
75
  opts = { inherit_mode: config['inherit_mode'] || {},
75
76
  unset_nil: unset_nil }
76
- Config.new(merge(default_configuration, config, opts), config_file)
77
+ Config.new(merge(default_configuration, config, **opts), config_file)
77
78
  end
78
79
 
79
80
  # Return a recursive merge of two hashes. That is, a normal hash merge,
@@ -92,7 +93,7 @@ module RuboCop
92
93
  elsif should_union?(base_hash, key, opts[:inherit_mode])
93
94
  result[key] = base_hash[key] | derived_hash[key]
94
95
  elsif opts[:debug]
95
- warn_on_duplicate_setting(base_hash, derived_hash, key, opts)
96
+ warn_on_duplicate_setting(base_hash, derived_hash, key, **opts)
96
97
  end
97
98
  end
98
99
  result
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # This class handles obsolete configuration.
5
+ class ConfigObsoletion
6
+ RENAMED_COPS = {
7
+ 'Lint/UnneededCopDisableDirective' => 'Lint/RedundantCopDisableDirective',
8
+ 'Lint/UnneededCopEnableDirective' => 'Lint/RedundantCopEnableDirective',
9
+ 'Lint/UnneededRequireStatement' => 'Lint/RedundantRequireStatement',
10
+ 'Lint/UnneededSplatExpansion' => 'Lint/RedundantSplatExpansion',
11
+ 'Style/SingleSpaceBeforeFirstArg' => 'Layout/SpaceBeforeFirstArg',
12
+ 'Style/MethodCallParentheses' => 'Style/MethodCallWithoutArgsParentheses',
13
+ 'Style/DeprecatedHashMethods' => 'Style/PreferredHashMethods',
14
+ 'Style/OpMethod' => 'Naming/BinaryOperatorParameterName',
15
+ 'Style/UnneededCapitalW' => 'Style/RedundantCapitalW',
16
+ 'Style/UnneededCondition' => 'Style/RedundantCondition',
17
+ 'Style/UnneededInterpolation' => 'Style/RedundantInterpolation',
18
+ 'Style/UnneededPercentQ' => 'Style/RedundantPercentQ',
19
+ 'Style/UnneededSort' => 'Style/RedundantSort',
20
+ 'Layout/FirstParameterIndentation' => 'Layout/IndentFirstArgument',
21
+ 'Layout/IndentArray' => 'Layout/IndentFirstArrayElement',
22
+ 'Layout/IndentHash' => 'Layout/IndentFirstHashElement'
23
+ }.map do |old_name, new_name|
24
+ [old_name, "The `#{old_name}` cop has been renamed to `#{new_name}`."]
25
+ end
26
+
27
+ MOVED_COPS = {
28
+ 'Security' => 'Lint/Eval',
29
+ 'Naming' => %w[Style/ClassAndModuleCamelCase Style/ConstantName
30
+ Style/FileName Style/MethodName Style/PredicateName
31
+ Style/VariableName Style/VariableNumber
32
+ Style/AccessorMethodName Style/AsciiIdentifiers],
33
+ 'Layout' => %w[Lint/BlockAlignment Lint/EndAlignment
34
+ Lint/DefEndAlignment],
35
+ 'Lint' => 'Style/FlipFlop'
36
+ }.map do |new_department, old_names|
37
+ Array(old_names).map do |old_name|
38
+ [old_name, "The `#{old_name}` cop has been moved to " \
39
+ "`#{new_department}/#{old_name.split('/').last}`."]
40
+ end
41
+ end
42
+
43
+ REMOVED_COPS = {
44
+ 'Rails/DefaultScope' => nil,
45
+ 'Layout/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
46
+ 'Layout/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
47
+ 'Style/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
48
+ 'Style/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
49
+ 'Style/TrailingComma' => 'Style/TrailingCommaInArguments, ' \
50
+ 'Style/TrailingCommaInArrayLiteral, and/or ' \
51
+ 'Style/TrailingCommaInHashLiteral',
52
+ 'Style/TrailingCommaInLiteral' => 'Style/TrailingCommaInArrayLiteral ' \
53
+ 'and/or ' \
54
+ 'Style/TrailingCommaInHashLiteral',
55
+ 'Lint/RescueWithoutErrorClass' => 'Style/RescueStandardError'
56
+ }.map do |old_name, other_cops|
57
+ if other_cops
58
+ more = ". Please use #{other_cops} instead".gsub(%r{[A-Z]\w+/\w+},
59
+ '`\&`')
60
+ end
61
+ [old_name, "The `#{old_name}` cop has been removed#{more}."]
62
+ end
63
+
64
+ REMOVED_COPS_WITH_REASON = {
65
+ 'Lint/InvalidCharacterLiteral' => 'it was never being actually triggered',
66
+ 'Lint/SpaceBeforeFirstArg' =>
67
+ 'it was a duplicate of `Layout/SpaceBeforeFirstArg`. Please use ' \
68
+ '`Layout/SpaceBeforeFirstArg` instead'
69
+ }.map do |cop_name, reason|
70
+ [cop_name, "The `#{cop_name}` cop has been removed since #{reason}."]
71
+ end
72
+
73
+ SPLIT_COPS = {
74
+ 'Style/MethodMissing' =>
75
+ 'The `Style/MethodMissing` cop has been split into ' \
76
+ '`Style/MethodMissingSuper` and `Style/MissingRespondToMissing`.'
77
+ }.to_a
78
+
79
+ OBSOLETE_COPS = Hash[*(RENAMED_COPS + MOVED_COPS + REMOVED_COPS +
80
+ REMOVED_COPS_WITH_REASON + SPLIT_COPS).flatten]
81
+
82
+ OBSOLETE_PARAMETERS = [
83
+ {
84
+ cops: %w[Layout/SpaceAroundOperators Style/SpaceAroundOperators],
85
+ parameters: 'MultiSpaceAllowedForOperators',
86
+ alternative: 'If your intention was to allow extra spaces for ' \
87
+ 'alignment, please use AllowForAlignment: true instead.'
88
+ },
89
+ {
90
+ cops: 'Style/Encoding',
91
+ parameters: %w[EnforcedStyle SupportedStyles
92
+ AutoCorrectEncodingComment],
93
+ alternative: 'Style/Encoding no longer supports styles. ' \
94
+ 'The "never" behavior is always assumed.'
95
+ },
96
+ {
97
+ cops: 'Style/IfUnlessModifier',
98
+ parameters: 'MaxLineLength',
99
+ alternative: '`Style/IfUnlessModifier: MaxLineLength` has been ' \
100
+ 'removed. Use `Metrics/LineLength: Max` instead'
101
+ },
102
+ {
103
+ cops: 'Style/WhileUntilModifier',
104
+ parameters: 'MaxLineLength',
105
+ alternative: '`Style/WhileUntilModifier: MaxLineLength` has been ' \
106
+ 'removed. Use `Metrics/LineLength: Max` instead'
107
+ },
108
+ {
109
+ cops: 'AllCops',
110
+ parameters: 'RunRailsCops',
111
+ alternative: "Use the following configuration instead:\n" \
112
+ "Rails:\n Enabled: true"
113
+ },
114
+ {
115
+ cops: 'Layout/CaseIndentation',
116
+ parameters: 'IndentWhenRelativeTo',
117
+ alternative: '`IndentWhenRelativeTo` has been renamed to ' \
118
+ '`EnforcedStyle`'
119
+ },
120
+ {
121
+ cops: %w[Lint/BlockAlignment Layout/BlockAlignment Lint/EndAlignment
122
+ Layout/EndAlignment Lint/DefEndAlignment
123
+ Layout/DefEndAlignment],
124
+ parameters: 'AlignWith',
125
+ alternative: '`AlignWith` has been renamed to `EnforcedStyleAlignWith`'
126
+ },
127
+ {
128
+ cops: 'Rails/UniqBeforePluck',
129
+ parameters: 'EnforcedMode',
130
+ alternative: '`EnforcedMode` has been renamed to `EnforcedStyle`'
131
+ },
132
+ {
133
+ cops: 'Style/MethodCallWithArgsParentheses',
134
+ parameters: 'IgnoredMethodPatterns',
135
+ alternative: '`IgnoredMethodPatterns` has been renamed to ' \
136
+ '`IgnoredPatterns`'
137
+ },
138
+ {
139
+ cops: %w[Performance/Count Performance/Detect],
140
+ parameters: 'SafeMode',
141
+ alternative: '`SafeMode` has been removed. ' \
142
+ 'Use `SafeAutoCorrect` instead.'
143
+ }
144
+ ].freeze
145
+
146
+ OBSOLETE_ENFORCED_STYLES = [
147
+ {
148
+ cop: 'Layout/IndentationConsistency',
149
+ parameter: 'EnforcedStyle',
150
+ enforced_style: 'rails',
151
+ alternative: '`EnforcedStyle: rails` has been renamed to ' \
152
+ '`EnforcedStyle: indented_internal_methods`'
153
+ }
154
+ ].freeze
155
+
156
+ def initialize(config)
157
+ @config = config
158
+ end
159
+
160
+ def reject_obsolete_cops_and_parameters
161
+ messages = [obsolete_cops, obsolete_parameters,
162
+ obsolete_enforced_style].flatten.compact
163
+ return if messages.empty?
164
+
165
+ raise ValidationError, messages.join("\n")
166
+ end
167
+
168
+ private
169
+
170
+ def obsolete_cops
171
+ OBSOLETE_COPS.map do |cop_name, message|
172
+ next unless @config.key?(cop_name) ||
173
+ @config.key?(Cop::Badge.parse(cop_name).cop_name)
174
+
175
+ message + "\n(obsolete configuration found in " \
176
+ "#{smart_loaded_path}, please update it)"
177
+ end
178
+ end
179
+
180
+ def obsolete_enforced_style
181
+ OBSOLETE_ENFORCED_STYLES.map do |params|
182
+ obsolete_enforced_style_message(params[:cop], params[:parameter],
183
+ params[:enforced_style],
184
+ params[:alternative])
185
+ end
186
+ end
187
+
188
+ def obsolete_enforced_style_message(cop, param, enforced_style, alternative)
189
+ style = @config[cop]&.detect { |key, _| key.start_with?(param) }
190
+
191
+ return unless style && style[1] == enforced_style
192
+
193
+ "obsolete `#{param}: #{enforced_style}` (for #{cop}) found in " \
194
+ "#{smart_loaded_path}\n#{alternative}"
195
+ end
196
+
197
+ def obsolete_parameters
198
+ OBSOLETE_PARAMETERS.map do |params|
199
+ obsolete_parameter_message(params[:cops], params[:parameters],
200
+ params[:alternative])
201
+ end
202
+ end
203
+
204
+ def obsolete_parameter_message(cops, parameters, alternative)
205
+ Array(cops).map do |cop|
206
+ obsolete_parameters = Array(parameters).select do |param|
207
+ @config[cop]&.key?(param)
208
+ end
209
+ next if obsolete_parameters.empty?
210
+
211
+ obsolete_parameters.map do |parameter|
212
+ "obsolete parameter #{parameter} (for #{cop}) found in " \
213
+ "#{smart_loaded_path}\n#{alternative}"
214
+ end
215
+ end
216
+ end
217
+
218
+ def smart_loaded_path
219
+ PathUtil.smart_path(@config.loaded_path)
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,248 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ module RuboCop
6
+ # Handles validation of configuration, for example cop names, parameter
7
+ # names, and Ruby versions.
8
+ class ConfigValidator
9
+ extend Forwardable
10
+
11
+ COMMON_PARAMS = %w[Exclude Include Severity inherit_mode
12
+ AutoCorrect StyleGuide Details].freeze
13
+ INTERNAL_PARAMS = %w[Description StyleGuide
14
+ VersionAdded VersionChanged VersionRemoved
15
+ Reference Safe SafeAutoCorrect].freeze
16
+
17
+ # 2.3 is the oldest officially supported Ruby version.
18
+ DEFAULT_RUBY_VERSION = 2.3
19
+ KNOWN_RUBIES = [2.3, 2.4, 2.5, 2.6, 2.7].freeze
20
+ OBSOLETE_RUBIES = {
21
+ 1.9 => '0.50', 2.0 => '0.50', 2.1 => '0.58', 2.2 => '0.69'
22
+ }.freeze
23
+ RUBY_VERSION_FILENAME = '.ruby-version'
24
+
25
+ def_delegators :@config,
26
+ :smart_loaded_path, :for_all_cops, :find_file_upwards,
27
+ :base_dir_for_path_parameters, :bundler_lock_file_path
28
+
29
+ def initialize(config)
30
+ @config = config
31
+ @config_obsoletion = ConfigObsoletion.new(config)
32
+ end
33
+
34
+ def validate
35
+ # Don't validate RuboCop's own files. Avoids infinite recursion.
36
+ return if @config.internal?
37
+
38
+ valid_cop_names, invalid_cop_names = @config.keys.partition do |key|
39
+ ConfigLoader.default_configuration.key?(key)
40
+ end
41
+
42
+ @config_obsoletion.reject_obsolete_cops_and_parameters
43
+
44
+ warn_about_unrecognized_cops(invalid_cop_names)
45
+ check_target_ruby
46
+ validate_parameter_names(valid_cop_names)
47
+ validate_enforced_styles(valid_cop_names)
48
+ validate_syntax_cop
49
+ reject_mutually_exclusive_defaults
50
+ end
51
+
52
+ def target_ruby_version
53
+ @target_ruby_version ||= begin
54
+ if for_all_cops['TargetRubyVersion']
55
+ @target_ruby_version_source = :rubocop_yml
56
+
57
+ for_all_cops['TargetRubyVersion'].to_f
58
+ elsif target_ruby_version_from_version_file
59
+ @target_ruby_version_source = :ruby_version_file
60
+
61
+ target_ruby_version_from_version_file
62
+ elsif target_ruby_version_from_bundler_lock_file
63
+ @target_ruby_version_source = :bundler_lock_file
64
+
65
+ target_ruby_version_from_bundler_lock_file
66
+ else
67
+ DEFAULT_RUBY_VERSION
68
+ end
69
+ end
70
+ end
71
+
72
+ def validate_section_presence(name)
73
+ return unless @config.key?(name) && @config[name].nil?
74
+
75
+ raise ValidationError,
76
+ "empty section #{name} found in #{smart_loaded_path}"
77
+ end
78
+
79
+ private
80
+
81
+ def check_target_ruby
82
+ return if KNOWN_RUBIES.include?(target_ruby_version)
83
+
84
+ msg = if OBSOLETE_RUBIES.include?(target_ruby_version)
85
+ "RuboCop found unsupported Ruby version #{target_ruby_version} " \
86
+ "in #{target_ruby_source}. #{target_ruby_version}-compatible " \
87
+ 'analysis was dropped after version ' \
88
+ "#{OBSOLETE_RUBIES[target_ruby_version]}."
89
+ else
90
+ 'RuboCop found unknown Ruby version ' \
91
+ "#{target_ruby_version.inspect} in #{target_ruby_source}."
92
+ end
93
+
94
+ msg += "\nSupported versions: #{KNOWN_RUBIES.join(', ')}"
95
+
96
+ raise ValidationError, msg
97
+ end
98
+
99
+ def warn_about_unrecognized_cops(invalid_cop_names)
100
+ invalid_cop_names.each do |name|
101
+ # There could be a custom cop with this name. If so, don't warn
102
+ next if Cop::Cop.registry.contains_cop_matching?([name])
103
+
104
+ # Special case for inherit_mode, which is a directive that we keep in
105
+ # the configuration (even though it's not a cop), because it's easier
106
+ # to do so than to pass the value around to various methods.
107
+ next if name == 'inherit_mode'
108
+
109
+ warn Rainbow("Warning: unrecognized cop #{name} found in " \
110
+ "#{smart_loaded_path}").yellow
111
+ end
112
+ end
113
+
114
+ def validate_syntax_cop
115
+ syntax_config = @config['Lint/Syntax']
116
+ default_config = ConfigLoader.default_configuration['Lint/Syntax']
117
+
118
+ return unless syntax_config &&
119
+ default_config.merge(syntax_config) != default_config
120
+
121
+ raise ValidationError,
122
+ "configuration for Syntax cop found in #{smart_loaded_path}\n" \
123
+ 'It\'s not possible to disable this cop.'
124
+ end
125
+
126
+ def validate_parameter_names(valid_cop_names)
127
+ valid_cop_names.each do |name|
128
+ validate_section_presence(name)
129
+ each_invalid_parameter(name) do |param, supported_params|
130
+ # FIXME: Remove .to_s, which works around a JRuby bug:
131
+ # https://github.com/jruby/jruby/issues/5935
132
+ warn Rainbow(<<~MESSAGE).yellow.to_s
133
+ Warning: #{name} does not support #{param} parameter.
134
+
135
+ Supported parameters are:
136
+
137
+ - #{supported_params.join("\n - ")}
138
+ MESSAGE
139
+ end
140
+ end
141
+ end
142
+
143
+ def each_invalid_parameter(cop_name)
144
+ default_config = ConfigLoader.default_configuration[cop_name]
145
+
146
+ @config[cop_name].each_key do |param|
147
+ next if COMMON_PARAMS.include?(param) || default_config.key?(param)
148
+
149
+ supported_params = default_config.keys - INTERNAL_PARAMS
150
+
151
+ yield param, supported_params
152
+ end
153
+ end
154
+
155
+ def validate_enforced_styles(valid_cop_names)
156
+ valid_cop_names.each do |name|
157
+ styles = @config[name].select { |key, _| key.start_with?('Enforced') }
158
+
159
+ styles.each do |style_name, style|
160
+ supported_key = RuboCop::Cop::Util.to_supported_styles(style_name)
161
+ valid = ConfigLoader.default_configuration[name][supported_key]
162
+
163
+ next unless valid
164
+ next if valid.include?(style)
165
+ next if validate_support_and_has_list(name, style, valid)
166
+
167
+ msg = "invalid #{style_name} '#{style}' for #{name} found in " \
168
+ "#{smart_loaded_path}\n" \
169
+ "Valid choices are: #{valid.join(', ')}"
170
+ raise ValidationError, msg
171
+ end
172
+ end
173
+ end
174
+
175
+ def validate_support_and_has_list(name, formats, valid)
176
+ ConfigLoader.default_configuration[name]['AllowMultipleStyles'] &&
177
+ formats.is_a?(Array) &&
178
+ formats.all? { |format| valid.include?(format) }
179
+ end
180
+
181
+ def target_ruby_source
182
+ case @target_ruby_version_source
183
+ when :ruby_version_file
184
+ "`#{RUBY_VERSION_FILENAME}`"
185
+ when :bundler_lock_file
186
+ "`#{bundler_lock_file_path}`"
187
+ when :rubocop_yml
188
+ "`TargetRubyVersion` parameter (in #{smart_loaded_path})"
189
+ end
190
+ end
191
+
192
+ def ruby_version_file
193
+ @ruby_version_file ||=
194
+ find_file_upwards(RUBY_VERSION_FILENAME, base_dir_for_path_parameters)
195
+ end
196
+
197
+ def target_ruby_version_from_version_file
198
+ file = ruby_version_file
199
+ return unless file && File.file?(file)
200
+
201
+ @target_ruby_version_from_version_file ||=
202
+ File.read(file).match(/\A(ruby-)?(?<version>\d+\.\d+)/) do |md|
203
+ md[:version].to_f
204
+ end
205
+ end
206
+
207
+ def target_ruby_version_from_bundler_lock_file
208
+ @target_ruby_version_from_bundler_lock_file ||=
209
+ read_ruby_version_from_bundler_lock_file
210
+ end
211
+
212
+ def read_ruby_version_from_bundler_lock_file
213
+ lock_file_path = bundler_lock_file_path
214
+ return nil unless lock_file_path
215
+
216
+ in_ruby_section = false
217
+ File.foreach(lock_file_path) do |line|
218
+ # If ruby is in Gemfile.lock or gems.lock, there should be two lines
219
+ # towards the bottom of the file that look like:
220
+ # RUBY VERSION
221
+ # ruby W.X.YpZ
222
+ # We ultimately want to match the "ruby W.X.Y.pZ" line, but there's
223
+ # extra logic to make sure we only start looking once we've seen the
224
+ # "RUBY VERSION" line.
225
+ in_ruby_section ||= line.match(/^\s*RUBY\s*VERSION\s*$/)
226
+ next unless in_ruby_section
227
+
228
+ # We currently only allow this feature to work with MRI ruby. If jruby
229
+ # (or something else) is used by the project, it's lock file will have a
230
+ # line that looks like:
231
+ # RUBY VERSION
232
+ # ruby W.X.YpZ (jruby x.x.x.x)
233
+ # The regex won't match in this situation.
234
+ result = line.match(/^\s*ruby\s+(\d+\.\d+)[p.\d]*\s*$/)
235
+ return result.captures.first.to_f if result
236
+ end
237
+ end
238
+
239
+ def reject_mutually_exclusive_defaults
240
+ disabled_by_default = for_all_cops['DisabledByDefault']
241
+ enabled_by_default = for_all_cops['EnabledByDefault']
242
+ return unless disabled_by_default && enabled_by_default
243
+
244
+ msg = 'Cops cannot be both enabled by default and disabled by default'
245
+ raise ValidationError, msg
246
+ end
247
+ end
248
+ end