rubocop 0.52.1 → 0.53.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (292) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +118 -46
  5. data/config/disabled.yml +8 -8
  6. data/config/enabled.yml +84 -28
  7. data/lib/rubocop.rb +28 -8
  8. data/lib/rubocop/ast/builder.rb +35 -37
  9. data/lib/rubocop/ast/node.rb +16 -1
  10. data/lib/rubocop/ast/node/and_node.rb +0 -8
  11. data/lib/rubocop/ast/node/block_node.rb +1 -9
  12. data/lib/rubocop/ast/node/case_node.rb +0 -8
  13. data/lib/rubocop/ast/node/ensure_node.rb +0 -8
  14. data/lib/rubocop/ast/node/for_node.rb +0 -8
  15. data/lib/rubocop/ast/node/or_node.rb +0 -8
  16. data/lib/rubocop/ast/node/pair_node.rb +0 -8
  17. data/lib/rubocop/ast/node/resbody_node.rb +0 -8
  18. data/lib/rubocop/ast/node/send_node.rb +0 -8
  19. data/lib/rubocop/ast/node/symbol_node.rb +0 -8
  20. data/lib/rubocop/ast/node/until_node.rb +0 -8
  21. data/lib/rubocop/ast/node/when_node.rb +0 -8
  22. data/lib/rubocop/ast/node/while_node.rb +0 -8
  23. data/lib/rubocop/cli.rb +17 -7
  24. data/lib/rubocop/comment_config.rb +24 -3
  25. data/lib/rubocop/config.rb +75 -6
  26. data/lib/rubocop/config_loader.rb +18 -28
  27. data/lib/rubocop/config_loader_resolver.rb +61 -9
  28. data/lib/rubocop/cop/bundler/duplicated_gem.rb +3 -1
  29. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +4 -2
  30. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  31. data/lib/rubocop/cop/commissioner.rb +2 -2
  32. data/lib/rubocop/cop/cop.rb +4 -0
  33. data/lib/rubocop/cop/corrector.rb +11 -1
  34. data/lib/rubocop/cop/correctors/alignment_corrector.rb +3 -6
  35. data/lib/rubocop/cop/correctors/line_break_corrector.rb +59 -0
  36. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -1
  37. data/lib/rubocop/cop/correctors/space_corrector.rb +13 -0
  38. data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +1 -1
  39. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +3 -1
  40. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  41. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -5
  42. data/lib/rubocop/cop/generator.rb +29 -8
  43. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +2 -0
  44. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +2 -0
  45. data/lib/rubocop/cop/layout/align_hash.rb +106 -37
  46. data/lib/rubocop/cop/{lint → layout}/block_alignment.rb +8 -5
  47. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -17
  48. data/lib/rubocop/cop/layout/case_indentation.rb +1 -0
  49. data/lib/rubocop/cop/layout/class_structure.rb +6 -7
  50. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  51. data/lib/rubocop/cop/{lint → layout}/condition_position.rb +3 -3
  52. data/lib/rubocop/cop/{lint → layout}/def_end_alignment.rb +2 -1
  53. data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
  54. data/lib/rubocop/cop/layout/empty_comment.rb +140 -0
  55. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +2 -0
  56. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -0
  57. data/lib/rubocop/cop/layout/empty_lines.rb +3 -1
  58. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +7 -5
  59. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +20 -10
  60. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +20 -0
  61. data/lib/rubocop/cop/{lint → layout}/end_alignment.rb +37 -6
  62. data/lib/rubocop/cop/layout/end_of_line.rb +1 -0
  63. data/lib/rubocop/cop/layout/extra_spacing.rb +30 -37
  64. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -0
  65. data/lib/rubocop/cop/layout/indent_heredoc.rb +38 -2
  66. data/lib/rubocop/cop/layout/indentation_consistency.rb +105 -1
  67. data/lib/rubocop/cop/layout/indentation_width.rb +4 -3
  68. data/lib/rubocop/cop/layout/initial_indentation.rb +15 -1
  69. data/lib/rubocop/cop/layout/leading_comment_space.rb +4 -2
  70. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -0
  71. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  72. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +62 -29
  73. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  74. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +74 -33
  75. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +16 -2
  76. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -1
  77. data/lib/rubocop/cop/layout/space_after_method_name.rb +2 -0
  78. data/lib/rubocop/cop/layout/space_after_not.rb +2 -0
  79. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -0
  80. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +15 -2
  81. data/lib/rubocop/cop/layout/space_around_operators.rb +15 -13
  82. data/lib/rubocop/cop/layout/space_before_block_braces.rb +13 -1
  83. data/lib/rubocop/cop/layout/space_before_comment.rb +6 -4
  84. data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -0
  85. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -0
  86. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +30 -45
  87. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +3 -2
  88. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +48 -18
  89. data/lib/rubocop/cop/layout/space_inside_parens.rb +8 -7
  90. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +57 -11
  91. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +1 -0
  92. data/lib/rubocop/cop/layout/tab.rb +42 -16
  93. data/lib/rubocop/cop/layout/trailing_blank_lines.rb +46 -13
  94. data/lib/rubocop/cop/layout/trailing_whitespace.rb +12 -0
  95. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +5 -3
  96. data/lib/rubocop/cop/lint/big_decimal_new.rb +44 -0
  97. data/lib/rubocop/cop/lint/boolean_symbol.rb +2 -2
  98. data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -2
  99. data/lib/rubocop/cop/lint/debugger.rb +2 -2
  100. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +5 -4
  101. data/lib/rubocop/cop/lint/duplicate_methods.rb +20 -9
  102. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +4 -3
  103. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +16 -10
  104. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +5 -4
  105. data/lib/rubocop/cop/lint/inherit_exception.rb +2 -2
  106. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  107. data/lib/rubocop/cop/lint/literal_as_condition.rb +2 -2
  108. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +2 -0
  109. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +7 -5
  110. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  111. data/lib/rubocop/cop/lint/number_conversion.rb +59 -0
  112. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +86 -0
  113. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +2 -0
  114. data/lib/rubocop/cop/lint/percent_string_array.rb +0 -2
  115. data/lib/rubocop/cop/lint/rand_one.rb +2 -2
  116. data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -0
  117. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -0
  118. data/lib/rubocop/cop/lint/require_parentheses.rb +2 -0
  119. data/lib/rubocop/cop/lint/rescue_type.rb +6 -3
  120. data/lib/rubocop/cop/lint/return_in_void_context.rb +2 -2
  121. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -21
  122. data/lib/rubocop/cop/lint/script_permission.rb +30 -10
  123. data/lib/rubocop/cop/lint/shadowed_argument.rb +3 -3
  124. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -0
  125. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +2 -2
  126. data/lib/rubocop/cop/lint/unified_integer.rb +2 -2
  127. data/lib/rubocop/cop/lint/{unneeded_disable.rb → unneeded_cop_disable_directive.rb} +13 -7
  128. data/lib/rubocop/cop/lint/unneeded_cop_enable_directive.rb +97 -0
  129. data/lib/rubocop/cop/lint/unneeded_require_statement.rb +1 -0
  130. data/lib/rubocop/cop/lint/unreachable_code.rb +3 -3
  131. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +11 -10
  132. data/lib/rubocop/cop/lint/useless_access_modifier.rb +7 -5
  133. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -2
  134. data/lib/rubocop/cop/lint/useless_setter_call.rb +2 -2
  135. data/lib/rubocop/cop/lint/void.rb +49 -10
  136. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  137. data/lib/rubocop/cop/metrics/line_length.rb +5 -2
  138. data/lib/rubocop/cop/mixin/alignment.rb +4 -0
  139. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -1
  140. data/lib/rubocop/cop/mixin/def_node.rb +4 -0
  141. data/lib/rubocop/cop/mixin/documentation_comment.rb +11 -3
  142. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -2
  143. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +20 -1
  144. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
  145. data/lib/rubocop/cop/mixin/hash_alignment.rb +2 -2
  146. data/lib/rubocop/cop/mixin/match_range.rb +2 -0
  147. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +6 -0
  148. data/lib/rubocop/cop/mixin/nil_methods.rb +19 -0
  149. data/lib/rubocop/cop/mixin/percent_literal.rb +57 -9
  150. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -5
  151. data/lib/rubocop/cop/mixin/range_help.rb +102 -0
  152. data/lib/rubocop/cop/mixin/rescue_node.rb +1 -1
  153. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +8 -7
  154. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +11 -9
  155. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -10
  156. data/lib/rubocop/cop/mixin/surrounding_space.rb +38 -8
  157. data/lib/rubocop/cop/mixin/trailing_body.rb +26 -0
  158. data/lib/rubocop/cop/mixin/trailing_comma.rb +15 -3
  159. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +104 -0
  160. data/lib/rubocop/cop/naming/ascii_identifiers.rb +3 -1
  161. data/lib/rubocop/cop/naming/file_name.rb +5 -10
  162. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +76 -0
  163. data/lib/rubocop/cop/naming/uncommunicative_block_param_name.rb +48 -0
  164. data/lib/rubocop/cop/naming/uncommunicative_method_param_name.rb +57 -0
  165. data/lib/rubocop/cop/offense.rb +3 -2
  166. data/lib/rubocop/cop/performance/case_when_splat.rb +1 -0
  167. data/lib/rubocop/cop/performance/casecmp.rb +17 -8
  168. data/lib/rubocop/cop/performance/compare_with_block.rb +2 -0
  169. data/lib/rubocop/cop/performance/count.rb +1 -0
  170. data/lib/rubocop/cop/performance/fixed_size.rb +41 -0
  171. data/lib/rubocop/cop/performance/flat_map.rb +2 -0
  172. data/lib/rubocop/cop/performance/lstrip_rstrip.rb +2 -0
  173. data/lib/rubocop/cop/performance/redundant_merge.rb +1 -1
  174. data/lib/rubocop/cop/performance/redundant_sort_by.rb +2 -0
  175. data/lib/rubocop/cop/performance/regexp_match.rb +4 -0
  176. data/lib/rubocop/cop/performance/reverse_each.rb +2 -0
  177. data/lib/rubocop/cop/performance/string_replacement.rb +2 -0
  178. data/lib/rubocop/cop/rails/active_record_aliases.rb +46 -0
  179. data/lib/rubocop/cop/rails/blank.rb +3 -3
  180. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +6 -0
  181. data/lib/rubocop/cop/rails/delegate.rb +6 -6
  182. data/lib/rubocop/cop/rails/file_path.rb +7 -1
  183. data/lib/rubocop/cop/rails/find_by.rb +2 -0
  184. data/lib/rubocop/cop/rails/http_positional_arguments.rb +17 -5
  185. data/lib/rubocop/cop/rails/inverse_of.rb +21 -2
  186. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +45 -9
  187. data/lib/rubocop/cop/rails/presence.rb +8 -2
  188. data/lib/rubocop/cop/rails/present.rb +5 -5
  189. data/lib/rubocop/cop/rails/read_write_attribute.rb +4 -3
  190. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -0
  191. data/lib/rubocop/cop/rails/relative_date_constant.rb +4 -3
  192. data/lib/rubocop/cop/rails/request_referer.rb +3 -2
  193. data/lib/rubocop/cop/rails/reversible_migration.rb +9 -8
  194. data/lib/rubocop/cop/rails/safe_navigation.rb +3 -2
  195. data/lib/rubocop/cop/rails/save_bang.rb +11 -12
  196. data/lib/rubocop/cop/rails/skips_model_validations.rb +2 -2
  197. data/lib/rubocop/cop/rails/time_zone.rb +38 -16
  198. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +26 -16
  199. data/lib/rubocop/cop/rails/validation.rb +30 -2
  200. data/lib/rubocop/cop/security/open.rb +48 -0
  201. data/lib/rubocop/cop/style/and_or.rb +1 -0
  202. data/lib/rubocop/cop/style/ascii_comments.rb +3 -1
  203. data/lib/rubocop/cop/style/attr.rb +2 -0
  204. data/lib/rubocop/cop/style/block_comments.rb +3 -1
  205. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +2 -5
  206. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
  207. data/lib/rubocop/cop/style/class_vars.rb +23 -0
  208. data/lib/rubocop/cop/style/colon_method_call.rb +1 -2
  209. data/lib/rubocop/cop/style/comment_annotation.rb +6 -4
  210. data/lib/rubocop/cop/style/commented_keyword.rb +3 -1
  211. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  212. data/lib/rubocop/cop/style/copyright.rb +3 -1
  213. data/lib/rubocop/cop/style/each_with_object.rb +15 -1
  214. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -0
  215. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -0
  216. data/lib/rubocop/cop/style/empty_else.rb +9 -5
  217. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -0
  218. data/lib/rubocop/cop/style/empty_line_after_guard_clause.rb +80 -0
  219. data/lib/rubocop/cop/style/empty_literal.rb +1 -0
  220. data/lib/rubocop/cop/style/encoding.rb +2 -0
  221. data/lib/rubocop/cop/style/expand_path_arguments.rb +194 -0
  222. data/lib/rubocop/cop/style/for.rb +33 -0
  223. data/lib/rubocop/cop/style/format_string.rb +1 -1
  224. data/lib/rubocop/cop/style/format_string_token.rb +4 -5
  225. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  226. data/lib/rubocop/cop/style/hash_syntax.rb +1 -0
  227. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -1
  228. data/lib/rubocop/cop/style/inline_comment.rb +1 -1
  229. data/lib/rubocop/cop/style/lambda.rb +1 -1
  230. data/lib/rubocop/cop/style/line_end_concatenation.rb +2 -0
  231. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -0
  232. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -0
  233. data/lib/rubocop/cop/style/missing_else.rb +72 -7
  234. data/lib/rubocop/cop/style/mixin_usage.rb +3 -5
  235. data/lib/rubocop/cop/style/module_function.rb +10 -0
  236. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -0
  237. data/lib/rubocop/cop/style/multiline_if_then.rb +1 -0
  238. data/lib/rubocop/cop/style/nested_modifier.rb +2 -0
  239. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -0
  240. data/lib/rubocop/cop/style/next.rb +1 -0
  241. data/lib/rubocop/cop/style/not.rb +2 -0
  242. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  243. data/lib/rubocop/cop/style/one_line_conditional.rb +2 -2
  244. data/lib/rubocop/cop/style/redundant_exception.rb +8 -3
  245. data/lib/rubocop/cop/style/redundant_return.rb +37 -3
  246. data/lib/rubocop/cop/style/redundant_self.rb +1 -1
  247. data/lib/rubocop/cop/style/rescue_standard_error.rb +1 -0
  248. data/lib/rubocop/cop/style/safe_navigation.rb +74 -32
  249. data/lib/rubocop/cop/style/semicolon.rb +3 -1
  250. data/lib/rubocop/cop/style/single_line_methods.rb +14 -23
  251. data/lib/rubocop/cop/style/stderr_puts.rb +2 -0
  252. data/lib/rubocop/cop/style/string_hash_keys.rb +12 -0
  253. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  254. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +1 -1
  255. data/lib/rubocop/cop/style/symbol_array.rb +29 -0
  256. data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
  257. data/lib/rubocop/cop/style/trailing_body_on_class.rb +43 -0
  258. data/lib/rubocop/cop/style/trailing_body_on_method_definition.rb +7 -54
  259. data/lib/rubocop/cop/style/trailing_body_on_module.rb +43 -0
  260. data/lib/rubocop/cop/style/{trailing_comma_in_literal.rb → trailing_comma_in_array_literal.rb} +2 -20
  261. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +56 -0
  262. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +17 -20
  263. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +1 -0
  264. data/lib/rubocop/cop/style/unless_else.rb +2 -0
  265. data/lib/rubocop/cop/style/word_array.rb +0 -1
  266. data/lib/rubocop/cop/style/yoda_condition.rb +1 -0
  267. data/lib/rubocop/cop/team.rb +5 -5
  268. data/lib/rubocop/cop/util.rb +23 -188
  269. data/lib/rubocop/cop/variable_force.rb +1 -1
  270. data/lib/rubocop/file_finder.rb +45 -0
  271. data/lib/rubocop/formatter/disabled_config_formatter.rb +23 -14
  272. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  273. data/lib/rubocop/formatter/html_formatter.rb +12 -5
  274. data/lib/rubocop/formatter/json_formatter.rb +1 -1
  275. data/lib/rubocop/node_pattern.rb +8 -5
  276. data/lib/rubocop/options.rb +40 -33
  277. data/lib/rubocop/path_util.rb +5 -8
  278. data/lib/rubocop/processed_source.rb +53 -0
  279. data/lib/rubocop/remote_config.rb +1 -1
  280. data/lib/rubocop/result_cache.rb +1 -1
  281. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  282. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -4
  283. data/lib/rubocop/rspec/shared_contexts.rb +3 -1
  284. data/lib/rubocop/rspec/shared_examples.rb +23 -25
  285. data/lib/rubocop/rspec/support.rb +5 -0
  286. data/lib/rubocop/runner.rb +3 -2
  287. data/lib/rubocop/string_util.rb +10 -9
  288. data/lib/rubocop/target_finder.rb +4 -1
  289. data/lib/rubocop/token.rb +26 -16
  290. data/lib/rubocop/version.rb +6 -4
  291. metadata +31 -17
  292. data/lib/rubocop/cop/performance/hash_each_methods.rb +0 -129
