rubocop 0.86.0 → 0.89.1

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 (377) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/rubocop-profile +32 -0
  4. data/config/default.yml +198 -25
  5. data/lib/rubocop.rb +30 -5
  6. data/lib/rubocop/cli.rb +2 -4
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +42 -7
  8. data/lib/rubocop/cli/command/base.rb +1 -0
  9. data/lib/rubocop/cli/command/execute_runner.rb +1 -1
  10. data/lib/rubocop/cli/command/show_cops.rb +3 -3
  11. data/lib/rubocop/cli/command/version.rb +2 -2
  12. data/lib/rubocop/comment_config.rb +5 -7
  13. data/lib/rubocop/config.rb +20 -3
  14. data/lib/rubocop/config_loader.rb +41 -69
  15. data/lib/rubocop/config_loader_resolver.rb +3 -3
  16. data/lib/rubocop/config_obsoletion.rb +6 -2
  17. data/lib/rubocop/config_store.rb +4 -0
  18. data/lib/rubocop/config_validator.rb +2 -4
  19. data/lib/rubocop/cop/autocorrect_logic.rb +14 -24
  20. data/lib/rubocop/cop/badge.rb +1 -1
  21. data/lib/rubocop/cop/base.rb +407 -0
  22. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +10 -20
  23. data/lib/rubocop/cop/commissioner.rb +47 -50
  24. data/lib/rubocop/cop/cop.rb +85 -236
  25. data/lib/rubocop/cop/corrector.rb +38 -115
  26. data/lib/rubocop/cop/correctors/line_break_corrector.rb +4 -4
  27. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +26 -0
  28. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  29. data/lib/rubocop/cop/correctors/punctuation_corrector.rb +1 -1
  30. data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +15 -18
  31. data/lib/rubocop/cop/force.rb +1 -0
  32. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +38 -12
  33. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  34. data/lib/rubocop/cop/generator.rb +1 -1
  35. data/lib/rubocop/cop/generator/configuration_injector.rb +2 -2
  36. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +4 -12
  37. data/lib/rubocop/cop/internal_affairs/node_destructuring.rb +1 -1
  38. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +11 -14
  39. data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +8 -8
  40. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +10 -7
  41. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +7 -8
  42. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -2
  43. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  44. data/lib/rubocop/cop/layout/case_indentation.rb +18 -19
  45. data/lib/rubocop/cop/layout/class_structure.rb +5 -44
  46. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  47. data/lib/rubocop/cop/layout/empty_lines.rb +0 -2
  48. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  49. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -8
  50. data/lib/rubocop/cop/layout/end_alignment.rb +3 -2
  51. data/lib/rubocop/cop/layout/extra_spacing.rb +22 -36
  52. data/lib/rubocop/cop/layout/first_argument_indentation.rb +4 -0
  53. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -1
  54. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -2
  55. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  56. data/lib/rubocop/cop/layout/indentation_style.rb +0 -2
  57. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  58. data/lib/rubocop/cop/layout/multiline_block_layout.rb +16 -6
  59. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -1
  60. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +0 -2
  61. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +22 -27
  62. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +33 -66
  63. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +3 -2
  64. data/lib/rubocop/cop/legacy/corrections_proxy.rb +49 -0
  65. data/lib/rubocop/cop/legacy/corrector.rb +29 -0
  66. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +7 -4
  67. data/lib/rubocop/cop/lint/ambiguous_operator.rb +15 -10
  68. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +11 -13
  69. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
  70. data/lib/rubocop/cop/lint/big_decimal_new.rb +10 -10
  71. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +50 -0
  72. data/lib/rubocop/cop/lint/boolean_symbol.rb +16 -11
  73. data/lib/rubocop/cop/lint/circular_argument_reference.rb +1 -1
  74. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  75. data/lib/rubocop/cop/lint/debugger.rb +7 -1
  76. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +9 -10
  77. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +21 -17
  78. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +8 -2
  79. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -1
  80. data/lib/rubocop/cop/lint/duplicate_elsif_condition.rb +39 -0
  81. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +1 -1
  82. data/lib/rubocop/cop/lint/duplicate_methods.rb +9 -6
  83. data/lib/rubocop/cop/lint/duplicate_rescue_exception.rb +60 -0
  84. data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
  85. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  86. data/lib/rubocop/cop/lint/empty_conditional_body.rb +67 -0
  87. data/lib/rubocop/cop/lint/empty_ensure.rb +5 -5
  88. data/lib/rubocop/cop/lint/empty_expression.rb +2 -2
  89. data/lib/rubocop/cop/lint/empty_interpolation.rb +5 -6
  90. data/lib/rubocop/cop/lint/empty_when.rb +2 -2
  91. data/lib/rubocop/cop/lint/ensure_return.rb +27 -29
  92. data/lib/rubocop/cop/lint/erb_new_arguments.rb +11 -10
  93. data/lib/rubocop/cop/lint/flip_flop.rb +1 -1
  94. data/lib/rubocop/cop/lint/float_comparison.rb +93 -0
  95. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  96. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +5 -4
  97. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +13 -14
  98. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +5 -4
  99. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +8 -8
  100. data/lib/rubocop/cop/lint/inherit_exception.rb +12 -7
  101. data/lib/rubocop/cop/lint/interpolation_check.rb +21 -5
  102. data/lib/rubocop/cop/lint/literal_as_condition.rb +14 -2
  103. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +7 -7
  104. data/lib/rubocop/cop/lint/loop.rb +23 -2
  105. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +6 -5
  106. data/lib/rubocop/cop/lint/missing_super.rb +99 -0
  107. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  108. data/lib/rubocop/cop/lint/multiple_comparison.rb +6 -9
  109. data/lib/rubocop/cop/lint/nested_method_definition.rb +15 -21
  110. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  111. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  112. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +84 -13
  113. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
  114. data/lib/rubocop/cop/lint/number_conversion.rb +6 -9
  115. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +11 -13
  116. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +90 -0
  117. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +12 -13
  118. data/lib/rubocop/cop/lint/percent_string_array.rb +13 -12
  119. data/lib/rubocop/cop/lint/percent_symbol_array.rb +13 -12
  120. data/lib/rubocop/cop/lint/raise_exception.rb +12 -10
  121. data/lib/rubocop/cop/lint/rand_one.rb +3 -3
  122. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +41 -40
  123. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +7 -11
  124. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -7
  125. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +15 -11
  126. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +6 -13
  127. data/lib/rubocop/cop/lint/redundant_with_index.rb +11 -14
  128. data/lib/rubocop/cop/lint/redundant_with_object.rb +11 -14
  129. data/lib/rubocop/cop/lint/regexp_as_condition.rb +4 -6
  130. data/lib/rubocop/cop/lint/require_parentheses.rb +2 -2
  131. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  132. data/lib/rubocop/cop/lint/rescue_type.rb +8 -8
  133. data/lib/rubocop/cop/lint/return_in_void_context.rb +2 -4
  134. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -6
  135. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +14 -10
  136. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +10 -2
  137. data/lib/rubocop/cop/lint/script_permission.rb +10 -7
  138. data/lib/rubocop/cop/lint/self_assignment.rb +78 -0
  139. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -11
  140. data/lib/rubocop/cop/lint/shadowed_argument.rb +3 -3
  141. data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -2
  142. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +3 -3
  143. data/lib/rubocop/cop/lint/struct_new_override.rb +1 -1
  144. data/lib/rubocop/cop/lint/suppressed_exception.rb +4 -7
  145. data/lib/rubocop/cop/lint/syntax.rb +11 -26
  146. data/lib/rubocop/cop/lint/to_json.rb +4 -6
  147. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +34 -0
  148. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +4 -4
  149. data/lib/rubocop/cop/lint/unified_integer.rb +4 -6
  150. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  151. data/lib/rubocop/cop/lint/unreachable_loop.rb +174 -0
  152. data/lib/rubocop/cop/lint/unused_block_argument.rb +8 -3
  153. data/lib/rubocop/cop/lint/unused_method_argument.rb +9 -4
  154. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +1 -1
  155. data/lib/rubocop/cop/lint/uri_regexp.rb +11 -47
  156. data/lib/rubocop/cop/lint/useless_access_modifier.rb +26 -16
  157. data/lib/rubocop/cop/lint/useless_assignment.rb +4 -4
  158. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +6 -15
  159. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -6
  160. data/lib/rubocop/cop/lint/void.rb +3 -7
  161. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  162. data/lib/rubocop/cop/metrics/block_length.rb +24 -2
  163. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
  164. data/lib/rubocop/cop/metrics/class_length.rb +26 -3
  165. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +2 -1
  166. data/lib/rubocop/cop/metrics/method_length.rb +25 -2
  167. data/lib/rubocop/cop/metrics/module_length.rb +26 -3
  168. data/lib/rubocop/cop/metrics/parameter_lists.rb +2 -6
  169. data/lib/rubocop/cop/metrics/perceived_complexity.rb +7 -8
  170. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +48 -5
  171. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +157 -0
  172. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +37 -0
  173. data/lib/rubocop/cop/migration/department_name.rb +14 -16
  174. data/lib/rubocop/cop/mixin/alignment.rb +2 -1
  175. data/lib/rubocop/cop/mixin/allowed_methods.rb +19 -0
  176. data/lib/rubocop/cop/mixin/array_min_size.rb +1 -1
  177. data/lib/rubocop/cop/mixin/auto_corrector.rb +12 -0
  178. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  179. data/lib/rubocop/cop/mixin/code_length.rb +26 -5
  180. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
  181. data/lib/rubocop/cop/mixin/enforce_superclass.rb +3 -1
  182. data/lib/rubocop/cop/mixin/hash_transform_method.rb +5 -11
  183. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -3
  184. data/lib/rubocop/cop/mixin/method_complexity.rb +10 -2
  185. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -2
  186. data/lib/rubocop/cop/mixin/nil_methods.rb +3 -5
  187. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +6 -1
  188. data/lib/rubocop/cop/mixin/percent_array.rb +2 -6
  189. data/lib/rubocop/cop/mixin/range_help.rb +18 -4
  190. data/lib/rubocop/cop/mixin/statement_modifier.rb +39 -10
  191. data/lib/rubocop/cop/mixin/surrounding_space.rb +4 -24
  192. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -4
  193. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +10 -15
  194. data/lib/rubocop/cop/mixin/unused_argument.rb +4 -6
  195. data/lib/rubocop/cop/mixin/visibility_help.rb +50 -0
  196. data/lib/rubocop/cop/naming/accessor_method_name.rb +4 -2
  197. data/lib/rubocop/cop/naming/ascii_identifiers.rb +29 -6
  198. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +3 -3
  199. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  200. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -2
  201. data/lib/rubocop/cop/naming/constant_name.rb +2 -2
  202. data/lib/rubocop/cop/naming/file_name.rb +3 -3
  203. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +2 -2
  204. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +2 -2
  205. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -2
  206. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  207. data/lib/rubocop/cop/naming/method_parameter_name.rb +2 -2
  208. data/lib/rubocop/cop/naming/predicate_name.rb +6 -10
  209. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -11
  210. data/lib/rubocop/cop/naming/variable_name.rb +1 -1
  211. data/lib/rubocop/cop/naming/variable_number.rb +1 -1
  212. data/lib/rubocop/cop/offense.rb +16 -2
  213. data/lib/rubocop/cop/registry.rb +3 -3
  214. data/lib/rubocop/cop/security/eval.rb +2 -2
  215. data/lib/rubocop/cop/security/json_load.rb +6 -8
  216. data/lib/rubocop/cop/security/marshal_load.rb +2 -4
  217. data/lib/rubocop/cop/security/open.rb +2 -2
  218. data/lib/rubocop/cop/security/yaml_load.rb +6 -6
  219. data/lib/rubocop/cop/style/access_modifier_declarations.rb +16 -9
  220. data/lib/rubocop/cop/style/accessor_grouping.rb +149 -0
  221. data/lib/rubocop/cop/style/alias.rb +41 -36
  222. data/lib/rubocop/cop/style/and_or.rb +9 -11
  223. data/lib/rubocop/cop/style/array_coercion.rb +63 -0
  224. data/lib/rubocop/cop/style/array_join.rb +6 -8
  225. data/lib/rubocop/cop/style/ascii_comments.rb +4 -4
  226. data/lib/rubocop/cop/style/attr.rb +11 -9
  227. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +5 -7
  228. data/lib/rubocop/cop/style/bare_percent_literals.rb +10 -12
  229. data/lib/rubocop/cop/style/begin_block.rb +2 -2
  230. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +141 -0
  231. data/lib/rubocop/cop/style/block_comments.rb +14 -18
  232. data/lib/rubocop/cop/style/block_delimiters.rb +23 -23
  233. data/lib/rubocop/cop/style/case_equality.rb +22 -3
  234. data/lib/rubocop/cop/style/case_like_if.rb +220 -0
  235. data/lib/rubocop/cop/style/class_and_module_children.rb +14 -11
  236. data/lib/rubocop/cop/style/class_check.rb +7 -9
  237. data/lib/rubocop/cop/style/class_methods.rb +7 -11
  238. data/lib/rubocop/cop/style/class_vars.rb +24 -7
  239. data/lib/rubocop/cop/style/collection_methods.rb +11 -17
  240. data/lib/rubocop/cop/style/colon_method_call.rb +8 -9
  241. data/lib/rubocop/cop/style/colon_method_definition.rb +6 -6
  242. data/lib/rubocop/cop/style/command_literal.rb +23 -24
  243. data/lib/rubocop/cop/style/comment_annotation.rb +15 -15
  244. data/lib/rubocop/cop/style/commented_keyword.rb +6 -3
  245. data/lib/rubocop/cop/style/conditional_assignment.rb +13 -4
  246. data/lib/rubocop/cop/style/constant_visibility.rb +3 -2
  247. data/lib/rubocop/cop/style/copyright.rb +12 -12
  248. data/lib/rubocop/cop/style/date_time.rb +2 -2
  249. data/lib/rubocop/cop/style/def_with_parentheses.rb +8 -10
  250. data/lib/rubocop/cop/style/dir.rb +9 -12
  251. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +7 -9
  252. data/lib/rubocop/cop/style/documentation.rb +6 -8
  253. data/lib/rubocop/cop/style/documentation_method.rb +1 -1
  254. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +12 -15
  255. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  256. data/lib/rubocop/cop/style/each_for_simple_loop.rb +5 -8
  257. data/lib/rubocop/cop/style/each_with_object.rb +16 -19
  258. data/lib/rubocop/cop/style/empty_case_condition.rb +19 -20
  259. data/lib/rubocop/cop/style/empty_else.rb +17 -19
  260. data/lib/rubocop/cop/style/empty_literal.rb +20 -21
  261. data/lib/rubocop/cop/style/empty_method.rb +10 -13
  262. data/lib/rubocop/cop/style/encoding.rb +5 -9
  263. data/lib/rubocop/cop/style/end_block.rb +4 -6
  264. data/lib/rubocop/cop/style/eval_with_location.rb +9 -7
  265. data/lib/rubocop/cop/style/even_odd.rb +7 -11
  266. data/lib/rubocop/cop/style/expand_path_arguments.rb +23 -22
  267. data/lib/rubocop/cop/style/explicit_block_argument.rb +102 -0
  268. data/lib/rubocop/cop/style/exponential_notation.rb +7 -9
  269. data/lib/rubocop/cop/style/float_division.rb +8 -11
  270. data/lib/rubocop/cop/style/for.rb +11 -15
  271. data/lib/rubocop/cop/style/format_string.rb +21 -19
  272. data/lib/rubocop/cop/style/format_string_token.rb +10 -12
  273. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +19 -41
  274. data/lib/rubocop/cop/style/global_std_stream.rb +65 -0
  275. data/lib/rubocop/cop/style/global_vars.rb +2 -2
  276. data/lib/rubocop/cop/style/guard_clause.rb +5 -6
  277. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +69 -0
  278. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -8
  279. data/lib/rubocop/cop/style/hash_like_case.rb +76 -0
  280. data/lib/rubocop/cop/style/hash_syntax.rb +4 -3
  281. data/lib/rubocop/cop/style/hash_transform_keys.rb +3 -2
  282. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -1
  283. data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -2
  284. data/lib/rubocop/cop/style/if_inside_else.rb +3 -3
  285. data/lib/rubocop/cop/style/if_unless_modifier.rb +18 -40
  286. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +11 -3
  287. data/lib/rubocop/cop/style/if_with_semicolon.rb +3 -6
  288. data/lib/rubocop/cop/style/implicit_runtime_error.rb +1 -1
  289. data/lib/rubocop/cop/style/infinite_loop.rb +24 -24
  290. data/lib/rubocop/cop/style/inline_comment.rb +3 -3
  291. data/lib/rubocop/cop/style/inverse_methods.rb +22 -32
  292. data/lib/rubocop/cop/style/lambda.rb +7 -12
  293. data/lib/rubocop/cop/style/lambda_call.rb +14 -13
  294. data/lib/rubocop/cop/style/line_end_concatenation.rb +19 -16
  295. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -1
  296. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -11
  297. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +4 -8
  298. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +8 -7
  299. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -2
  300. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -16
  301. data/lib/rubocop/cop/style/min_max.rb +8 -12
  302. data/lib/rubocop/cop/style/missing_else.rb +11 -21
  303. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +10 -3
  304. data/lib/rubocop/cop/style/mixin_grouping.rb +24 -27
  305. data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
  306. data/lib/rubocop/cop/style/module_function.rb +10 -13
  307. data/lib/rubocop/cop/style/multiline_block_chain.rb +10 -1
  308. data/lib/rubocop/cop/style/multiline_if_modifier.rb +3 -10
  309. data/lib/rubocop/cop/style/multiline_if_then.rb +4 -10
  310. data/lib/rubocop/cop/style/multiline_memoization.rb +14 -12
  311. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -2
  312. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +4 -6
  313. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -9
  314. data/lib/rubocop/cop/style/multiple_comparison.rb +1 -1
  315. data/lib/rubocop/cop/style/mutable_constant.rb +27 -24
  316. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +5 -6
  317. data/lib/rubocop/cop/style/numeric_predicate.rb +7 -4
  318. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +42 -0
  319. data/lib/rubocop/cop/style/parallel_assignment.rb +5 -5
  320. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  321. data/lib/rubocop/cop/style/proc.rb +1 -1
  322. data/lib/rubocop/cop/style/random_with_offset.rb +5 -10
  323. data/lib/rubocop/cop/style/redundant_assignment.rb +117 -0
  324. data/lib/rubocop/cop/style/redundant_condition.rb +15 -3
  325. data/lib/rubocop/cop/style/redundant_exception.rb +18 -10
  326. data/lib/rubocop/cop/style/redundant_fetch_block.rb +26 -7
  327. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +50 -0
  328. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  329. data/lib/rubocop/cop/style/redundant_parentheses.rb +7 -1
  330. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -1
  331. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +11 -11
  332. data/lib/rubocop/cop/style/redundant_sort.rb +26 -12
  333. data/lib/rubocop/cop/style/rescue_standard_error.rb +1 -1
  334. data/lib/rubocop/cop/style/safe_navigation.rb +4 -4
  335. data/lib/rubocop/cop/style/signal_exception.rb +3 -1
  336. data/lib/rubocop/cop/style/single_argument_dig.rb +54 -0
  337. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  338. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +3 -2
  339. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  340. data/lib/rubocop/cop/style/string_concatenation.rb +92 -0
  341. data/lib/rubocop/cop/style/struct_inheritance.rb +3 -3
  342. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  343. data/lib/rubocop/cop/style/symbol_proc.rb +2 -2
  344. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +9 -32
  345. data/lib/rubocop/cop/style/trivial_accessors.rb +8 -7
  346. data/lib/rubocop/cop/style/zero_length_predicate.rb +12 -8
  347. data/lib/rubocop/cop/team.rb +98 -82
  348. data/lib/rubocop/cop/tokens_util.rb +84 -0
  349. data/lib/rubocop/cop/util.rb +3 -13
  350. data/lib/rubocop/cop/utils/format_string.rb +1 -2
  351. data/lib/rubocop/cop/variable_force.rb +0 -2
  352. data/lib/rubocop/cop/variable_force/branch.rb +1 -0
  353. data/lib/rubocop/cop/variable_force/variable.rb +7 -5
  354. data/lib/rubocop/cops_documentation_generator.rb +282 -0
  355. data/lib/rubocop/error.rb +1 -0
  356. data/lib/rubocop/file_finder.rb +12 -12
  357. data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -2
  358. data/lib/rubocop/formatter/formatter_set.rb +1 -0
  359. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  360. data/lib/rubocop/name_similarity.rb +1 -3
  361. data/lib/rubocop/options.rb +18 -11
  362. data/lib/rubocop/path_util.rb +17 -17
  363. data/lib/rubocop/rake_task.rb +7 -9
  364. data/lib/rubocop/result_cache.rb +12 -8
  365. data/lib/rubocop/rspec/cop_helper.rb +4 -4
  366. data/lib/rubocop/rspec/expect_offense.rb +53 -22
  367. data/lib/rubocop/rspec/shared_contexts.rb +16 -17
  368. data/lib/rubocop/runner.rb +35 -34
  369. data/lib/rubocop/target_finder.rb +13 -10
  370. data/lib/rubocop/target_ruby.rb +1 -1
  371. data/lib/rubocop/version.rb +2 -2
  372. metadata +40 -11
  373. data/lib/rubocop/cop/lint/useless_comparison.rb +0 -28
  374. data/lib/rubocop/cop/mixin/classish_length.rb +0 -37
  375. data/lib/rubocop/cop/mixin/parser_diagnostic.rb +0 -37
  376. data/lib/rubocop/cop/mixin/too_many_lines.rb +0 -35
  377. data/lib/rubocop/cop/style/method_missing_super.rb +0 -34
