rubocop 1.59.0 → 1.65.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 (255) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +3 -4
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +93 -17
  7. data/lib/rubocop/cached_data.rb +11 -3
  8. data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
  9. data/lib/rubocop/cli/command/lsp.rb +2 -2
  10. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  11. data/lib/rubocop/cli.rb +10 -1
  12. data/lib/rubocop/config.rb +36 -12
  13. data/lib/rubocop/config_finder.rb +12 -2
  14. data/lib/rubocop/config_loader.rb +1 -2
  15. data/lib/rubocop/config_loader_resolver.rb +9 -3
  16. data/lib/rubocop/config_obsoletion.rb +1 -1
  17. data/lib/rubocop/config_validator.rb +14 -7
  18. data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
  19. data/lib/rubocop/cop/base.rb +63 -16
  20. data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
  21. data/lib/rubocop/cop/cop.rb +22 -4
  22. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  23. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  24. data/lib/rubocop/cop/documentation.rb +16 -6
  25. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  26. data/lib/rubocop/cop/force.rb +12 -0
  27. data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
  28. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  29. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  30. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  31. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  32. data/lib/rubocop/cop/internal_affairs/example_description.rb +6 -5
  33. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  34. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +122 -28
  35. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  36. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  37. data/lib/rubocop/cop/layout/assignment_indentation.rb +3 -2
  38. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  39. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  40. data/lib/rubocop/cop/layout/condition_position.rb +0 -4
  41. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  42. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  43. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
  44. data/lib/rubocop/cop/layout/end_alignment.rb +8 -2
  45. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
  46. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -1
  47. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
  48. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  49. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
  50. data/lib/rubocop/cop/layout/line_length.rb +20 -20
  51. data/lib/rubocop/cop/layout/redundant_line_break.rb +14 -2
  52. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -0
  53. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  54. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  55. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  56. data/lib/rubocop/cop/legacy/corrector.rb +12 -2
  57. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +0 -2
  58. data/lib/rubocop/cop/lint/ambiguous_operator.rb +0 -2
  59. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +0 -2
  60. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
  61. data/lib/rubocop/cop/lint/boolean_symbol.rb +0 -2
  62. data/lib/rubocop/cop/lint/circular_argument_reference.rb +0 -13
  63. data/lib/rubocop/cop/lint/debugger.rb +27 -6
  64. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  65. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +0 -10
  66. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -5
  67. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +0 -4
  68. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -10
  69. data/lib/rubocop/cop/lint/each_with_object_argument.rb +0 -4
  70. data/lib/rubocop/cop/lint/else_layout.rb +0 -2
  71. data/lib/rubocop/cop/lint/empty_conditional_body.rb +2 -2
  72. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -11
  73. data/lib/rubocop/cop/lint/empty_interpolation.rb +0 -4
  74. data/lib/rubocop/cop/lint/empty_when.rb +1 -3
  75. data/lib/rubocop/cop/lint/ensure_return.rb +1 -6
  76. data/lib/rubocop/cop/lint/erb_new_arguments.rb +21 -14
  77. data/lib/rubocop/cop/lint/float_comparison.rb +3 -1
  78. data/lib/rubocop/cop/lint/float_out_of_range.rb +0 -4
  79. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +0 -10
  80. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +15 -12
  81. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +0 -7
  82. data/lib/rubocop/cop/lint/interpolation_check.rb +0 -4
  83. data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
  84. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +13 -6
  85. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +0 -4
  86. data/lib/rubocop/cop/lint/loop.rb +6 -12
  87. data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
  88. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -7
  89. data/lib/rubocop/cop/lint/next_without_accumulator.rb +0 -4
  90. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +0 -5
  91. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  92. data/lib/rubocop/cop/lint/percent_string_array.rb +0 -4
  93. data/lib/rubocop/cop/lint/percent_symbol_array.rb +0 -4
  94. data/lib/rubocop/cop/lint/rand_one.rb +0 -4
  95. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +3 -1
  96. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +14 -9
  97. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  98. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +0 -4
  99. data/lib/rubocop/cop/lint/redundant_with_index.rb +4 -0
  100. data/lib/rubocop/cop/lint/require_parentheses.rb +0 -4
  101. data/lib/rubocop/cop/lint/rescue_exception.rb +0 -4
  102. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  103. data/lib/rubocop/cop/lint/return_in_void_context.rb +0 -2
  104. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +0 -4
  105. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  106. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  107. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +6 -10
  108. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  109. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -3
  110. data/lib/rubocop/cop/lint/unified_integer.rb +0 -4
  111. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  112. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -7
  113. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  114. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -5
  115. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +0 -4
  116. data/lib/rubocop/cop/lint/useless_setter_call.rb +0 -4
  117. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  118. data/lib/rubocop/cop/lint/void.rb +11 -1
  119. data/lib/rubocop/cop/metrics/block_nesting.rb +19 -7
  120. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
  121. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  122. data/lib/rubocop/cop/mixin/allowed_methods.rb +7 -1
  123. data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
  124. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  125. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  126. data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
  127. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +9 -2
  128. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  129. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  130. data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
  131. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  132. data/lib/rubocop/cop/naming/block_forwarding.rb +32 -5
  133. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  134. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
  135. data/lib/rubocop/cop/naming/predicate_name.rb +54 -28
  136. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +10 -1
  137. data/lib/rubocop/cop/registry.rb +1 -1
  138. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  139. data/lib/rubocop/cop/security/open.rb +2 -2
  140. data/lib/rubocop/cop/style/access_modifier_declarations.rb +50 -0
  141. data/lib/rubocop/cop/style/alias.rb +1 -0
  142. data/lib/rubocop/cop/style/arguments_forwarding.rb +89 -17
  143. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  144. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  145. data/lib/rubocop/cop/style/collection_compact.rb +14 -5
  146. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  147. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -7
  148. data/lib/rubocop/cop/style/copyright.rb +31 -21
  149. data/lib/rubocop/cop/style/def_with_parentheses.rb +0 -2
  150. data/lib/rubocop/cop/style/documentation.rb +24 -24
  151. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  152. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -8
  153. data/lib/rubocop/cop/style/eval_with_location.rb +15 -23
  154. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  155. data/lib/rubocop/cop/style/file_read.rb +2 -5
  156. data/lib/rubocop/cop/style/file_write.rb +2 -5
  157. data/lib/rubocop/cop/style/for.rb +2 -0
  158. data/lib/rubocop/cop/style/format_string.rb +9 -9
  159. data/lib/rubocop/cop/style/global_std_stream.rb +7 -1
  160. data/lib/rubocop/cop/style/hash_each_methods.rb +29 -8
  161. data/lib/rubocop/cop/style/hash_except.rb +8 -5
  162. data/lib/rubocop/cop/style/hash_syntax.rb +24 -2
  163. data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
  164. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -4
  165. data/lib/rubocop/cop/style/inverse_methods.rb +8 -8
  166. data/lib/rubocop/cop/style/invertible_unless_condition.rb +46 -4
  167. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +81 -50
  168. data/lib/rubocop/cop/style/map_into_array.rb +175 -0
  169. data/lib/rubocop/cop/style/map_to_hash.rb +10 -6
  170. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  171. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +18 -5
  172. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  173. data/lib/rubocop/cop/style/missing_else.rb +0 -4
  174. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  175. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +5 -3
  176. data/lib/rubocop/cop/style/multiline_when_then.rb +0 -4
  177. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  178. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  179. data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
  180. data/lib/rubocop/cop/style/object_then.rb +5 -3
  181. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  182. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  183. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  184. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  185. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  186. data/lib/rubocop/cop/style/redundant_argument.rb +25 -2
  187. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  188. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  189. data/lib/rubocop/cop/style/redundant_condition.rb +0 -1
  190. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +5 -4
  191. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  192. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
  193. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  194. data/lib/rubocop/cop/style/redundant_line_continuation.rb +17 -2
  195. data/lib/rubocop/cop/style/redundant_parentheses.rb +18 -2
  196. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  197. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -24
  198. data/lib/rubocop/cop/style/redundant_return.rb +6 -0
  199. data/lib/rubocop/cop/style/require_order.rb +1 -1
  200. data/lib/rubocop/cop/style/sample.rb +1 -3
  201. data/lib/rubocop/cop/style/send.rb +4 -4
  202. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +104 -0
  203. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  204. data/lib/rubocop/cop/style/sole_nested_conditional.rb +21 -2
  205. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  206. data/lib/rubocop/cop/style/super_arguments.rb +174 -0
  207. data/lib/rubocop/cop/style/symbol_proc.rb +75 -5
  208. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  209. data/lib/rubocop/cop/style/while_until_do.rb +0 -2
  210. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  211. data/lib/rubocop/cop/style/zero_length_predicate.rb +32 -24
  212. data/lib/rubocop/cop/team.rb +13 -0
  213. data/lib/rubocop/cop/util.rb +7 -1
  214. data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
  215. data/lib/rubocop/cop/variable_force.rb +13 -1
  216. data/lib/rubocop/cops_documentation_generator.rb +16 -4
  217. data/lib/rubocop/core_ext/string.rb +2 -6
  218. data/lib/rubocop/directive_comment.rb +10 -8
  219. data/lib/rubocop/ext/regexp_node.rb +18 -35
  220. data/lib/rubocop/ext/regexp_parser.rb +4 -21
  221. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  222. data/lib/rubocop/formatter/disabled_config_formatter.rb +23 -8
  223. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  224. data/lib/rubocop/formatter/html_formatter.rb +32 -10
  225. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  226. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  227. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  228. data/lib/rubocop/formatter.rb +1 -1
  229. data/lib/rubocop/lockfile.rb +56 -7
  230. data/lib/rubocop/lsp/logger.rb +1 -1
  231. data/lib/rubocop/lsp/routes.rb +12 -15
  232. data/lib/rubocop/lsp/runtime.rb +1 -1
  233. data/lib/rubocop/lsp/server.rb +7 -2
  234. data/lib/rubocop/lsp/severity.rb +1 -1
  235. data/lib/rubocop/lsp.rb +36 -0
  236. data/lib/rubocop/magic_comment.rb +1 -1
  237. data/lib/rubocop/options.rb +17 -12
  238. data/lib/rubocop/path_util.rb +6 -2
  239. data/lib/rubocop/rake_task.rb +1 -1
  240. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  241. data/lib/rubocop/rspec/expect_offense.rb +16 -8
  242. data/lib/rubocop/rspec/shared_contexts.rb +73 -16
  243. data/lib/rubocop/rspec/support.rb +3 -0
  244. data/lib/rubocop/runner.rb +14 -3
  245. data/lib/rubocop/server/cache.rb +11 -2
  246. data/lib/rubocop/server/client_command/exec.rb +2 -3
  247. data/lib/rubocop/server/client_command/start.rb +1 -1
  248. data/lib/rubocop/server/core.rb +4 -0
  249. data/lib/rubocop/server/server_command/exec.rb +0 -1
  250. data/lib/rubocop/target_finder.rb +84 -78
  251. data/lib/rubocop/target_ruby.rb +82 -80
  252. data/lib/rubocop/version.rb +19 -4
  253. data/lib/rubocop.rb +9 -0
  254. metadata +18 -11
  255. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -118,12 +118,14 @@ module RuboCop