@@ -138,7 +138,7 @@ module RuboCop
138
138
  else elsif end ensure false for if in module
139
139
  next nil not or redo rescue retry return self
140
140
  super then true undef unless until when while
141
- yield].include?(method_name)
141
+ yield __FILE__ __LINE__ __ENCODING__].include?(method_name)
142
142
  end
143
143
 
144
144
  def allow_self(node)
@@ -73,6 +73,7 @@ module RuboCop
73
73
  class RescueStandardError < Cop
74
74
  include RescueNode
75
75
  include ConfigurableEnforcedStyle
76
+ include RangeHelp
76
77
 
77
78
  MSG_IMPLICIT = 'Omit the error class when rescuing ' \
78
79
  '`StandardError` by itself.'.freeze
@@ -5,7 +5,10 @@ module RuboCop
5
5
  module Style
6
6
  # This cop transforms usages of a method call safeguarded by a non `nil`
7
7
  # check for the variable whose method is being called to
8
- # safe navigation (`&.`).
8
+ # safe navigation (`&.`). If there is a method chain, all of the methods
9
+ # in the chain need to be checked for safety, and all of the methods will
10
+ # need to be changed to use safe navigation. We have limited the cop to
11
+ # not register an offense for method chains that exceed 2 methods.
9
12
  #