@@ -18,25 +18,23 @@ module RuboCop
18
18
  XDG_CONFIG = 'config.yml'
19
19
  RUBOCOP_HOME = File.realpath(File.join(File.dirname(__FILE__), '..', '..'))
20
20
  DEFAULT_FILE = File.join(RUBOCOP_HOME, 'config', 'default.yml')
21
- AUTO_GENERATED_FILE = '.rubocop_todo.yml'
22
21
 
23
22
  class << self
24
23
  include FileFinder
25
24
 
26
- attr_accessor :debug, :auto_gen_config, :ignore_parent_exclusion,
27
- :options_config, :disable_pending_cops, :enable_pending_cops
28
- attr_writer :default_configuration
25
+ attr_accessor :debug, :ignore_parent_exclusion,
26
+ :disable_pending_cops, :enable_pending_cops
27
+ attr_writer :default_configuration, :project_root
29
28
 
30
29
  alias debug? debug
31
- alias auto_gen_config? auto_gen_config
32
30
  alias ignore_parent_exclusion? ignore_parent_exclusion
33
31
 
34
32
  def clear_options
35
- @debug = @auto_gen_config = @options_config = nil
33
+ @debug = nil
36
34
  FileFinder.root_level = nil
37
35
  end
38
36
 
39
- def load_file(file) # rubocop:disable Metrics/AbcSize
37
+ def load_file(file)
40
38
  path = File.absolute_path(file.is_a?(RemoteConfig) ? file.file : file)