118
118
 
119
119
  return unless numeric && operator && replacement_supported?(operator)
120
120
 
121
- [numeric, replacement(numeric, operator)]
121
+ [numeric, replacement(node, numeric, operator)]
122
122
  end
123
123
 
124
- def replacement(numeric, operation)
124
+ def replacement(node, numeric, operation)
125
125
  if style == :predicate
126
126
  [parenthesized_source(numeric), REPLACEMENTS.invert[operation.to_s]].join('.')
127
+ elsif negated?(node)
128
+ "(#{numeric.source} #{REPLACEMENTS[operation.to_s]} 0)"
127
129
  else
128
130
  [numeric.source, REPLACEMENTS[operation.to_s], 0].join(' ')
129
131
  end
@@ -157,6 +159,12 @@ module RuboCop
157
159
  end
158
160
  end
159
161
 
162
+ def negated?(node)
163
+ return false unless (parent = node.parent)
164
+
165
+ parent.send_type? && parent.method?(:!)
166
+ end
167
+
160
168
  # @!method predicate(node)
161
169
  def_node_matcher :predicate, <<~PATTERN
162
170
  (send $(...) ${:zero? :positive? :negative?})
@@ -46,15 +46,17 @@ module RuboCop
46
46
  private
47
47
 
48
48
  def check_method_node(node)