10
13
  # Configuration option: ConvertCodeThatCanStartToReturnNil
11
14
  # The default for this is `false`. When configured to `true`, this will
@@ -18,6 +21,7 @@ module RuboCop
18
21
  # @example
19
22
  # # bad
20
23
  # foo.bar if foo
24
+ # foo.bar.baz if foo
21
25
  # foo.bar(param1, param2) if foo
22
26
  # foo.bar { |e| e.something } if foo
23
27
  # foo.bar(param) { |e| e.something } if foo
@@ -27,28 +31,40 @@ module RuboCop
27
31
  # foo.bar unless foo.nil?
28
32
  #
29
33
  # foo && foo.bar
34
+ # foo && foo.bar.baz
30
35
  # foo && foo.bar(param1, param2)
31
36
  # foo && foo.bar { |e| e.something }
32
37
  # foo && foo.bar(param) { |e| e.something }
33
38
  #
34
39
  # # good
35
40
  # foo&.bar
41
+ # foo&.bar&.baz
36
42
  # foo&.bar(param1, param2)
37
43
  # foo&.bar { |e| e.something }
38
44
  # foo&.bar(param) { |e| e.something }
45
+ # foo && foo.bar.baz.qux # method chain with more than 2 methods
46
+ # foo && foo.nil? # method that `nil` responds to
39
47
  #