41
39
 
42
40
  hash = load_yaml_configuration(path)
@@ -55,12 +53,27 @@ module RuboCop
55
53
  Config.create(hash, path)
56
54
  end
57
55
 
56
+ def load_yaml_configuration(absolute_path)
57
+ file_contents = read_file(absolute_path)
58
+ yaml_code = Dir.chdir(File.dirname(absolute_path)) do
59
+ ERB.new(file_contents).result
60
+ end
61
+ check_duplication(yaml_code, absolute_path)
62
+ hash = yaml_safe_load(yaml_code, absolute_path) || {}
63
+
64
+ puts "configuration from #{absolute_path}" if debug?
65
+
66
+ raise(TypeError, "Malformed configuration in #{absolute_path}") unless hash.is_a?(Hash)
67
+
68
+ hash
69
+ end
70
+
58
71
  def add_missing_namespaces(path, hash)
59
72
  # Using `hash.each_key` will cause the
60
73
  # `can't add a new key into hash during iteration` error
61
74
  hash_keys = hash.keys
62
75
  hash_keys.each do |key|
63
- q = Cop::Cop.qualified_cop_name(key, path)
76
+ q = Cop::Registry.qualified_cop_name(key, path)
64
77
  next if q == key
65
78
 
66
79
  hash[q] = hash.delete(key)