49
- return unless preferred_method(node)
49
+ return unless preferred_method?(node)
50
50
 
51
51
  message = message(node)
52
52
  add_offense(node.loc.selector, message: message) do |corrector|
53
- corrector.replace(node.loc.selector, style.to_s)
53
+ prefer = style == :then && node.receiver.nil? ? 'self.then' : style
54
+
55
+ corrector.replace(node.loc.selector, prefer)
54
56
  end
55
57
  end
56
58
 
57
- def preferred_method(node)
59
+ def preferred_method?(node)
58
60
  case style
59
61
  when :then
60
62
  node.method?(:yield_self)
@@ -75,7 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  def always_multiline?
78
- @config.for_cop('Style/OneLineConditional')['AlwaysCorrectToMultiline']
78
+ cop_config['AlwaysCorrectToMultiline']
79
79
  end
80
80
 
81
81
  def cannot_replace_to_ternary?(node)
@@ -142,8 +142,8 @@ module RuboCop
142
142
  @assignments = assignments
143
143
  end
144
144
 
145
- def tsort_each_node(&block)
146
- @assignments.each(&block)
145
+ def tsort_each_node(...)
146
+ @assignments.each(...)
147
147
  end
148
148
 
149
149
  def tsort_each_child(assignment)
@@ -289,9 +289,7 @@ module RuboCop
289
289
  private