48
+ # # Method calls that do not use `.`
49
+ # foo && foo < bar
50
+ # foo < bar if foo
51
+ #
52
+ # # This could start returning `nil` as well as the return of the method
40
53
  # foo.nil? || foo.bar
41
54
  # !foo || foo.bar
42
55
  #
43
- # # Methods that `nil` will `respond_to?` should not be converted to
44
- # # use safe navigation
45
- # foo.to_i if foo
56
+ # # Methods that are used on assignment, arithmetic operation or
57
+ # # comparison should not be converted to use safe navigation
58
+ # foo.baz = bar if foo
59
+ # foo.baz + bar if foo
60
+ # foo.bar > 2 if foo
46
61
  class SafeNavigation < Cop
47
62
  extend TargetRubyVersion
63
+ include NilMethods
64
+ include RangeHelp
48
65
 
49
66
  MSG = 'Use safe navigation (`&.`) instead of checking if an object ' \
50
67
  'exists before calling the method.'.freeze
51
- NIL_METHODS = nil.methods.freeze
52
68
 
53
69
  minimum_target_ruby_version 2.3
54
70
 
@@ -81,9 +97,12 @@ module RuboCop
81
97
 
82
98
  def check_node(node)
83
99
  return if target_ruby_version < 2.3
84
- checked_variable, receiver, method = extract_parts(node)
100
+ checked_variable, receiver, method_chain, method = extract_parts(node)
85
101
  return unless receiver == checked_variable