@@ -85,7 +98,7 @@ module RuboCop
85
98
  end
86
99
 
87
100
  def configuration_from_file(config_file)
88
- return ConfigLoader.default_configuration if config_file == DEFAULT_FILE
101
+ return default_configuration if config_file == DEFAULT_FILE
89
102
 
90
103
  config = load_file(config_file)
91
104
  if ignore_parent_exclusion?
@@ -105,15 +118,13 @@ module RuboCop
105
118
  end
106
119
 
107
120
  def add_excludes_from_files(config, config_file)
108
- found_files = find_files_upwards(DOTFILE, config_file) +
109
- [find_user_dotfile, find_user_xdg_config].compact
121
+ exclusion_file = find_last_file_upwards(DOTFILE, config_file, project_root)
110
122
 
111
- return if found_files.empty?
112
- return if PathUtil.relative_path(found_files.last) ==
113
- PathUtil.relative_path(config_file)
123
+ return unless exclusion_file
124
+ return if PathUtil.relative_path(exclusion_file) == PathUtil.relative_path(config_file)
114
125
 
115
126
  print 'AllCops/Exclude ' if debug?
116
- config.add_excludes_from_higher_level(load_file(found_files.last))
127
+ config.add_excludes_from_higher_level(load_file(exclusion_file))
117
128
  end