290
290
 
291
291
  def modifier_range(node)
292
- Parser::Source::Range.new(node.source_range.source_buffer,
293
- node.loc.keyword.begin_pos,
294
- node.source_range.end_pos)
292
+ node.loc.keyword.join(node.source_range.end)
295
293
  end
296
294
  end
297
295
  end
@@ -81,6 +81,7 @@ module RuboCop
81
81
  cond = node.condition
82
82
 
83
83
  control_op_condition(cond) do |first_child, rest_children|
84
+ return if require_parentheses?(node, first_child)
84
85
  return if semicolon_separated_expressions?(first_child, rest_children)
85
86
  return if modifier_op?(first_child)
86
87
  return if parens_allowed?(cond)
@@ -92,6 +93,13 @@ module RuboCop
92
93
  end
93
94
  end
94
95
 
96
+ def require_parentheses?(node, condition_body)
97
+ return false if !node.while_type? && !node.until_type?
98
+ return false if !condition_body.block_type? && !condition_body.numblock_type?
99
+
100
+ condition_body.send_node.block_literal? && condition_body.keywords?
101
+ end
102
+
95
103
  def semicolon_separated_expressions?(first_exp, rest_exps)
96
104
  return false unless (second_exp = rest_exps.first)
97
105
 
@@ -9,7 +9,7 @@ module RuboCop
9
9
  #
10
10
  # String interpolation is always kept in double quotes.
11
11
  #
12
- # Note: `Lint/SymbolConversion` can be used in parallel to ensure that symbols
12
+ # NOTE: `Lint/SymbolConversion` can be used in parallel to ensure that symbols
13
13
  # are not quoted that don't need to be. This cop is for configuring the quoting
14
14
  # style to use for symbols that require quotes.
15
15
  #
@@ -16,6 +16,9 @@ module RuboCop
16
16
  # The exploded style has an `AllowedCompactTypes` configuration
17
17
  # option that takes an Array of exception name Strings.
18
18
  #
19
+ # @safety
20
+ # This cop is unsafe because `raise Foo` calls `Foo.exception`, not `Foo.new`.
21
+ #
19
22
  # @example EnforcedStyle: exploded (default)
20
23
  # # bad
21
24
  # raise StandardError.new('message')
@@ -77,7 +80,7 @@ module RuboCop
77
80
 
78
81
  def correction_exploded_to_compact(node)
79
82
  exception_node, *message_nodes = *node.arguments
80
- return node.source if message_nodes.size > 1
83
+ return if message_nodes.size > 1
81
84
 
82
85
  argument = message_nodes.first.source
83
86
  exception_class = exception_node.receiver&.source || exception_node.source
@@ -81,14 +81,20 @@ module RuboCop
81
81
  redundant_argument = redundant_arg_for_method(node.method_name.to_s)
82
82
  return false if redundant_argument.nil?
83
83
 
84
- node.first_argument == redundant_argument
84
+ target_argument = if node.first_argument.respond_to?(:value)
85
+ node.first_argument.value
86
+ else
87
+ node.first_argument
88
+ end
89
+
90
+ argument_matched?(target_argument, redundant_argument)
85
91
  end
86
92
 
87
93
  def redundant_arg_for_method(method_name)
88
94
  arg = cop_config['Methods'].fetch(method_name) { return }
89
95
 
90
96
  @mem ||= {}
91
- @mem[method_name] ||= parse(arg.inspect).ast
97
+ @mem[method_name] ||= arg.inspect
92
98
  end
93
99
 
94
100
  def argument_range(node)
@@ -98,6 +104,23 @@ module RuboCop
98
104
  range_with_surrounding_space(node.first_argument.source_range, newlines: false)
99
105
  end
100
106
  end