86
- return if unsafe_method?(method)
102
+ # method is already a method call so this is actually checking for a
103
+ # chain greater than 2
104
+ return if chain_size(method_chain, method) > 1
105
+ return if unsafe_method_used?(method_chain, method)
87
106
 
88
107
  add_offense(node)
89
108
  end
@@ -96,7 +115,9 @@ module RuboCop
96
115
  lambda do |corrector|
97
116
  corrector.remove(begin_range(node, body))
98
117
  corrector.remove(end_range(node, body))
99
- corrector.insert_before((method_call || body).loc.dot, '&')
118
+ corrector.insert_before(method_call.loc.dot, '&')
119
+
120
+ add_safe_nav_to_all_methods_in_chain(corrector, method_call, body)
100
121
  end
101
122
  end
102
123
 
@@ -116,10 +137,12 @@ module RuboCop
116
137
  end
117
138
 
118
139
  def extract_parts_from_if(node)
119
- checked_variable, receiver =
140
+ variable, receiver =
120
141
  modifier_if_safe_navigation_candidate?(node)
121
142
 
122
- extract_common_parts(receiver, checked_variable)
143
+ checked_variable, matching_receiver, method =
144
+ extract_common_parts(receiver, variable)
145
+ [checked_variable, matching_receiver, receiver, method]
123
146
  end