118
129
 
119
130
  def default_configuration
@@ -123,6 +134,12 @@ module RuboCop
123
134
  end
124
135
  end
125
136
 
137
+ # Returns the path rubocop inferred as the root of the project. No file
138
+ # searches will go past this directory.
139
+ def project_root
140
+ @project_root ||= find_project_root
141
+ end
142
+
126
143
  def warn_on_pending_cops(pending_cops)
127
144
  return if pending_cops.empty?
128
145
 
@@ -139,40 +156,23 @@ module RuboCop
139
156
  warn Rainbow('For more information: https://docs.rubocop.org/rubocop/versioning.html').yellow
140
157
  end
141
158
 
142
- # Merges the given configuration with the default one. If
143
- # AllCops:DisabledByDefault is true, it changes the Enabled params so
144
- # that only cops from user configuration are enabled.
145
- # If AllCops::EnabledByDefault is true, it changes the Enabled params
146
- # so that only cops explicitly disabled in user configuration are
147
- # disabled.
159
+ # Merges the given configuration with the default one.
148
160
  def merge_with_default(config, config_file, unset_nil: true)
149
161
  resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
150
162
  end
151
163
 
152
- def add_inheritance_from_auto_generated_file
153
- file_string = " #{AUTO_GENERATED_FILE}"
154
-
155
- config_file = options_config || DOTFILE
156
-
157
- if File.exist?(config_file)
158
- files = Array(load_yaml_configuration(config_file)['inherit_from'])
159
-
160
- return if files.include?(AUTO_GENERATED_FILE)
161
-
162
- files.unshift(AUTO_GENERATED_FILE)
163
- file_string = "\n - " + files.join("\n - ") if files.size > 1
164
- rubocop_yml_contents = existing_configuration(config_file)
165
- end
166
-
167
- write_config_file(config_file, file_string, rubocop_yml_contents)
164
+ private
168
165
 
169
- puts "Added inheritance from `#{AUTO_GENERATED_FILE}` in `#{DOTFILE}`."
166
+ def find_project_dotfile(target_dir)
167
+ find_file_upwards(DOTFILE, target_dir, project_root)
170
168
  end
171
169
 
172
- private
170
+ def find_project_root
171
+ pwd = Dir.pwd
172
+ gems_file = find_last_file_upwards('Gemfile', pwd) || find_last_file_upwards('gems.rb', pwd)
173
+ return unless gems_file
173
174
 
174
- def find_project_dotfile(target_dir)
175
- find_file_upwards(DOTFILE, target_dir)
175
+ File.dirname(gems_file)
176
176
  end
177
177
 
178
178
  def find_user_dotfile
@@ -196,38 +196,10 @@ module RuboCop
196
196
  path
197
197
  end
198
198
 
199
- def existing_configuration(config_file)
200
- IO.read(config_file, encoding: Encoding::UTF_8)
201
- .sub(/^inherit_from: *[^\n]+/, '')
202
- .sub(/^inherit_from: *(\n *- *[^\n]+)+/, '')
203
- end
204
-
205
- def write_config_file(file_name, file_string, rubocop_yml_contents)
206
- File.open(file_name, 'w') do |f|
207
- f.write "inherit_from:#{file_string}\n"
208
- f.write "\n#{rubocop_yml_contents}" if /\S/.match?(rubocop_yml_contents)
209
- end
210
- end
211
-
212
199
  def resolver
213
200
  @resolver ||= ConfigLoaderResolver.new
214
201
  end
215
202
 
216
- def load_yaml_configuration(absolute_path)
217
- file_contents = read_file(absolute_path)
218
- yaml_code = Dir.chdir(File.dirname(absolute_path)) do
219
- ERB.new(file_contents).result
220
- end
221
- check_duplication(yaml_code, absolute_path)
222
- hash = yaml_safe_load(yaml_code, absolute_path) || {}
223
-
224
- puts "configuration from #{absolute_path}" if debug?
225
-
226
- raise(TypeError, "Malformed configuration in #{absolute_path}") unless hash.is_a?(Hash)
227
-
228
- hash
229
- end
230
-
231
203
  def check_duplication(yaml_code, absolute_path)
232
204
  smart_path = PathUtil.smart_path(absolute_path)
233
205
  YAMLDuplicationChecker.check(yaml_code, absolute_path) do |key1, key2|
@@ -201,7 +201,7 @@ module RuboCop
201
201
  next unless dept_params['Enabled']
202
202
 
203
203
  new_default_configuration.each do |cop, params|
204
- next unless cop.start_with?(dept + '/')
204
+ next unless cop.start_with?("#{dept}/")
205
205
 
206
206
  # Retain original default configuration for cops in the department.
207
207
  params['Enabled'] = ConfigLoader.default_configuration[cop]['Enabled']
@@ -213,8 +213,8 @@ module RuboCop
213
213
  end
214
214
  end
215
215
 
216
- def transform(config)
217
- config.transform_values { |params| yield(params) }
216
+ def transform(config, &block)
217
+ config.transform_values(&block)
218
218
  end
219
219
 
220
220
  def gem_config_path(gem_name, relative_config_path)
@@ -63,7 +63,6 @@ module RuboCop
63
63
  'Layout/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
64
64
  'Layout/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
65
65
  'Lint/RescueWithoutErrorClass' => 'Style/RescueStandardError',
66
- 'Rails/DefaultScope' => nil,
67
66
  'Style/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
68
67
  'Style/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
69
68
  'Style/TrailingComma' => 'Style/TrailingCommaInArguments, ' \
@@ -85,7 +84,12 @@ module RuboCop
85
84
  'Lint/InvalidCharacterLiteral' => 'it was never being actually triggered',
86
85
  'Lint/SpaceBeforeFirstArg' =>
87
86
  'it was a duplicate of `Layout/SpaceBeforeFirstArg`. Please use ' \