107
+
108
+ def argument_matched?(target_argument, redundant_argument)
109
+ argument = if target_argument.is_a?(AST::Node)
110
+ target_argument.source
111
+ elsif exclude_cntrl_character?(target_argument, redundant_argument)
112
+ target_argument.inspect
113
+ else
114
+ target_argument.to_s
115
+ end
116
+
117
+ argument == redundant_argument
118
+ end
119
+
120
+ def exclude_cntrl_character?(target_argument, redundant_argument)
121
+ !target_argument.to_s.sub(/\A'/, '"').sub(/'\z/, '"').match?(/[[:cntrl:]]/) ||
122
+ !redundant_argument.match?(/[[:cntrl:]]/)
123
+ end
101
124
  end
102
125
  end
103
126
  end
@@ -54,12 +54,14 @@ module RuboCop
54
54
 
55
55
  private
56
56
 
57
+ # rubocop:disable Metrics/CyclomaticComplexity
57
58
  def check_branch(node)
58
59
  return unless node
59
60
 
60
61
  case node.type
61
- when :case then check_case_node(node)
62
- when :if then check_if_node(node)
62
+ when :case then check_case_node(node)
63
+ when :case_match then check_case_match_node(node)
64
+ when :if then check_if_node(node)
63
65
  when :rescue, :resbody
64
66
  check_rescue_node(node)
65
67
  when :ensure then check_ensure_node(node)
@@ -67,12 +69,18 @@ module RuboCop
67
69
  check_begin_node(node)
68
70
  end
69
71
  end
72
+ # rubocop:enable Metrics/CyclomaticComplexity
70
73
 
71
74
  def check_case_node(node)
72
75
  node.when_branches.each { |when_node| check_branch(when_node.body) }
73
76
  check_branch(node.else_branch)
74
77
  end
75
78
 
79
+ def check_case_match_node(node)
80
+ node.in_pattern_branches.each { |in_pattern_node| check_branch(in_pattern_node.body) }
81
+ check_branch(node.else_branch)
82
+ end
83
+
76
84
  def check_if_node(node)
77
85
  return if node.modifier_form? || node.ternary?
78
86
 
@@ -75,7 +75,7 @@ module RuboCop
75
75
 
76
76
  def on_def(node)
77
77
  return unless node.body&.kwbegin_type?
78
- return if node.endless? && !node.body.children.one?
78
+ return if node.endless?
79
79
 
80
80
  register_offense(node.body)
81
81
  end
@@ -12,7 +12,6 @@ module RuboCop
12
12
  # # good
13
13
  # a = b || c
14
14
  #
15
- # @example
16
15
  # # bad
17
16
  # if b
18
17
  # b
@@ -18,14 +18,15 @@ module RuboCop
18
18
  extend AutoCorrector
19
19
 
20
20
  MSG = 'Remove the redundant current directory path.'
21
+ RESTRICT_ON_SEND = %i[require_relative].freeze
21
22
  CURRENT_DIRECTORY_PATH = './'
22
23
 
23
24
  def on_send(node)
24
- return unless node.method?(:require_relative)
25
- return unless node.first_argument.str_content&.start_with?(CURRENT_DIRECTORY_PATH)
26
- return unless (index = node.first_argument.source.index(CURRENT_DIRECTORY_PATH))
25
+ return unless (first_argument = node.first_argument)
26
+ return unless first_argument.str_content&.start_with?(CURRENT_DIRECTORY_PATH)
27
+ return unless (index = first_argument.source.index(CURRENT_DIRECTORY_PATH))
27
28
 
28
- begin_pos = node.first_argument.source_range.begin.begin_pos + index
29
+ begin_pos = first_argument.source_range.begin.begin_pos + index
29
30
  range = range_between(begin_pos, begin_pos + 2)
30
31
 
31
32
  add_offense(range) do |corrector|
@@ -56,6 +56,7 @@ module RuboCop
56
56
  end
57
57
  end
58
58
  end
59
+ alias on_csend on_send
59
60
 
60
61
  private
61
62
 
@@ -64,7 +65,7 @@ module RuboCop
64
65
  return if node.last_argument&.block_pass_type?
65
66
 
66
67
  if node.method?(:each) && !node.parent&.block_type?
67
- ancestor_node = node.each_ancestor(:send).detect do |ancestor|
68
+ ancestor_node = node.each_ancestor(:send, :csend).detect do |ancestor|
68
69
  ancestor.receiver == node &&
69
70
  (RESTRICT_ON_SEND.include?(ancestor.method_name) || ancestor.method?(:reverse_each))
70
71
  end
@@ -83,10 +84,12 @@ module RuboCop
83
84
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
84
85
 
85
86
  def range(node)
86
- if node.method?(:each)
87
- node.loc.dot.join(node.loc.selector)
87
+ return node.selector unless node.method?(:each)
88
+
89
+ if node.parent&.call_type?
90
+ node.selector.join(node.parent.loc.dot)
88
91
  else
89
- node.loc.selector
92
+ node.loc.dot.join(node.selector)
90
93
  end
91
94
  end
92
95
 
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks for the presence of superfluous `.rb` extension in
7
7
  # the filename provided to `require` and `require_relative`.
8
8
  #
9
- # Note: If the extension is omitted, Ruby tries adding '.rb', '.so',
9
+ # NOTE: If the extension is omitted, Ruby tries adding '.rb', '.so',
10
10
  # and so on to the name until found. If the file named cannot be found,
11
11
  # a `LoadError` will be raised.
12
12
  # There is an edge case where `foo.so` file is loaded instead of a `LoadError`
@@ -79,7 +79,7 @@ module RuboCop
79
79
  private_constant :REPLACEMENT_METHODS
80
80
 
81
81
  def on_send(node)
82
- return if node.arguments? || node.block_node
82
+ return if node.arguments? || node.block_literal?
83
83
 
84
84
  select_predicate?(node) do |select_node, filter_method|
85
85
  return if RAILS_METHODS.include?(filter_method) && !active_support_extensions_enabled?
@@ -74,6 +74,7 @@ module RuboCop
74
74
  kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
75
75
  tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
76
76
  ].freeze