124
147
 
125
148
  def extract_parts_from_and(node)
@@ -129,49 +152,56 @@ module RuboCop
129
152
  not_nil_check?(checked_variable) || checked_variable
130
153
  end
131
154
 
132
- extract_common_parts(rhs, checked_variable)
155
+ checked_variable, matching_receiver, method =
156
+ extract_common_parts(rhs, checked_variable)
157
+ [checked_variable, matching_receiver, rhs, method]
133
158
  end
134
159
 
135
- def extract_common_parts(continuation, checked_variable)
160
+ def extract_common_parts(method_chain, checked_variable)
136
161
  matching_receiver =
137
- find_matching_receiver_invocation(continuation, checked_variable)
162
+ find_matching_receiver_invocation(method_chain, checked_variable)
138
163
 
139
164
  method = matching_receiver.parent if matching_receiver
140
165
 
141
166
  [checked_variable, matching_receiver, method]
142
167
  end
143
168
 
144
- def find_matching_receiver_invocation(node, checked_variable)
145
- return nil unless node
169
+ def find_matching_receiver_invocation(method_chain, checked_variable)
170
+ return nil unless method_chain
146
171
 
147
- receiver = if node.block_type?
148
- node.send_node.receiver
172
+ receiver = if method_chain.block_type?
173
+ method_chain.send_node.receiver
149
174
  else
150
- node.receiver
175
+ method_chain.receiver
151
176
  end
152
177
 
153
- if receiver == checked_variable
154
- return nil if assignment_arithmetic_or_comparison?(node)
155
-
156
- return receiver
157
- end
158
-
178
+ return receiver if receiver == checked_variable
159
179
  find_matching_receiver_invocation(receiver, checked_variable)
160
180
  end
161
181
 
162
- def assignment_arithmetic_or_comparison?(node)
163
- node.assignment? ||
164
- node.parent.arithmetic_operation? ||
165
- comparison_node?(node.parent)
182
+ def chain_size(method_chain, method)
183
+ method.each_ancestor(:send).inject(0) do |total, ancestor|
184
+ break total + 1 if ancestor == method_chain
185
+ total + 1
186
+ end
166
187
  end
167
188
 
168
- def comparison_node?(parent)
169
- parent.send_type? && parent.comparison_method?
189
+ def unsafe_method_used?(method_chain, method)
190
+ return true if unsafe_method?(method)
191
+
192
+ method.each_ancestor(:send).any? do |ancestor|
193
+ unless config.for_cop('Lint/SafeNavigationChain')['Enabled']
194
+ break true
195
+ end
196
+
197
+ break true if unsafe_method?(ancestor)
198
+ break true if nil_methods.include?(ancestor.method_name)
199
+ break false if ancestor == method_chain
200
+ end
170
201
  end
171
202
 
172
203
  def unsafe_method?(send_node)
173
- NIL_METHODS.include?(send_node.method_name) ||
174
- negated?(send_node) || !send_node.dot?
204
+ negated?(send_node) || send_node.assignment? || !send_node.dot?
175
205
  end
176
206
 
177
207
  def negated?(send_node)
@@ -191,6 +221,18 @@ module RuboCop
191
221
  range_between(method_call.loc.expression.end_pos,
192
222
  node.loc.expression.end_pos)
193
223
  end
224
+
225
+ def add_safe_nav_to_all_methods_in_chain(corrector,
226
+ start_method,
227
+ method_chain)
228
+ start_method.each_ancestor do |ancestor|
229
+ break unless %i[send block].include?(ancestor.type)
230
+ next unless ancestor.send_type?
231
+ break if ancestor == method_chain
232
+
233
+ corrector.insert_before(ancestor.loc.dot, '&')
234
+ end
235
+ end
194
236
  end
195
237
  end
196
238
  end
@@ -16,10 +16,12 @@ module RuboCop
16
16
  # bar = 2
17
17
  # baz = 3
18
18
  class Semicolon < Cop
19
+ include RangeHelp
20
+
19
21
  MSG = 'Do not use semicolons to terminate expressions.'.freeze
20
22
 
21
23
  def investigate(processed_source)
22
- return unless processed_source.ast
24
+ return if processed_source.blank?
23
25
  @processed_source = processed_source
24
26
 
25
27
  check_for_line_terminator_or_opener
@@ -31,17 +31,20 @@ module RuboCop
31
31
  alias on_defs on_def
32
32
 
33
33
  def autocorrect(node)
34
- body = node.body
35
-
36
34
  lambda do |corrector|