88
- '`Layout/SpaceBeforeFirstArg` instead'
87
+ '`Layout/SpaceBeforeFirstArg` instead',
88
+ 'Style/MethodMissingSuper' => 'it has been superseded by `Lint/MissingSuper`. Please use ' \
89
+ '`Lint/MissingSuper` instead',
90
+ 'Lint/UselessComparison' => 'it has been superseded by '\
91
+ '`Lint/BinaryOperatorWithIdenticalOperands`. Please use '\
92
+ '`Lint/BinaryOperatorWithIdenticalOperands` instead'
89
93
  }.map do |cop_name, reason|
90
94
  [cop_name, "The `#{cop_name}` cop has been removed since #{reason}."]
91
95
  end
@@ -33,6 +33,10 @@ module RuboCop
33
33
  for_dir(File.dirname(file))
34
34
  end
35
35
 
36
+ def for_pwd
37
+ for_dir(Dir.pwd)
38
+ end
39
+
36
40
  # If type (file/dir) is known beforehand,
37
41
  # prefer using #for_file or #for_dir for improved performance
38
42
  def for(file_or_dir)
@@ -23,7 +23,6 @@ module RuboCop
23
23
  @target_ruby = TargetRuby.new(config)
24
24
  end
25
25
 
26
- # rubocop:disable Metrics/AbcSize
27
26
  def validate
28
27
  check_cop_config_value(@config)
29
28
  reject_conflicting_safe_settings
@@ -45,7 +44,6 @@ module RuboCop
45
44
  validate_syntax_cop
46
45
  reject_mutually_exclusive_defaults
47
46
  end
48
- # rubocop:enable Metrics/AbcSize
49
47
 
50
48
  def target_ruby_version
51
49
  target_ruby.version
@@ -86,7 +84,7 @@ module RuboCop
86
84
  unknown_cops = []
87
85
  invalid_cop_names.each do |name|
88
86
  # There could be a custom cop with this name. If so, don't warn
89
- next if Cop::Cop.registry.contains_cop_matching?([name])
87
+ next if Cop::Registry.global.contains_cop_matching?([name])
90
88
 
91
89
  # Special case for inherit_mode, which is a directive that we keep in
92
90
  # the configuration (even though it's not a cop), because it's easier
@@ -150,7 +148,7 @@ module RuboCop
150
148
  end
151
149
  end
152
150
 
153
- def validate_enforced_styles(valid_cop_names)
151
+ def validate_enforced_styles(valid_cop_names) # rubocop:todo Metrics/AbcSize
154
152
  valid_cop_names.each do |name|
155
153
  styles = @config[name].select { |key, _| key.start_with?('Enforced') }
156
154
 
@@ -13,11 +13,7 @@ module RuboCop
13
13
  end
14
14
 
15
15
  def correctable?
16
- support_autocorrect? || disable_uncorrectable?
17
- end
18
-
19
- def support_autocorrect?
20
- respond_to?(:autocorrect)
16
+ self.class.support_autocorrect? || disable_uncorrectable?
21
17
  end
22
18
 
23
19
  def disable_uncorrectable?
@@ -40,8 +36,9 @@ module RuboCop
40
36
  true
41
37
  end
42
38
 
43
- def disable_offense(node)
44
- range = node.location.expression
39
+ private
40
+
41
+ def disable_offense(range)
45
42
  eol_comment = " # rubocop:todo #{cop_name}"
46
43
  needed_line_length = (range.source_line + eol_comment).length
47
44
  if needed_line_length <= max_line_length
@@ -52,8 +49,6 @@ module RuboCop
52
49
  end
53
50
  end
54
51
 
55
- private
56
-
57
52
  def range_of_first_line(range)
58
53
  begin_of_first_line = range.begin_pos - range.column
59
54
  end_of_first_line = begin_of_first_line + range.source_line.length
@@ -78,27 +73,22 @@ module RuboCop
78
73
  end
79
74
 
80
75
  def max_line_length
81
- config.for_cop('Layout/LineLength')['Max'] || 80
76
+ config.for_cop('Layout/LineLength')['Max'] || 120
82
77
  end
83
78
 
84
79
  def disable_offense_at_end_of_line(range, eol_comment)
85
- ->(corrector) { corrector.insert_after(range, eol_comment) }
80
+ Corrector.new(range).insert_after(range, eol_comment)
86
81
  end
87
82
 
88
83
  def disable_offense_before_and_after(range_by_lines)
89
- lambda do |corrector|
90
- range_with_newline = range_by_lines.resize(range_by_lines.size + 1)
91
- leading_whitespace = range_by_lines.source_line[/^\s*/]
92
-
93
- corrector.insert_before(
94
- range_with_newline,
95
- "#{leading_whitespace}# rubocop:todo #{cop_name}\n"
96
- )
97
- corrector.insert_after(
98
- range_with_newline,
99
- "#{leading_whitespace}# rubocop:enable #{cop_name}\n"
100
- )
101
- end
84
+ range_with_newline = range_by_lines.resize(range_by_lines.size + 1)
85
+ leading_whitespace = range_by_lines.source_line[/^\s*/]
86
+
87
+ Corrector.new(range_by_lines).wrap(
88
+ range_with_newline,
89
+ "#{leading_whitespace}# rubocop:todo #{cop_name}\n",
90
+ "#{leading_whitespace}# rubocop:enable #{cop_name}\n"
91
+ )
102
92
  end
103
93
  end
104
94
  end
@@ -58,7 +58,7 @@ module RuboCop
58
58
  end
59
59
 
60
60
  def to_s
61
- qualified? ? "#{department}/#{cop_name}" : cop_name
61
+ @to_s ||= qualified? ? "#{department}/#{cop_name}" : cop_name
62
62
  end
63
63
 
64
64
  def qualified?