77
+ ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
77
78
 
78
79
  def on_new_investigation
79
80
  return unless processed_source.ast
@@ -94,7 +95,8 @@ module RuboCop
94
95
  !ends_with_backslash_without_comment?(range.source_line) ||
95
96
  string_concatenation?(range.source_line) ||
96
97
  start_with_arithmetic_operator?(processed_source[range.line]) ||
97
- inside_string_literal_or_method_with_argument?(range)
98
+ inside_string_literal_or_method_with_argument?(range) ||
99
+ leading_dot_method_chain_with_blank_line?(range)
98
100
  end
99
101
 
100
102
  def ends_with_backslash_without_comment?(source_line)
@@ -113,6 +115,12 @@ module RuboCop
113
115
  end
114
116
  end
115
117
 
118
+ def leading_dot_method_chain_with_blank_line?(range)
119
+ return false unless range.source_line.strip.start_with?('.', '&.')
120
+
121
+ processed_source[range.line].strip.empty?
122
+ end
123
+
116
124
  def redundant_line_continuation?(range)
117
125
  return true unless (node = find_node_for_line(range.line))
118
126
  return false if argument_newline?(node)
@@ -130,10 +138,16 @@ module RuboCop
130
138
  # do_something \
131
139
  # argument
132
140
  def method_with_argument?(current_token, next_token)
133
- current_token.type == :tIDENTIFIER && ARGUMENT_TYPES.include?(next_token.type)
141
+ return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
142
+
143
+ ARGUMENT_TYPES.include?(next_token.type)
134
144
  end
135
145
 
146
+ # rubocop:disable Metrics/AbcSize
136
147
  def argument_newline?(node)
148
+ node = node.to_a.last if node.assignment?
149
+ return false if node.parenthesized_call?
150
+
137
151
  node = node.children.first if node.root? && node.begin_type?
138
152
 
139
153
  if argument_is_method?(node)
@@ -144,6 +158,7 @@ module RuboCop
144
158
  node.loc.selector.line != node.first_argument.loc.line
145
159
  end
146
160
  end
161
+ # rubocop:enable Metrics/AbcSize
147
162
 
148
163
  def find_node_for_line(line)
149
164
  processed_source.ast.each_node do |node|
@@ -53,8 +53,8 @@ module RuboCop
53
53
  def ignore_syntax?(node)
54
54
  return false unless (parent = node.parent)
55
55
 
56
- parent.while_post_type? || parent.until_post_type? ||
57
- like_method_argument_parentheses?(parent)
56
+ parent.while_post_type? || parent.until_post_type? || parent.match_with_lvasgn_type? ||
57
+ like_method_argument_parentheses?(parent) || multiline_control_flow_statements?(node)
58
58
  end
59
59
 
60
60
  def allowed_expression?(node)
@@ -104,6 +104,13 @@ module RuboCop
104
104
  !node.arithmetic_operation? && node.first_argument.begin_type?
105
105
  end
106
106
 