37
- each_part(body) do |part|
38
- break_line_before(part, node, corrector, 1)
35
+ each_part(node.body) do |part|
36
+ LineBreakCorrector.break_line_before(
37
+ range: part, node: node, corrector: corrector,
38
+ configured_width: configured_indentation_width
39
+ )
39
40
  end
40
41
 
41
- break_line_before(node.loc.end, node, corrector, 0)
42
+ LineBreakCorrector.break_line_before(
43
+ range: node.loc.end, node: node, corrector: corrector,
44
+ indent_steps: 0, configured_width: configured_indentation_width
45
+ )
42
46
 
43
- eol_comment = end_of_line_comment(node.source_range.line)
44
- move_comment(eol_comment, node, corrector) if eol_comment
47
+ move_comment(node, corrector)
45
48
  end
46
49
  end
47
50
 
@@ -51,10 +54,6 @@ module RuboCop
51
54
  cop_config['AllowIfMethodIsEmpty']
52
55
  end
53
56
 
54
- def end_of_line_comment(line)
55
- processed_source.comments.find { |c| c.loc.line == line }
56
- end
57
-
58
57
  def each_part(body)
59
58
  return unless body
60
59
 
@@ -65,20 +64,12 @@ module RuboCop
65
64
  end
66
65
  end
67
66
 