@@ -0,0 +1,407 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # A scaffold for concrete cops.
6
+ #
7
+ # The Cop::Base class is meant to be extended.
8
+ #
9
+ # Cops track offenses and can autocorrect them on the fly.
10
+ #
11
+ # A commissioner object is responsible for traversing the AST and invoking
12
+ # the specific callbacks on each cop.
13
+ #
14
+ # First the callback `on_new_investigation` is called;
15
+ # if a cop needs to do its own processing of the AST or depends on
16
+ # something else.
17
+ #
18
+ # Then callbacks like `on_def`, `on_send` (see AST::Traversal) are called
19
+ # with their respective nodes.
20
+ #
21
+ # Finally the callback `on_investigation_end` is called.
22
+ #
23
+ # Within these callbacks, cops are meant to call `add_offense` or
24
+ # `add_global_offense`. Use the `processed_source` method to
25
+ # get the currently processed source being investigated.
26
+ #
27
+ # In case of invalid syntax / unparseable content,
28
+ # the callback `on_other_file` is called instead of all the other
29
+ # `on_...` callbacks.
30
+ #
31
+ # Private methods are not meant for custom cops consumption,
32
+ # nor are any instance variables.
33
+ #
34
+ class Base # rubocop:disable Metrics/ClassLength
35
+ extend RuboCop::AST::Sexp
36
+ extend NodePattern::Macros
37
+ include RuboCop::AST::Sexp
38
+ include Util
39
+ include IgnoredNode
40
+ include AutocorrectLogic
41
+
42
+ attr_reader :config, :processed_source
43
+
44
+ # Reports of an investigation.
45
+ # Immutable
46
+ # Consider creation API private
47
+ InvestigationReport = Struct.new(:cop, :processed_source, :offenses, :corrector)
48
+
49
+ # List of cops that should not try to autocorrect at the same
50
+ # time as this cop
51
+ #
52
+ # @return [Array<RuboCop::Cop::Cop>]
53
+ #
54
+ # @api public
55
+ def self.autocorrect_incompatible_with
56
+ []
57
+ end
58
+
59
+ def initialize(config = nil, options = nil)
60
+ @config = config || Config.new
61
+ @options = options || { debug: false }
62
+ reset_investigation
63
+ end
64
+
65
+ # Called before all on_... have been called
66
+ # When refining this method, always call `super`
67
+ def on_new_investigation
68
+ # Typically do nothing here
69
+ end
70
+
71
+ # Called after all on_... have been called
72
+ # When refining this method, always call `super`
73
+ def on_investigation_end
74
+ # Typically do nothing here
75
+ end
76
+
77
+ # Called instead of all on_... callbacks for unrecognized files / syntax errors
78
+ # When refining this method, always call `super`
79
+ def on_other_file
80
+ # Typically do nothing here
81
+ end
82
+
83
+ # Override and return the Force class(es) you need to join
84
+ def self.joining_forces; end
85
+
86
+ # Gets called if no message is specified when calling `add_offense` or
87
+ # `add_global_offense`
88
+ # Cops are discouraged to override this; instead pass your message directly
89
+ def message(_range = nil)
90
+ self.class::MSG
91
+ end
92
+
93
+ # Adds an offense that has no particular location.
94
+ # No correction can be applied to global offenses
95
+ def add_global_offense(message = nil, severity: nil)
96
+ severity = find_severity(nil, severity)
97
+ message = find_message(nil, message)
98
+ @current_offenses <<
99
+ Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported)
100
+ end
101
+
102
+ # Adds an offense on the specified range (or node with an expression)
103
+ # Unless that offense is disabled for this range, a corrector will be yielded
104
+ # to provide the cop the opportunity to autocorrect the offense.
105
+ # If message is not specified, the method `message` will be called.
106
+ def add_offense(node_or_range, message: nil, severity: nil, &block)
107
+ range = range_from_node_or_range(node_or_range)
108
+ return unless current_offense_locations.add?(range)
109
+
110
+ range_to_pass = callback_argument(range)
111
+
112
+ severity = find_severity(range_to_pass, severity)
113
+ message = find_message(range_to_pass, message)
114
+
115
+ status, corrector = enabled_line?(range.line) ? correct(range, &block) : :disabled
116
+
117
+ @current_offenses << Offense.new(severity, range, message, name, status, corrector)
118
+ end
119
+
120
+ # This method should be overridden when a cop's behavior depends
121
+ # on state that lives outside of these locations:
122
+ #
123
+ # (1) the file under inspection
124
+ # (2) the cop's source code
125
+ # (3) the config (eg a .rubocop.yml file)
126
+ #
127
+ # For example, some cops may want to look at other parts of
128
+ # the codebase being inspected to find violations. A cop may
129
+ # use the presence or absence of file `foo.rb` to determine
130
+ # whether a certain violation exists in `bar.rb`.
131
+ #
132
+ # Overriding this method allows the cop to indicate to RuboCop's
133
+ # ResultCache system when those external dependencies change,
134
+ # ie when the ResultCache should be invalidated.
135
+ def external_dependency_checksum
136
+ nil
137
+ end
138
+
139
+ def self.inherited(subclass)
140
+ super
141
+ Registry.global.enlist(subclass)
142
+ end
143
+
144
+ # Call for abstract Cop classes
145
+ def self.exclude_from_registry
146
+ Registry.global.dismiss(self)
147
+ end
148
+
149
+ # Returns if class supports auto_correct.
150
+ # It is recommended to extend AutoCorrector instead of overriding
151
+ def self.support_autocorrect?
152
+ false
153
+ end
154
+
155
+ ### Naming
156
+
157
+ def self.badge
158
+ @badge ||= Badge.for(name)
159
+ end
160
+
161
+ def self.cop_name
162
+ badge.to_s
163
+ end
164
+
165
+ def self.department
166
+ badge.department
167
+ end
168
+
169
+ def self.lint?
170
+ department == :Lint
171
+ end
172
+
173
+ # Returns true if the cop name or the cop namespace matches any of the
174
+ # given names.
175
+ def self.match?(given_names)
176
+ return false unless given_names
177
+
178
+ given_names.include?(cop_name) ||
179
+ given_names.include?(department.to_s)
180
+ end
181
+
182
+ def cop_name
183
+ @cop_name ||= self.class.cop_name
184
+ end
185
+
186
+ alias name cop_name
187
+
188
+ ### Configuration Helpers
189
+
190
+ def cop_config
191
+ # Use department configuration as basis, but let individual cop
192
+ # configuration override.
193
+ @cop_config ||= @config.for_badge(self.class.badge)
194
+ end
195
+
196
+ def config_to_allow_offenses
197
+ Formatter::DisabledConfigFormatter
198
+ .config_to_allow_offenses[cop_name] ||= {}
199
+ end
200
+
201
+ def config_to_allow_offenses=(hash)
202
+ Formatter::DisabledConfigFormatter.config_to_allow_offenses[cop_name] =
203
+ hash
204
+ end
205
+
206
+ def target_ruby_version
207
+ @config.target_ruby_version
208
+ end
209
+
210
+ def target_rails_version
211
+ @config.target_rails_version
212
+ end
213
+
214
+ def relevant_file?(file)
215
+ file == RuboCop::AST::ProcessedSource::STRING_SOURCE_NAME ||
216
+ file_name_matches_any?(file, 'Include', true) &&
217
+ !file_name_matches_any?(file, 'Exclude', false)
218
+ end
219
+
220
+ def excluded_file?(file)
221
+ !relevant_file?(file)
222
+ end
223
+
224
+ ### Persistence
225
+
226
+ # Override if your cop should be called repeatedly for multiple investigations
227
+ # Between calls to `on_new_investigation` and `on_investigation_end`,
228
+ # the result of `processed_source` will remain constant.
229
+ # You should invalidate any caches that depend on the current `processed_source`
230
+ # in the `on_new_investigation` callback.
231
+ # If your cop does autocorrections, be aware that your instance may be called
232
+ # multiple times with the same `processed_source.path` but different content.
233
+ def self.support_multiple_source?
234
+ false
235
+ end
236
+
237
+ # @api private
238
+ # Called between investigations
239
+ def ready
240
+ return self if self.class.support_multiple_source?
241
+
242
+ self.class.new(@config, @options)
243
+ end
244
+
245
+ ### Reserved for Cop::Cop
246
+
247
+ # @deprecated Make potential errors with previous API more obvious
248
+ def offenses
249
+ raise 'The offenses are not directly available; ' \
250
+ 'they are returned as the result of the investigation'
251
+ end
252
+
253
+ private
254
+
255
+ ### Reserved for Cop::Cop
256
+
257
+ def callback_argument(range)
258
+ range
259
+ end
260
+
261
+ def apply_correction(corrector)
262
+ @current_corrector&.merge!(corrector) if corrector
263
+ end
264
+
265
+ def correction_strategy
266
+ return :unsupported unless correctable?
267
+ return :uncorrected unless autocorrect?
268
+
269
+ :attempt_correction
270
+ end
271
+
272
+ ### Reserved for Commissioner:
273
+
274
+ def current_offense_locations
275
+ @current_offense_locations ||= Set.new
276
+ end
277
+
278
+ def currently_disabled_lines
279
+ @currently_disabled_lines ||= Set.new
280
+ end
281
+
282
+ # Called before any investigation
283
+ def begin_investigation(processed_source)
284
+ @current_offenses = []
285
+ @current_offense_locations = nil
286
+ @currently_disabled_lines = nil
287
+ @processed_source = processed_source
288
+ @current_corrector = Corrector.new(@processed_source) if @processed_source.valid_syntax?
289
+ end
290
+
291
+ # Called to complete an investigation
292
+ def complete_investigation
293
+ InvestigationReport.new(self, processed_source, @current_offenses, @current_corrector)
294
+ ensure
295
+ reset_investigation
296
+ end
297
+
298
+ ### Actually private methods
299
+
300
+ def reset_investigation
301
+ @currently_disabled_lines = @current_offenses = @processed_source = @current_corrector = nil
302
+ end
303
+
304
+ # @return [Symbol, Corrector] offense status
305
+ def correct(range)
306
+ status = correction_strategy
307
+
308
+ if block_given?
309
+ corrector = Corrector.new(self)
310
+ yield corrector
311
+ if !corrector.empty? && !self.class.support_autocorrect?
312
+ raise "The Cop #{name} must `extend AutoCorrector` to be able to autocorrect"
313
+ end
314
+ end
315
+
316
+ status = attempt_correction(range, corrector) if status == :attempt_correction
317
+
318
+ [status, corrector]
319
+ end
320
+
321
+ # @return [Symbol] offense status
322
+ def attempt_correction(range, corrector)
323
+ if corrector && !corrector.empty?
324
+ status = :corrected
325
+ elsif disable_uncorrectable?
326
+ corrector = disable_uncorrectable(range)
327
+ status = :corrected_with_todo
328
+ else
329
+ return :uncorrected
330
+ end
331
+
332
+ apply_correction(corrector) if corrector
333
+ status
334
+ end
335
+
336
+ def disable_uncorrectable(range)
337
+ line = range.line
338
+ return unless currently_disabled_lines.add?(line)
339
+
340
+ disable_offense(range)
341
+ end
342
+
343
+ def range_from_node_or_range(node_or_range)
344
+ if node_or_range.respond_to?(:loc)
345
+ node_or_range.loc.expression
346
+ elsif node_or_range.is_a?(::Parser::Source::Range)
347
+ node_or_range
348
+ else
349
+ extra = ' (call `add_global_offense`)' if node_or_range.nil?
350
+ raise "Expected a Source::Range, got #{node_or_range.inspect}#{extra}"
351
+ end
352
+ end
353
+
354
+ def find_message(range, message)
355
+ annotate(message || message(range))
356
+ end
357
+
358
+ def annotate(message)
359
+ RuboCop::Cop::MessageAnnotator.new(
360
+ config, cop_name, cop_config, @options
361
+ ).annotate(message)
362
+ end
363
+
364
+ def file_name_matches_any?(file, parameter, default_result)
365
+ patterns = cop_config[parameter]
366
+ return default_result unless patterns
367
+
368
+ path = nil
369
+ patterns.any? do |pattern|
370
+ # Try to match the absolute path, as Exclude properties are absolute.
371
+ next true if match_path?(pattern, file)
372
+
373
+ # Try with relative path.
374
+ path ||= config.path_relative_to_config(file)
375
+ match_path?(pattern, path)
376
+ end
377
+ end
378
+
379
+ def enabled_line?(line_number)
380
+ return true if @options[:ignore_disable_comments] || !@processed_source
381
+
382
+ @processed_source.comment_config.cop_enabled_at_line?(self, line_number)
383
+ end
384
+
385
+ def find_severity(_range, severity)
386
+ custom_severity || severity || default_severity
387
+ end
388
+
389
+ def default_severity
390
+ self.class.lint? ? :warning : :convention
391
+ end
392
+
393
+ def custom_severity
394
+ severity = cop_config['Severity']
395
+ return unless severity
396
+
397
+ if Severity::NAMES.include?(severity.to_sym)
398
+ severity.to_sym
399
+ else
400
+ message = "Warning: Invalid severity '#{severity}'. " \
401
+ "Valid severities are #{Severity::NAMES.join(', ')}."
402
+ warn(Rainbow(message).red)
403
+ end
404
+ end
405
+ end
406
+ end
407
+ end