107
+ def multiline_control_flow_statements?(node)
108
+ return false unless (parent = node.parent)
109
+ return false if parent.single_line?
110
+
111
+ parent.return_type? || parent.next_type? || parent.break_type?
112
+ end
113
+
107
114
  def empty_parentheses?(node)
108
115
  # Don't flag `()`
109
116
  node.children.empty?
@@ -150,6 +157,8 @@ module RuboCop
150
157
  return if begin_node.chained?
151
158
 
152
159
  if node.and_type? || node.or_type?
160
+ return if node.semantic_operator? && begin_node.parent
161
+ return if node.multiline? && allow_in_multiline_conditions?
153
162
  return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
154
163
  return if begin_node.parent&.if_type? && begin_node.parent&.ternary?
155
164
 
@@ -165,6 +174,13 @@ module RuboCop
165
174
  # @!method interpolation?(node)
166
175
  def_node_matcher :interpolation?, '[^begin ^^dstr]'
167
176
 
177
+ def allow_in_multiline_conditions?
178
+ parentheses_around_condition_config = config.for_cop('Style/ParenthesesAroundCondition')
179
+ return false unless parentheses_around_condition_config['Enabled']
180
+
181
+ !!parentheses_around_condition_config['AllowInMultilineConditions']
182
+ end
183
+
168
184
  def check_send(begin_node, node)
169
185
  return check_unary(begin_node, node) if node.unary_operation?
170
186
 
@@ -53,7 +53,7 @@ module RuboCop
53
53
  return if interpolated_quotes?(node) || allowed_percent_q?(node)
54
54
 
55
55
  add_offense(node) do |corrector|