68
- def break_line_before(range, node, corrector, indent_steps)
69
- corrector.insert_before(
70
- range,
71
- "\n" + ' ' * (node.loc.keyword.column +
72
- indent_steps * configured_indentation_width)
67
+ def move_comment(node, corrector)
68
+ LineBreakCorrector.move_comment(
69
+ eol_comment: end_of_line_comment(node.source_range.line),
70
+ node: node, corrector: corrector
73
71
  )
74
72
  end
75
-
76
- def move_comment(eol_comment, node, corrector)
77
- text = eol_comment.loc.expression.source
78
- corrector.insert_before(node.source_range,
79
- text + "\n" + (' ' * node.loc.keyword.column))
80
- corrector.remove(eol_comment.loc.expression)
81
- end
82
73
  end
83
74
  end
84
75
  end
@@ -15,6 +15,8 @@ module RuboCop
15
15
  # warn('hello')
16
16
  #
17
17
  class StderrPuts < Cop
18
+ include RangeHelp
19
+
18
20
  MSG = 'Use `warn` instead of `$stderr.puts` to allow such output ' \
19
21
  'to be disabled.'.freeze
20
22
 
@@ -19,8 +19,20 @@ module RuboCop
19
19
  (pair (str _) _)
20
20
  PATTERN
21
21
 
22
+ def_node_matcher :receive_environments_method?, <<-PATTERN
23
+ {
24
+ ^^(send (const {nil? cbase} :IO) :popen ...)
25
+ ^^(send (const {nil? cbase} :Open3)
26
+ {:capture2 :capture2e :capture3 :popen2 :popen2e :popen3} ...)
27
+ ^^^(send (const {nil? cbase} :Open3)
28
+ {:pipeline :pipeline_r :pipeline_rw :pipeline_start :pipeline_w} ...)
29
+ ^^(send {nil? (const {nil? cbase} :Kernel)} {:spawn :system} ...)
30
+ }
31
+ PATTERN
32
+
22
33
  def on_pair(node)
23
34
  return unless string_hash_key?(node)
35
+ return if receive_environments_method?(node)
24
36
  add_offense(node.key)
25
37
  end
26
38
 
@@ -76,7 +76,7 @@ module RuboCop
76
76
  styles.map(&:source).uniq
77
77
  end
78
78
 
79
- def message(*)
79
+ def message(_node)
80
80
  if style == :single_quotes
81
81
  "Prefer single-quoted strings when you don't need string " \
82
82
  'interpolation or special symbols.'
@@ -29,7 +29,7 @@ module RuboCop
29
29
 
30
30
  private
31
31
 
32
- def message(*)
32
+ def message(_node)
33
33
  # single_quotes -> single-quoted
34
34
  kind = style.to_s.sub(/_(.*)s/, '-\1d')
35
35
 
@@ -75,6 +75,35 @@ module RuboCop
75
75
  corrector.replace(node.source_range, "[#{syms.join(', ')}]")
76
76
  end
77
77
  end
78
+
79
+ def to_symbol_literal(string)
80
+ if symbol_without_quote?(string)
81
+ ":#{string}"
82
+ else
83
+ ":#{to_string_literal(string)}"
84
+ end
85
+ end
86
+
87
+ def symbol_without_quote?(string)
88
+ special_gvars = %w[
89
+ $! $" $$ $& $' $* $+ $, $/ $; $: $. $< $= $> $? $@ $\\ $_ $` $~ $0
90
+ $-0 $-F $-I $-K $-W $-a $-d $-i $-l $-p $-v $-w
91
+ ]
92
+ redefinable_operators = %w(
93
+ | ^ & <=> == === =~ > >= < <= << >>
94
+ + - * / % ** ~ +@ -@ [] []= ` ! != !~
95
+ )
96
+
97
+ # method name
98
+ string =~ /\A[a-zA-Z_]\w*[!?]?\z/ ||
99
+ # instance / class variable
100
+ string =~ /\A\@\@?[a-zA-Z_]\w*\z/ ||
101
+ # global variable
102
+ string =~ /\A\$[1-9]\d*\z/ ||
103
+ string =~ /\A\$[a-zA-Z_]\w*\z/ ||
104
+ special_gvars.include?(string) ||
105
+ redefinable_operators.include?(string)
106
+ end
78
107
  end
79
108
  end
80
109
  end
@@ -12,6 +12,8 @@ module RuboCop
12
12
  # # good
13
13
  # something.map(&:upcase)
14
14
  class SymbolProc < Cop
15
+ include RangeHelp
16
+
15
17
  MSG = 'Pass `&:%<method>s` as an argument to `%<block_method>s` ' \
16
18
  'instead of a block.'.freeze
17
19
  SUPER_TYPES = %i[super zsuper].freeze
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for trailing code after the class definition.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # class Foo; def foo; end
11
+ # end
12
+ #
13
+ # # good
14
+ # class Foo
15
+ # def foo; end
16
+ # end
17
+ #
18
+ class TrailingBodyOnClass < Cop
19
+ include Alignment
20
+ include TrailingBody
21
+
22
+ MSG = 'Place the first line of class body on its own line.'.freeze
23
+
24
+ def on_class(node)
25
+ return unless trailing_body?(node)
26
+
27
+ add_offense(node, location: first_part_of(node.to_a.last))
28
+ end
29
+
30
+ def autocorrect(node)
31
+ lambda do |corrector|
32
+ LineBreakCorrector.correct_trailing_body(
33
+ configured_width: configured_indentation_width,
34
+ corrector: corrector,
35
+ node: node,
36
+ processed_source: processed_source
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -26,6 +26,7 @@ module RuboCop
26
26
  #
27
27
  class TrailingBodyOnMethodDefinition < Cop
28
28
  include Alignment
29
+ include TrailingBody
29
30
 
30
31
  MSG = "Place the first line of a multi-line method definition's " \
31
32
  'body on its own line.'.freeze
@@ -39,60 +40,12 @@ module RuboCop
39
40
 
40
41
  def autocorrect(node)
41
42
  lambda do |corrector|
42
- break_line_before_body(node, corrector)
43
- move_comment(node, corrector)
44
- remove_semicolon(corrector)
45
- end
46
- end
47
-
48
- private
49
-
50
- def trailing_body?(node)
51
- node.body && node.multiline? && on_def_line?(node)
52
- end
53
-
54
- def on_def_line?(node)
55
- node.source_range.first_line == node.body.source_range.first_line
56
- end
57
-
58
- def break_line_before_body(node, corrector)
59
- corrector.insert_before(
60
- first_part_of(node.body),
61
- "\n" + ' ' * (node.loc.keyword.column +
62
- configured_indentation_width)
63
- )
64
- end
65
-
66
- def first_part_of(body)
67
- if body.begin_type?
68
- body.children.first.source_range
69
- else
70
- body.source_range
71
- end
72
- end
73
-
74
- def move_comment(node, corrector)
75
- eol_comment = end_of_line_comment(node.source_range.line)
76
- return unless eol_comment
77
-
78
- text = eol_comment.loc.expression.source
79
- corrector.insert_before(node.source_range,
80
- text + "\n" + (' ' * node.loc.keyword.column))
81
- corrector.remove(eol_comment.loc.expression)
82
- end
83
-
84
- def end_of_line_comment(line)
85
- processed_source.comments.find { |c| c.loc.line == line }
86
- end
87
-
88
- def remove_semicolon(corrector)
89
- return unless semicolon
90
- corrector.remove(semicolon.pos)
91
- end
92
-
93
- def semicolon
94
- @semicolon ||= processed_source.tokens.find do |token|
95
- token.line == 1 && token.semicolon?
43
+ LineBreakCorrector.correct_trailing_body(
44
+ configured_width: configured_indentation_width,
45
+ corrector: corrector,
46
+ node: node,
47
+ processed_source: processed_source
48
+ )
96
49
  end
97
50
  end
98
51
  end