56
- delimiter = /^%Q[^"]+$|'/.match?(node.source) ? QUOTE : SINGLE_QUOTE
56
+ delimiter = /\A%Q[^"]+\z|'/.match?(node.source) ? QUOTE : SINGLE_QUOTE
57
57
 
58
58
  corrector.replace(node.loc.begin, delimiter)
59
59
  corrector.replace(node.loc.end, delimiter)
@@ -95,30 +95,14 @@ module RuboCop
95
95
  delimiters.include?(char)
96
96
  end
97
97
 
98
- if Gem::Version.new(Regexp::Parser::VERSION) >= Gem::Version.new('2.0')
99
- def each_escape(node)
100
- node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
101
- yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
102
-
103
- if expr.type == :set
104
- char_class_depth + (event == :enter ? 1 : -1)
105
- else
106
- char_class_depth
107
- end
108
- end
109
- end
110
- # Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
111
- # It's for compatibility with regexp_parser 1.8 and will never be maintained.
112
- else
113
- def each_escape(node)
114
- node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
115
- yield(expr.text[1], expr.start_index, !char_class_depth.zero?) if expr.type == :escape
116
-
117
- if expr.type == :set
118
- char_class_depth + (event == :enter ? 1 : -1)
119
- else
120
- char_class_depth
121
- end
98
+ def each_escape(node)
99
+ node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
100
+ yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
101
+
102
+ if expr.type == :set
103
+ char_class_depth + (event == :enter ? 1 : -1)
104
+ else
105
+ char_class_depth
122
106
  end
123
107
  end
124
108
  end
@@ -113,6 +113,7 @@ module RuboCop
113
113
  case node.type
114
114
  when :return then check_return_node(node)
115
115
  when :case then check_case_node(node)
116
+ when :case_match then check_case_match_node(node)
116
117
  when :if then check_if_node(node)
117
118
  when :rescue then check_rescue_node(node)
118
119
  when :resbody then check_resbody_node(node)
@@ -140,6 +141,11 @@ module RuboCop
140
141
  check_branch(node.else_branch)
141
142
  end
142
143
 
144
+ def check_case_match_node(node)
145
+ node.in_pattern_branches.each { |in_pattern_node| check_branch(in_pattern_node.body) }
146
+ check_branch(node.else_branch)
147
+ end
148
+
143
149
  def check_if_node(node)
144
150
  return if node.ternary?
145
151
 
@@ -131,7 +131,7 @@ module RuboCop
131
131
  end
132
132
 
133
133
  def in_same_section?(node1, node2)
134
- !node1.source_range.with(end_pos: node2.source_range.end_pos).source.include?("\n\n")
134
+ !node1.source_range.join(node2.source_range.end).source.include?("\n\n")
135
135
  end
136
136
  end
137
137
  end
@@ -110,9 +110,7 @@ module RuboCop
110
110
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
111
111
 
112
112
  def source_range(shuffle_node, node)
113
- Parser::Source::Range.new(shuffle_node.source_range.source_buffer,
114
- shuffle_node.loc.selector.begin_pos,
115
- node.source_range.end_pos)
113
+ shuffle_node.loc.selector.join(node.source_range.end)
116
114
  end
117
115
 
118
116
  def message(shuffle_arg, method, method_args, range)
@@ -7,12 +7,12 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  # # bad
10
- # Foo.send(:bar)
11
- # quuz.send(:fred)
10
+ # Foo.send(bar)
11
+ # quuz.send(fred)
12
12
  #
13
13
  # # good
14
- # Foo.__send__(:bar)
15
- # quuz.public_send(:fred)
14
+ # Foo.__send__(bar)
15
+ # quuz.public_send(fred)
16
16
  class Send < Base
17
17
  MSG = 'Prefer `Object#__send__` or `Object#public_send` to `send`.'
18
18
  RESTRICT_ON_SEND = %i[send].freeze
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Detects the use of the `public_send` method with a literal method name argument.
7
+ # Since the `send` method can be used to call private methods, by default,
8
+ # only the `public_send` method is detected.
9
+ #
10
+ # NOTE: Writer methods with names ending in `=` are always permitted because their
11
+ # behavior differs as follows:
12
+ #
13
+ # [source,ruby]
14
+ # ----
15
+ # def foo=(foo)
16
+ # @foo = foo
17
+ # 42
18
+ # end
19
+ #
20
+ # self.foo = 1 # => 1
21
+ # send(:foo=, 1) # => 42
22
+ # ----
23
+ #
24
+ # @safety
25
+ # This cop is not safe because it can incorrectly detect based on the receiver.
26
+ # Additionally, when `AllowSend` is set to `true`, it cannot determine whether
27
+ # the `send` method being detected is calling a private method.
28
+ #
29
+ # @example
30
+ # # bad
31
+ # obj.public_send(:method_name)
32
+ # obj.public_send('method_name')
33
+ #
34
+ # # good
35
+ # obj.method_name
36
+ #
37
+ # @example AllowSend: true (default)
38
+ # # good
39
+ # obj.send(:method_name)
40
+ # obj.send('method_name')
41
+ # obj.__send__(:method_name)
42
+ # obj.__send__('method_name')
43
+ #
44
+ # @example AllowSend: false
45
+ # # bad
46
+ # obj.send(:method_name)
47
+ # obj.send('method_name')
48
+ # obj.__send__(:method_name)
49
+ # obj.__send__('method_name')
50
+ #
51
+ # # good
52
+ # obj.method_name
53
+ #
54
+ class SendWithLiteralMethodName < Base
55
+ extend AutoCorrector
56
+
57
+ MSG = 'Use `%<method_name>s` method call directly instead.'
58
+ RESTRICT_ON_SEND = %i[public_send send __send__].freeze
59
+ STATIC_METHOD_NAME_NODE_TYPES = %i[sym str].freeze
60
+ METHOD_NAME_PATTERN = /\A[a-zA-Z_][a-zA-Z0-9_]*[!?]?\z/.freeze
61
+ RESERVED_WORDS = %i[
62
+ BEGIN END alias and begin break case class def defined? do else elsif end ensure
63
+ false for if in module next nil not or redo rescue retry return self super then true
64
+ undef unless until when while yield
65
+ ].freeze
66
+
67
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
68
+ def on_send(node)
69
+ return if allow_send? && !node.method?(:public_send)
70
+ return unless (first_argument = node.first_argument)
71
+ return unless STATIC_METHOD_NAME_NODE_TYPES.include?(first_argument.type)
72
+
73
+ offense_range = offense_range(node)
74
+ method_name = first_argument.value
75
+ return if !METHOD_NAME_PATTERN.match?(method_name) || RESERVED_WORDS.include?(method_name)
76
+
77
+ add_offense(offense_range, message: format(MSG, method_name: method_name)) do |corrector|
78
+ if node.arguments.one?
79
+ corrector.replace(offense_range, method_name)
80
+ else
81
+ corrector.replace(node.loc.selector, method_name)
82
+ corrector.remove(removal_argument_range(first_argument, node.arguments[1]))
83
+ end
84
+ end
85
+ end
86
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
87
+
88
+ private
89
+
90
+ def allow_send?
91
+ !!cop_config['AllowSend']
92
+ end
93
+
94
+ def offense_range(node)
95
+ node.loc.selector.join(node.source_range.end)
96
+ end
97
+
98
+ def removal_argument_range(first_argument, second_argument)
99
+ first_argument.source_range.begin.join(second_argument.source_range.begin)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end