sonicop 26.8.112 → 26.8.113

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 (343) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +11 -11
  3. data/Cargo.toml +4 -4
  4. data/README.ja.md +36 -23
  5. data/README.md +38 -26
  6. data/lib/sonicop/version.rb +1 -1
  7. data/src/config/inheritance.rs +45 -3
  8. data/src/engine.rs +11 -7
  9. data/src/lib.rs +1 -0
  10. data/src/nul_bytes.rs +2 -6
  11. data/src/parser.rs +37 -0
  12. data/src/profile.rs +13 -1
  13. data/src/rules/bundler/duplicated_group.rs +3 -2
  14. data/src/rules/bundler/gem_comment.rs +5 -4
  15. data/src/rules/gemspec/attribute_assignment.rs +4 -3
  16. data/src/rules/gemspec/deprecated_attribute_assignment.rs +7 -6
  17. data/src/rules/gemspec/duplicated_assignment.rs +4 -3
  18. data/src/rules/gemspec/require_mfa.rs +10 -9
  19. data/src/rules/gemspec/required_ruby_version.rs +3 -2
  20. data/src/rules/gemspec/support.rs +3 -2
  21. data/src/rules/layout/array_alignment.rs +1 -2
  22. data/src/rules/layout/block_end_newline.rs +5 -5
  23. data/src/rules/layout/class_structure.rs +5 -3
  24. data/src/rules/layout/closing_heredoc_indentation.rs +4 -3
  25. data/src/rules/layout/closing_parenthesis_indentation.rs +1 -2
  26. data/src/rules/layout/condition_position.rs +3 -2
  27. data/src/rules/layout/def_end_alignment.rs +2 -2
  28. data/src/rules/layout/dot_position.rs +1 -2
  29. data/src/rules/layout/empty_line_after_guard_clause.rs +3 -6
  30. data/src/rules/layout/empty_line_after_multiline_condition.rs +5 -5
  31. data/src/rules/layout/empty_lines_around_access_modifier.rs +2 -3
  32. data/src/rules/layout/empty_lines_around_arguments.rs +4 -4
  33. data/src/rules/layout/empty_lines_around_exception_handling_keywords.rs +1 -2
  34. data/src/rules/layout/empty_lines_around_method_body.rs +3 -2
  35. data/src/rules/layout/end_alignment.rs +2 -2
  36. data/src/rules/layout/extra_spacing.rs +7 -6
  37. data/src/rules/layout/first_array_element_indentation.rs +1 -2
  38. data/src/rules/layout/first_hash_element_indentation.rs +8 -6
  39. data/src/rules/layout/hash_alignment.rs +4 -4
  40. data/src/rules/layout/heredoc_argument_closing_parenthesis.rs +6 -5
  41. data/src/rules/layout/heredoc_indentation.rs +4 -3
  42. data/src/rules/layout/indentation_style.rs +4 -3
  43. data/src/rules/layout/indentation_width.rs +14 -13
  44. data/src/rules/layout/line_continuation_leading_space.rs +4 -3
  45. data/src/rules/layout/line_continuation_spacing.rs +2 -2
  46. data/src/rules/layout/line_length.rs +101 -57
  47. data/src/rules/layout/multiline_assignment_layout.rs +4 -3
  48. data/src/rules/layout/multiline_block_layout.rs +1 -2
  49. data/src/rules/layout/multiline_expression.rs +60 -31
  50. data/src/rules/layout/multiline_hash_brace_layout.rs +4 -3
  51. data/src/rules/layout/multiline_method_call_indentation.rs +1 -1
  52. data/src/rules/layout/multiline_operation_indentation.rs +3 -3
  53. data/src/rules/layout/redundant_line_break.rs +3 -2
  54. data/src/rules/layout/single_line_block_chain.rs +4 -3
  55. data/src/rules/layout/space_around_block_parameters.rs +1 -2
  56. data/src/rules/layout/space_around_equals_in_parameter_default.rs +1 -2
  57. data/src/rules/layout/space_around_operators.rs +1 -2
  58. data/src/rules/layout/space_before_brackets.rs +6 -5
  59. data/src/rules/layout/space_before_comma.rs +3 -2
  60. data/src/rules/layout/space_inside_range_literal.rs +8 -6
  61. data/src/rules/layout/support.rs +9 -7
  62. data/src/rules/layout/tokens.rs +15 -6
  63. data/src/rules/lint/access_modifier.rs +19 -10
  64. data/src/rules/lint/ambiguity.rs +2 -2
  65. data/src/rules/lint/ambiguous_block_association.rs +7 -10
  66. data/src/rules/lint/ambiguous_regexp_literal.rs +7 -5
  67. data/src/rules/lint/array_literal_in_regexp.rs +4 -3
  68. data/src/rules/lint/assignment_in_condition.rs +3 -2
  69. data/src/rules/lint/blocks.rs +2 -1
  70. data/src/rules/lint/boolean_symbol.rs +4 -4
  71. data/src/rules/lint/constant_definition_in_block.rs +1 -2
  72. data/src/rules/lint/constant_reassignment.rs +2 -1
  73. data/src/rules/lint/deprecated_open_ssl_constant.rs +1 -2
  74. data/src/rules/lint/disjunctive_assignment_in_constructor.rs +2 -2
  75. data/src/rules/lint/duplicate_branch.rs +6 -5
  76. data/src/rules/lint/duplicate_case_condition.rs +5 -5
  77. data/src/rules/lint/duplicate_hash_key.rs +4 -3
  78. data/src/rules/lint/duplicate_match_pattern.rs +7 -5
  79. data/src/rules/lint/duplicate_methods.rs +4 -3
  80. data/src/rules/lint/duplicate_require.rs +1 -2
  81. data/src/rules/lint/duplicate_set_element.rs +3 -2
  82. data/src/rules/lint/empty_conditional_body.rs +4 -3
  83. data/src/rules/lint/empty_in_pattern.rs +3 -2
  84. data/src/rules/lint/empty_when.rs +4 -4
  85. data/src/rules/lint/ensure_return.rs +3 -2
  86. data/src/rules/lint/float_comparison.rs +8 -6
  87. data/src/rules/lint/format_parameter_mismatch.rs +4 -3
  88. data/src/rules/lint/hash_compare_by_identity.rs +5 -4
  89. data/src/rules/lint/heredoc_method_call_position.rs +3 -2
  90. data/src/rules/lint/implicit_string_concatenation.rs +7 -5
  91. data/src/rules/lint/ineffective_access_modifier.rs +5 -4
  92. data/src/rules/lint/inherit_exception.rs +4 -3
  93. data/src/rules/lint/literal_as_condition.rs +5 -3
  94. data/src/rules/lint/literal_assignment_in_condition.rs +4 -3
  95. data/src/rules/lint/literal_in_interpolation.rs +5 -5
  96. data/src/rules/lint/literals.rs +10 -8
  97. data/src/rules/lint/no_return_in_begin_end_blocks.rs +2 -2
  98. data/src/rules/lint/node_equality.rs +8 -5
  99. data/src/rules/lint/non_atomic_file_operation.rs +1 -1
  100. data/src/rules/lint/non_deterministic_require_order.rs +5 -3
  101. data/src/rules/lint/non_local_exit_from_iterator.rs +3 -2
  102. data/src/rules/lint/number_conversion.rs +1 -1
  103. data/src/rules/lint/out_of_range_regexp_ref.rs +6 -4
  104. data/src/rules/lint/redundant_dir_glob_sort.rs +1 -2
  105. data/src/rules/lint/redundant_safe_navigation.rs +4 -3
  106. data/src/rules/lint/redundant_splat_expansion.rs +4 -2
  107. data/src/rules/lint/redundant_string_coercion.rs +3 -2
  108. data/src/rules/lint/regexp_source.rs +2 -2
  109. data/src/rules/lint/require_range_parentheses.rs +5 -5
  110. data/src/rules/lint/rescue_exception.rs +4 -3
  111. data/src/rules/lint/rescue_type.rs +3 -2
  112. data/src/rules/lint/return_in_void_context.rs +2 -2
  113. data/src/rules/lint/safe_navigation_chain.rs +3 -2
  114. data/src/rules/lint/self_assignment.rs +3 -2
  115. data/src/rules/lint/shadowed_argument.rs +2 -2
  116. data/src/rules/lint/shadowed_exception.rs +2 -2
  117. data/src/rules/lint/suppressed_exception_in_number_conversion.rs +4 -3
  118. data/src/rules/lint/symbol_conversion.rs +6 -5
  119. data/src/rules/lint/syntax.rs +4 -3
  120. data/src/rules/lint/triple_quotes.rs +3 -2
  121. data/src/rules/lint/unescaped_bracket_in_regexp.rs +1 -1
  122. data/src/rules/lint/unexpected_block_arity.rs +3 -2
  123. data/src/rules/lint/unmodified_reduce_accumulator.rs +7 -6
  124. data/src/rules/lint/unreachable_pattern_branch.rs +4 -4
  125. data/src/rules/lint/unused_block_argument.rs +2 -2
  126. data/src/rules/lint/unused_method_argument.rs +1 -2
  127. data/src/rules/lint/useless_assignment.rs +3 -2
  128. data/src/rules/lint/useless_constant_scoping.rs +3 -2
  129. data/src/rules/lint/useless_else_without_rescue.rs +4 -3
  130. data/src/rules/lint/useless_rescue.rs +5 -4
  131. data/src/rules/lint/useless_ruby2_keywords.rs +2 -1
  132. data/src/rules/lint/useless_setter_call.rs +5 -4
  133. data/src/rules/lint/useless_times.rs +4 -3
  134. data/src/rules/lint/variable_force.rs +146 -100
  135. data/src/rules/lint/void.rs +5 -4
  136. data/src/rules/metrics/block_nesting.rs +1 -2
  137. data/src/rules/metrics/collection_literal_length.rs +2 -1
  138. data/src/rules/metrics/complexity.rs +18 -13
  139. data/src/rules/metrics/fragments.rs +10 -14
  140. data/src/rules/metrics/locals.rs +23 -12
  141. data/src/rules/metrics/parameter_lists.rs +7 -6
  142. data/src/rules/metrics/support.rs +1 -1
  143. data/src/rules/mod.rs +464 -62
  144. data/src/rules/naming/ascii_identifiers.rs +3 -3
  145. data/src/rules/naming/block_forwarding.rs +9 -8
  146. data/src/rules/naming/constant_name.rs +1 -1
  147. data/src/rules/naming/predicate_method.rs +6 -5
  148. data/src/rules/naming/predicate_prefix.rs +10 -8
  149. data/src/rules/naming/rescued_exceptions_variable_name.rs +8 -6
  150. data/src/rules/naming/support.rs +7 -5
  151. data/src/rules/naming/variable_number.rs +4 -4
  152. data/src/rules/node_ext.rs +1 -1
  153. data/src/rules/ruby_literal.rs +3 -2
  154. data/src/rules/security/compound_hash.rs +3 -2
  155. data/src/rules/security/open.rs +5 -4
  156. data/src/rules/send_node.rs +134 -0
  157. data/src/rules/single_line.rs +4 -4
  158. data/src/rules/style/access_modifier_declarations.rs +1 -1
  159. data/src/rules/style/alias.rs +1 -2
  160. data/src/rules/style/and_or.rs +2 -2
  161. data/src/rules/style/arguments_forwarding.rs +5 -5
  162. data/src/rules/style/array_coercion.rs +5 -5
  163. data/src/rules/style/array_first_last.rs +3 -3
  164. data/src/rules/style/array_intersect.rs +2 -2
  165. data/src/rules/style/array_intersect_with_single_element.rs +1 -1
  166. data/src/rules/style/attr.rs +1 -1
  167. data/src/rules/style/auto_resource_cleanup.rs +1 -1
  168. data/src/rules/style/bitwise_predicate.rs +2 -2
  169. data/src/rules/style/block_args.rs +1 -1
  170. data/src/rules/style/block_delimiters.rs +7 -6
  171. data/src/rules/style/case_equality.rs +3 -2
  172. data/src/rules/style/case_like_if.rs +1 -1
  173. data/src/rules/style/class_and_module_children.rs +7 -5
  174. data/src/rules/style/class_methods.rs +1 -1
  175. data/src/rules/style/collection_compact.rs +4 -4
  176. data/src/rules/style/combinable_defined.rs +2 -2
  177. data/src/rules/style/combinable_loops.rs +1 -1
  178. data/src/rules/style/comparable_clamp.rs +2 -2
  179. data/src/rules/style/concat_array_literals.rs +3 -3
  180. data/src/rules/style/conditional.rs +8 -1
  181. data/src/rules/style/constant_visibility.rs +3 -3
  182. data/src/rules/style/copyright.rs +1 -1
  183. data/src/rules/style/data_inheritance.rs +1 -1
  184. data/src/rules/style/def_with_parentheses.rs +1 -1
  185. data/src/rules/style/document_dynamic_eval_definition.rs +1 -1
  186. data/src/rules/style/documentation.rs +1 -1
  187. data/src/rules/style/each_for_simple_loop.rs +1 -1
  188. data/src/rules/style/each_with_object.rs +4 -4
  189. data/src/rules/style/empty_block_parameter.rs +1 -1
  190. data/src/rules/style/empty_case_condition.rs +6 -6
  191. data/src/rules/style/empty_class_definition.rs +1 -1
  192. data/src/rules/style/empty_else.rs +1 -1
  193. data/src/rules/style/empty_heredoc.rs +1 -1
  194. data/src/rules/style/empty_lambda_parameter.rs +1 -1
  195. data/src/rules/style/empty_literal.rs +2 -2
  196. data/src/rules/style/empty_method.rs +1 -1
  197. data/src/rules/style/empty_string_inside_interpolation.rs +1 -1
  198. data/src/rules/style/endless.rs +1 -1
  199. data/src/rules/style/env_home.rs +1 -1
  200. data/src/rules/style/even_odd.rs +1 -1
  201. data/src/rules/style/exact_regexp_match.rs +1 -1
  202. data/src/rules/style/expand_path_arguments.rs +3 -3
  203. data/src/rules/style/explicit_block_argument.rs +3 -3
  204. data/src/rules/style/file_open_call.rs +3 -3
  205. data/src/rules/style/file_write.rs +1 -1
  206. data/src/rules/style/for.rs +1 -1
  207. data/src/rules/style/format_string.rs +2 -2
  208. data/src/rules/style/format_string_token.rs +6 -6
  209. data/src/rules/style/guard_clause.rs +8 -7
  210. data/src/rules/style/hash_as_last_array_item.rs +4 -4
  211. data/src/rules/style/hash_each_methods.rs +1 -1
  212. data/src/rules/style/hash_like_case.rs +8 -8
  213. data/src/rules/style/hash_lookup_method.rs +3 -3
  214. data/src/rules/style/hash_subset.rs +16 -10
  215. data/src/rules/style/hash_syntax.rs +4 -4
  216. data/src/rules/style/hash_transform.rs +20 -18
  217. data/src/rules/style/identical_conditional_branches.rs +4 -5
  218. data/src/rules/style/if_inside_else.rs +3 -3
  219. data/src/rules/style/if_unless_modifier.rs +13 -14
  220. data/src/rules/style/if_with_boolean_literal_branches.rs +1 -1
  221. data/src/rules/style/if_with_semicolon.rs +1 -1
  222. data/src/rules/style/in_pattern_then.rs +2 -2
  223. data/src/rules/style/inverse_methods.rs +2 -2
  224. data/src/rules/style/invertible_unless_condition.rs +3 -3
  225. data/src/rules/style/it_block_parameter.rs +1 -1
  226. data/src/rules/style/keyword_arguments_merging.rs +2 -2
  227. data/src/rules/style/keyword_parameters_order.rs +1 -1
  228. data/src/rules/style/magic_comment_format.rs +3 -2
  229. data/src/rules/style/map_chain.rs +1 -1
  230. data/src/rules/style/map_compact_with_conditional_block.rs +3 -3
  231. data/src/rules/style/map_into_array.rs +7 -7
  232. data/src/rules/style/map_join.rs +3 -3
  233. data/src/rules/style/method_call_with_args_parentheses.rs +7 -7
  234. data/src/rules/style/method_call_without_args_parentheses.rs +2 -2
  235. data/src/rules/style/method_def_parentheses.rs +2 -3
  236. data/src/rules/style/min_max.rs +3 -3
  237. data/src/rules/style/min_max_comparison.rs +2 -2
  238. data/src/rules/style/missing_else.rs +1 -1
  239. data/src/rules/style/missing_respond_to_missing.rs +1 -1
  240. data/src/rules/style/mixin_grouping.rs +1 -1
  241. data/src/rules/style/multiline_block_chain.rs +2 -2
  242. data/src/rules/style/multiline_if_then.rs +1 -1
  243. data/src/rules/style/multiline_in_pattern_then.rs +1 -1
  244. data/src/rules/style/multiline_method_signature.rs +1 -1
  245. data/src/rules/style/multiline_when_then.rs +2 -2
  246. data/src/rules/style/mutable_constant.rs +3 -3
  247. data/src/rules/style/negated_if.rs +2 -2
  248. data/src/rules/style/negated_if_else_condition.rs +2 -2
  249. data/src/rules/style/negated_while.rs +1 -1
  250. data/src/rules/style/negative_array_index.rs +2 -2
  251. data/src/rules/style/nested_modifier.rs +1 -1
  252. data/src/rules/style/nested_parenthesized_calls.rs +2 -2
  253. data/src/rules/style/nested_ternary_operator.rs +2 -2
  254. data/src/rules/style/next.rs +1 -1
  255. data/src/rules/style/nil_lambda.rs +2 -2
  256. data/src/rules/style/nodes.rs +21 -0
  257. data/src/rules/style/non_nil_check.rs +2 -2
  258. data/src/rules/style/numbered_parameters_limit.rs +2 -2
  259. data/src/rules/style/one_line_conditional.rs +4 -4
  260. data/src/rules/style/optional_arguments.rs +1 -1
  261. data/src/rules/style/or_assignment.rs +1 -1
  262. data/src/rules/style/parallel_assignment.rs +9 -10
  263. data/src/rules/style/parens.rs +1 -1
  264. data/src/rules/style/parentheses_around_condition.rs +3 -3
  265. data/src/rules/style/partition_instead_of_double_select.rs +3 -3
  266. data/src/rules/style/percent.rs +9 -7
  267. data/src/rules/style/percent_q_literals.rs +4 -3
  268. data/src/rules/style/preferred_hash_methods.rs +1 -1
  269. data/src/rules/style/random_with_offset.rs +1 -1
  270. data/src/rules/style/reduce_to_hash.rs +6 -6
  271. data/src/rules/style/redundant_argument.rs +1 -1
  272. data/src/rules/style/redundant_assignment.rs +5 -5
  273. data/src/rules/style/redundant_begin.rs +2 -2
  274. data/src/rules/style/redundant_capital_w.rs +3 -2
  275. data/src/rules/style/redundant_condition.rs +9 -7
  276. data/src/rules/style/redundant_current_directory_in_path.rs +2 -2
  277. data/src/rules/style/redundant_double_splat_hash_braces.rs +4 -4
  278. data/src/rules/style/redundant_file_extension_in_require.rs +2 -2
  279. data/src/rules/style/redundant_format.rs +16 -14
  280. data/src/rules/style/redundant_freeze.rs +1 -1
  281. data/src/rules/style/redundant_heredoc_delimiter_quotes.rs +1 -1
  282. data/src/rules/style/redundant_initialize.rs +2 -2
  283. data/src/rules/style/redundant_interpolation.rs +2 -2
  284. data/src/rules/style/redundant_interpolation_unfreeze.rs +2 -2
  285. data/src/rules/style/redundant_line_continuation.rs +5 -4
  286. data/src/rules/style/redundant_parentheses.rs +16 -15
  287. data/src/rules/style/redundant_regexp_argument.rs +1 -1
  288. data/src/rules/style/redundant_regexp_character_class.rs +4 -3
  289. data/src/rules/style/redundant_regexp_escape.rs +3 -2
  290. data/src/rules/style/redundant_return.rs +1 -2
  291. data/src/rules/style/redundant_self.rs +11 -11
  292. data/src/rules/style/redundant_sort.rs +1 -1
  293. data/src/rules/style/redundant_sort_by.rs +1 -1
  294. data/src/rules/style/redundant_string_escape.rs +6 -5
  295. data/src/rules/style/regexp_literal.rs +3 -2
  296. data/src/rules/style/require_order.rs +2 -2
  297. data/src/rules/style/rescue_modifier.rs +1 -1
  298. data/src/rules/style/rescue_standard_error.rs +1 -1
  299. data/src/rules/style/return_nil.rs +2 -2
  300. data/src/rules/style/return_nil_in_predicate_method_definition.rs +2 -2
  301. data/src/rules/style/safe_navigation.rs +2 -2
  302. data/src/rules/style/sample.rs +3 -3
  303. data/src/rules/style/select_by.rs +2 -2
  304. data/src/rules/style/select_by_range.rs +1 -1
  305. data/src/rules/style/semicolon.rs +5 -4
  306. data/src/rules/style/single_argument_dig.rs +1 -1
  307. data/src/rules/style/single_line_block_params.rs +7 -6
  308. data/src/rules/style/single_line_do_end_block.rs +13 -12
  309. data/src/rules/style/single_line_methods.rs +2 -2
  310. data/src/rules/style/slicing_with_range.rs +2 -2
  311. data/src/rules/style/sole_nested_conditional.rs +4 -4
  312. data/src/rules/style/special_global_vars.rs +2 -2
  313. data/src/rules/style/stabby_lambda_parentheses.rs +1 -1
  314. data/src/rules/style/statement_modifier.rs +3 -2
  315. data/src/rules/style/static_class.rs +1 -1
  316. data/src/rules/style/string_concatenation.rs +9 -7
  317. data/src/rules/style/string_hash_keys.rs +3 -2
  318. data/src/rules/style/string_literals.rs +3 -3
  319. data/src/rules/style/string_literals_in_interpolation.rs +1 -1
  320. data/src/rules/style/struct_inheritance.rs +3 -3
  321. data/src/rules/style/super_arguments.rs +2 -2
  322. data/src/rules/style/super_with_args_parentheses.rs +1 -1
  323. data/src/rules/style/swap_values.rs +1 -1
  324. data/src/rules/style/symbol_array.rs +1 -1
  325. data/src/rules/style/symbol_proc.rs +3 -3
  326. data/src/rules/style/tally_method.rs +4 -4
  327. data/src/rules/style/ternary_parentheses.rs +4 -4
  328. data/src/rules/style/top_level_method_definition.rs +1 -1
  329. data/src/rules/style/trailing_body.rs +1 -1
  330. data/src/rules/style/trailing_comma_in_array_literal.rs +1 -1
  331. data/src/rules/style/trailing_comma_in_hash_literal.rs +1 -1
  332. data/src/rules/style/trailing_method_end_statement.rs +1 -1
  333. data/src/rules/style/trailing_underscore_variable.rs +4 -5
  334. data/src/rules/style/trivial_accessors.rs +2 -2
  335. data/src/rules/style/unless_logical_operators.rs +1 -1
  336. data/src/rules/style/unpack_first.rs +1 -1
  337. data/src/rules/style/when_then.rs +4 -4
  338. data/src/rules/style/while_until_do.rs +1 -1
  339. data/src/rules/style/while_until_modifier.rs +3 -3
  340. data/src/rules/style/word_array.rs +3 -3
  341. data/src/rules/style/yoda_condition.rs +2 -2
  342. data/src/rules/support.rs +33 -8
  343. metadata +2 -1
@@ -3,9 +3,10 @@ use tree_sitter::Node;
3
3
  use crate::diagnostic::{Edit, Offense};
4
4
  use crate::rules::RuleContext;
5
5
  use crate::rules::node_ext::NodeExt;
6
- use crate::rules::push_named_children;
7
- use crate::rules::send_node::{arguments, is_plain_send, named_children, top_level_constant};
6
+ use crate::rules::{push_named_children_in};
7
+ use crate::rules::send_node::{arguments, is_plain_send, top_level_constant};
8
8
  use crate::rules::support::whole_lines;
9
+ use crate::rules::send_node::named_children_of;
9
10
 
10
11
  /// The attributes RubyGems deprecated, in the order upstream tries them. The order is what the cop
11
12
  /// reports, and it is also load-bearing for `+=`: see [`deprecated_attribute`].
@@ -87,7 +88,7 @@ fn is_specification(call: Node<'_>, context: &RuleContext<'_>) -> bool {
87
88
  /// has. A destructured `|(a, b)|` yields `(a, b)`, which no receiver can be written as.
88
89
  fn block_parameter<'a>(call: Node<'_>, context: &'a RuleContext<'_>) -> Option<&'a str> {
89
90
  let parameters = call.field("block")?.field("parameters")?;
90
- let first = named_children(parameters).first().copied()?;
91
+ let first = named_children_of(parameters, context).first().copied()?;
91
92
  Some(context.source.node_text(first))
92
93
  }
93
94
 
@@ -100,15 +101,15 @@ fn block_parameter<'a>(call: Node<'_>, context: &'a RuleContext<'_>) -> Option<&
100
101
  fn first_deprecated<'tree>(
101
102
  call: Node<'tree>,
102
103
  parameter: &str,
103
- context: &RuleContext<'_>,
104
+ context: &'tree RuleContext<'_>,
104
105
  ) -> Option<(Node<'tree>, &'static str)> {
105
106
  let mut stack = Vec::new();
106
- push_named_children(call, &mut stack);
107
+ push_named_children_in(call, context, &mut stack);
107
108
  while let Some(node) = stack.pop() {
108
109
  if let Some(attribute) = deprecated_attribute(node, parameter, context) {
109
110
  return Some((node, attribute));
110
111
  }
111
- push_named_children(node, &mut stack);
112
+ push_named_children_in(node, context, &mut stack);
112
113
  }
113
114
  None
114
115
  }
@@ -2,12 +2,13 @@ use tree_sitter::Node;
2
2
 
3
3
  use crate::diagnostic::Offense;
4
4
  use crate::rules::RuleContext;
5
- use crate::rules::send_node::{first_line_range, is_plain_send, literal_key, named_children};
5
+ use crate::rules::send_node::{first_line_range, is_plain_send, literal_key};
6
6
 
7
7
  use super::support::{
8
8
  enclosing_specification, first_specification_variable, is_literal, is_specification_receiver,
9
9
  };
10
10
  use crate::rules::node_ext::NodeExt;
11
+ use crate::rules::send_node::named_children_of;
11
12
 
12
13
  /// The specification block an assignment was made in, and the target it named. Two assignments
13
14
  /// are duplicates of one another only when both agree.
@@ -30,7 +31,7 @@ pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
30
31
  };
31
32
  // `spec.a, spec.b = 1, 2` assigns through one node per target.
32
33
  let targets = match left.kind_str() {
33
- "left_assignment_list" => named_children(left),
34
+ "left_assignment_list" => named_children_of(left, context),
34
35
  _ => vec![left],
35
36
  };
36
37
  for target in targets {
@@ -92,7 +93,7 @@ fn assignment<'tree>(
92
93
  return None;
93
94
  }
94
95
  let method = context.source.node_text(object.field("method")?);
95
- let indices = named_children(target);
96
+ let indices = named_children_of(target, context);
96
97
  let [index] = indices.get(1..)? else {
97
98
  return None;
98
99
  };
@@ -5,13 +5,14 @@ use tree_sitter::Node;
5
5
  use crate::diagnostic::{Edit, Offense};
6
6
  use crate::rules::RuleContext;
7
7
  use crate::rules::node_ext::NodeExt;
8
- use crate::rules::push_named_children;
8
+ use crate::rules::{push_named_children_in};
9
9
  use crate::rules::send_node::{
10
10
  has_interpolation, is_plain_send, is_string, named_children, pair_key_symbol, string_text,
11
11
  symbol_name,
12
12
  };
13
13
 
14
14
  use super::support::{local_variables, specification_variable};
15
+ use crate::rules::send_node::named_children_of;
15
16
 
16
17
  const KEY: &str = "rubygems_mfa_required";
17
18
  const MSG: &str = "`metadata['rubygems_mfa_required']` must be set to `'true'`.";
@@ -41,7 +42,7 @@ fn specifications_within<'a>(block: Node<'_>, context: &'a RuleContext<'_>) -> V
41
42
  if let Some(variable) = specification_variable(node, context) {
42
43
  found.push(variable);
43
44
  }
44
- push_named_children(node, &mut stack);
45
+ push_named_children_in(node, context, &mut stack);
45
46
  }
46
47
  found
47
48
  }
@@ -84,7 +85,7 @@ fn report(
84
85
  fn metadata_value<'tree>(
85
86
  block: Node<'tree>,
86
87
  locals: &HashSet<&str>,
87
- context: &RuleContext<'_>,
88
+ context: &'tree RuleContext<'_>,
88
89
  ) -> Option<Node<'tree>> {
89
90
  let mut stack = vec![block];
90
91
  while let Some(node) = stack.pop() {
@@ -102,7 +103,7 @@ fn metadata_value<'tree>(
102
103
  return node.field("right");
103
104
  }
104
105
  }
105
- push_named_children(node, &mut stack);
106
+ push_named_children_in(node, context, &mut stack);
106
107
  }
107
108
  None
108
109
  }
@@ -111,7 +112,7 @@ fn metadata_value<'tree>(
111
112
  /// hash gives the `rubygems_mfa_required` key.
112
113
  fn mfa_value<'tree>(
113
114
  metadata: Option<Node<'tree>>,
114
- context: &RuleContext<'_>,
115
+ context: &'tree RuleContext<'_>,
115
116
  ) -> Option<Node<'tree>> {
116
117
  let metadata = metadata?;
117
118
  if is_string(metadata, context) {
@@ -122,7 +123,7 @@ fn mfa_value<'tree>(
122
123
  if node.kind_str() == "pair" && is_mfa_pair(node, context) {
123
124
  return node.field("value");
124
125
  }
125
- push_named_children(node, &mut stack);
126
+ push_named_children_in(node, context, &mut stack);
126
127
  }
127
128
  None
128
129
  }
@@ -139,7 +140,7 @@ fn insertion(
139
140
  // `correct_metadata`: a new pair goes after the last one, or between the braces of an empty
140
141
  // hash. Metadata assigned anything other than a hash literal cannot be corrected at all.
141
142
  Some(hash) if hash.kind_str() == "hash" => {
142
- let pairs: Vec<Node<'_>> = named_children(hash)
143
+ let pairs: Vec<Node<'_>> = named_children_of(hash, context)
143
144
  .into_iter()
144
145
  .filter(|child| child.kind_str() == "pair")
145
146
  .collect();
@@ -183,7 +184,7 @@ fn insertion(
183
184
  fn last_metadata_assignment<'tree>(
184
185
  block: Node<'tree>,
185
186
  locals: &HashSet<&str>,
186
- context: &RuleContext<'_>,
187
+ context: &'tree RuleContext<'_>,
187
188
  ) -> Option<Node<'tree>> {
188
189
  let mut last = None;
189
190
  let mut stack = vec![block];
@@ -196,7 +197,7 @@ fn last_metadata_assignment<'tree>(
196
197
  {
197
198
  last = Some(node);
198
199
  }
199
- push_named_children(node, &mut stack);
200
+ push_named_children_in(node, context, &mut stack);
200
201
  }
201
202
  last
202
203
  }
@@ -6,6 +6,7 @@ use crate::rules::send_node::{
6
6
  FILE_KEYWORD, arguments, is_plain_send, is_string, named_children, string_text,
7
7
  };
8
8
  use crate::rules::node_ext::NodeExt;
9
+ use crate::rules::send_node::named_children_of;
9
10
 
10
11
  pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
11
12
  let assignments: Vec<Node<'_>> = context
@@ -66,7 +67,7 @@ fn dynamic_version(node: Node<'_>, context: &RuleContext<'_>) -> bool {
66
67
  {
67
68
  return true;
68
69
  }
69
- named_children(node)
70
+ named_children_of(node, context)
70
71
  .into_iter()
71
72
  .any(|child| dynamic_descendant(child, context))
72
73
  }
@@ -74,7 +75,7 @@ fn dynamic_version(node: Node<'_>, context: &RuleContext<'_>) -> bool {
74
75
  fn dynamic_descendant(node: Node<'_>, context: &RuleContext<'_>) -> bool {
75
76
  is_variable(node, context)
76
77
  || is_send(node, context)
77
- || named_children(node)
78
+ || named_children_of(node, context)
78
79
  .into_iter()
79
80
  .any(|child| dynamic_descendant(child, context))
80
81
  }
@@ -8,7 +8,8 @@ use crate::rules::RuleContext;
8
8
  use crate::rules::lint::blocks::BlockArgs;
9
9
  use crate::rules::lint::locals::LocalVariables;
10
10
  use crate::rules::node_ext::NodeExt;
11
- use crate::rules::send_node::{arguments, named_children, top_level_constant};
11
+ use crate::rules::send_node::named_children_of;
12
+ use crate::rules::send_node::{arguments, top_level_constant};
12
13
 
13
14
  /// The block parameter of `Gem::Specification.new do |spec|`, or `None` when the call is not one.
14
15
  ///
@@ -38,7 +39,7 @@ pub(super) fn specification_variable<'a>(
38
39
  return None;
39
40
  }
40
41
  let parameters = call.field("block")?.field("parameters")?;
41
- match named_children(parameters).as_slice() {
42
+ match named_children_of(parameters, context).as_slice() {
42
43
  [only] if only.kind_str() == "identifier" => Some(context.source.node_text(*only)),
43
44
  _ => None,
44
45
  }
@@ -101,8 +101,7 @@ fn inspect(
101
101
  /// `node.children`, where a run of `key: value` pairs is a single `hash` value upstream.
102
102
  fn elements(node: Node<'_>) -> Vec<Range<usize>> {
103
103
  let mut cursor = node.walk();
104
- let children: Vec<Node<'_>> = node
105
- .named_children(&mut cursor)
104
+ let children: Vec<Node<'_>> = node.named_children(&mut cursor)
106
105
  .filter(|child| !matches!(child.kind_str(), "comment" | "heredoc_body"))
107
106
  .collect();
108
107
  let mut elements = Vec::new();
@@ -8,6 +8,7 @@ use super::support::{begins_its_line, heredoc_terminators};
8
8
  use crate::diagnostic::{Edit, Offense};
9
9
  use crate::rules::RuleContext;
10
10
  use crate::rules::node_ext::NodeExt;
11
+ use crate::rules::send_node::named_children_of;
11
12
 
12
13
  pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
13
14
  let text = context.source.text();
@@ -108,9 +109,9 @@ fn last_heredoc_argument(
108
109
  let terminators = heredoc_terminators(context);
109
110
  loop {
110
111
  if let Some(list) = argument_list(node) {
111
- let mut cursor = list.walk();
112
- let found = list
113
- .named_children(&mut cursor)
112
+ let _cursor = list.walk();
113
+ let found = named_children_of(list, context)
114
+ .into_iter()
114
115
  .filter(|child| child.kind_str() == "heredoc_beginning")
115
116
  .filter_map(|child| plain_heredoc(context, &bodies, &terminators, child))
116
117
  .last();
@@ -131,8 +132,7 @@ fn body_call<'tree>(block: Node<'tree>) -> Option<Node<'tree>> {
131
132
  matches!(child.kind_str(), "body_statement" | "block_body") && child.named_child_count() > 0
132
133
  })?;
133
134
  let mut cursor = body.walk();
134
- let statements: Vec<Node<'tree>> = body
135
- .named_children(&mut cursor)
135
+ let statements: Vec<Node<'tree>> = body.named_children(&mut cursor)
136
136
  .filter(|child| !matches!(child.kind_str(), "comment" | "heredoc_body"))
137
137
  .collect();
138
138
  match statements.as_slice() {
@@ -8,6 +8,8 @@ use crate::rules::lint::access_modifier::send_name;
8
8
  use crate::rules::node_ext::NodeExt;
9
9
  use crate::rules::send_node::{arguments, named_children, symbol_name};
10
10
  use crate::rules::visibility::{node_visibility, siblings, statements};
11
+ use crate::rules::send_node::all_children_iter;
12
+ use crate::rules::send_node::named_children_iter;
11
13
 
12
14
  pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
13
15
  let expected: Vec<String> = context.setting("ExpectedOrder").unwrap_or_default();
@@ -204,7 +206,7 @@ fn is_private_constant(node: Node<'_>, context: &RuleContext<'_>) -> bool {
204
206
  let Some(parent) = node.parent_of(context) else {
205
207
  return false;
206
208
  };
207
- named_children(parent).into_iter().any(|sibling| {
209
+ named_children_iter(parent, context).any(|sibling| {
208
210
  sibling.kind_str() == "call"
209
211
  && sibling
210
212
  .field("method")
@@ -358,8 +360,8 @@ fn is_upstream_send(node: Node<'_>, context: &RuleContext<'_>) -> bool {
358
360
  }
359
361
 
360
362
  fn operator_text<'a>(node: Node<'_>, context: &'a RuleContext<'_>) -> Option<&'a str> {
361
- let mut cursor = node.walk();
362
- node.children(&mut cursor)
363
+ let _cursor = node.walk();
364
+ all_children_iter(node, context)
363
365
  .find(|child| !child.is_named())
364
366
  .map(|child| context.source.node_text(child))
365
367
  }
@@ -7,6 +7,7 @@ use crate::rules::RuleContext;
7
7
 
8
8
  use super::support::is_send_like;
9
9
  use crate::rules::node_ext::NodeExt;
10
+ use crate::rules::send_node::named_children_of;
10
11
 
11
12
  pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
12
13
  let openers: Vec<Node<'_>> = context.nodes_of("heredoc_beginning").collect();
@@ -25,9 +26,9 @@ pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
25
26
  if heredoc_type(&text[opener.byte_range()]) == Some("<<") {
26
27
  continue;
27
28
  }
28
- let mut cursor = body.walk();
29
- let Some(delimiter) = body
30
- .named_children(&mut cursor)
29
+ let _cursor = body.walk();
30
+ let Some(delimiter) = named_children_of(body, context)
31
+ .into_iter()
31
32
  .find(|child| child.kind_str() == "heredoc_end")
32
33
  else {
33
34
  continue;
@@ -153,8 +153,7 @@ fn delimited<'tree>(node: Node<'tree>) -> Option<Delimited<'tree>> {
153
153
  "call" => grouped(node),
154
154
  _ => {
155
155
  let mut cursor = container.walk();
156
- container
157
- .named_children(&mut cursor)
156
+ container.named_children(&mut cursor)
158
157
  .filter(|child| !matches!(child.kind_str(), "comment" | "heredoc_body"))
159
158
  .map(|child| (child.start_byte(), hash_parts(child)))
160
159
  .collect()
@@ -5,6 +5,7 @@ use tree_sitter::Node;
5
5
  use crate::diagnostic::{Edit, Offense};
6
6
  use crate::rules::RuleContext;
7
7
  use crate::rules::node_ext::NodeExt;
8
+ use crate::rules::send_node::named_children_iter;
8
9
 
9
10
  pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
10
11
  // The modifier forms and the ternary have their own node kinds here, so reaching one of these
@@ -54,8 +55,8 @@ fn removal(context: &RuleContext<'_>, node: Node<'_>, condition: Node<'_>) -> Ed
54
55
  let body = node.field("consequence").or_else(|| node.field("body"));
55
56
  let body_start = body
56
57
  .and_then(|body| {
57
- let mut cursor = body.walk();
58
- body.named_children(&mut cursor)
58
+ let _cursor = body.walk();
59
+ named_children_iter(body, context)
59
60
  .find(|child| !matches!(child.kind_str(), "comment" | "heredoc_body"))
60
61
  })
61
62
  .map(|first| first.start_byte());
@@ -6,7 +6,7 @@ use tree_sitter::Node;
6
6
 
7
7
  use super::support::{effective_character_column, end_keyword, end_keyword_alignment};
8
8
  use crate::diagnostic::Offense;
9
- use crate::rules::{RuleContext, push_named_children};
9
+ use crate::rules::{RuleContext, push_named_children_in};
10
10
  use crate::rules::node_ext::NodeExt;
11
11
 
12
12
  pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
@@ -63,7 +63,7 @@ pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
63
63
  }
64
64
  _ => {}
65
65
  }
66
- push_named_children(node, &mut stack);
66
+ push_named_children_in(node, context, &mut stack);
67
67
  }
68
68
  }
69
69
 
@@ -136,8 +136,7 @@ fn last_heredoc(heredocs: &[(usize, Range<usize>)], receiver: Node<'_>) -> Optio
136
136
  }
137
137
  let arguments = receiver.field("arguments")?;
138
138
  let mut cursor = arguments.walk();
139
- arguments
140
- .named_children(&mut cursor)
139
+ arguments.named_children(&mut cursor)
141
140
  .filter(|argument| argument.kind_str() == "heredoc_beginning")
142
141
  .filter_map(|argument| terminator_of(argument.start_byte()))
143
142
  .max_by_key(|terminator| terminator.end)
@@ -215,8 +215,7 @@ fn if_branch<'tree>(node: Node<'tree>) -> Option<Node<'tree>> {
215
215
  // A `then` clause holding more than one statement is a `begin` upstream, which is
216
216
  // never a guard clause.
217
217
  let mut cursor = branch.walk();
218
- let mut statements = branch
219
- .named_children(&mut cursor)
218
+ let mut statements = branch.named_children(&mut cursor)
220
219
  .filter(|child| !matches!(child.kind_str(), "heredoc_body" | "comment"));
221
220
  let first = statements.next()?;
222
221
  statements.next().is_none().then_some(first)
@@ -279,8 +278,7 @@ fn next_statement<'tree>(node: Node<'tree>) -> Option<(Node<'tree>, bool)> {
279
278
  _ => return None,
280
279
  };
281
280
  let mut cursor = parent.walk();
282
- let statements: Vec<Node<'tree>> = parent
283
- .named_children(&mut cursor)
281
+ let statements: Vec<Node<'tree>> = parent.named_children(&mut cursor)
284
282
  .filter(|child| {
285
283
  !matches!(
286
284
  child.kind_str(),
@@ -382,8 +380,7 @@ fn is_and(text: &str, node: Node<'_>) -> bool {
382
380
 
383
381
  fn call_arguments<'tree>(node: Node<'tree>) -> Vec<Node<'tree>> {
384
382
  let mut cursor = node.walk();
385
- let Some(list) = node
386
- .children(&mut cursor)
383
+ let Some(list) = node.children(&mut cursor)
387
384
  .find(|child| child.kind_str() == "argument_list")
388
385
  else {
389
386
  return Vec::new();
@@ -5,8 +5,8 @@ use tree_sitter::Node;
5
5
  use crate::diagnostic::{Edit, Offense};
6
6
  use crate::rules::RuleContext;
7
7
  use crate::rules::node_ext::NodeExt;
8
- use crate::rules::send_node::named_children;
9
8
  use crate::rules::support;
9
+ use crate::rules::send_node::named_children_of;
10
10
 
11
11
  const MSG: &str = "Use empty line after multiline condition.";
12
12
 
@@ -98,11 +98,11 @@ fn block_delimiters(node: Node<'_>) -> Option<Range<usize>> {
98
98
  /// `on_case`: each `when` whose own list of conditions spans more than one line.
99
99
  fn when_branches(node: Node<'_>, context: &RuleContext<'_>) -> Vec<Offense> {
100
100
  let mut offenses = Vec::new();
101
- for branch in named_children(node) {
101
+ for branch in named_children_of(node, context) {
102
102
  if branch.kind_str() != "when" {
103
103
  continue;
104
104
  }
105
- let conditions: Vec<Node<'_>> = named_children(branch)
105
+ let conditions: Vec<Node<'_>> = named_children_of(branch, context)
106
106
  .into_iter()
107
107
  .filter(|child| child.kind_str() == "pattern")
108
108
  .collect();
@@ -123,7 +123,7 @@ fn when_branches(node: Node<'_>, context: &RuleContext<'_>) -> Vec<Offense> {
123
123
 
124
124
  /// `on_rescue`: each `resbody` that names more than one exception across more than one line.
125
125
  fn rescue_branch(node: Node<'_>, context: &RuleContext<'_>) -> Option<Offense> {
126
- let exceptions = named_children(node.field("exceptions")?);
126
+ let exceptions = named_children_of(node.field("exceptions")?, context);
127
127
  // `multiline_rescue_exceptions?`: one exception is never enough.
128
128
  if exceptions.len() <= 1 {
129
129
  return None;
@@ -170,7 +170,7 @@ fn next_statement<'tree>(
170
170
  if !CONTAINERS.contains(&parent.kind_str()) {
171
171
  return None;
172
172
  }
173
- let siblings: Vec<Node<'_>> = named_children(parent)
173
+ let siblings: Vec<Node<'_>> = named_children_of(parent, context)
174
174
  .into_iter()
175
175
  .filter(|child| child.kind_str() != "comment")
176
176
  .collect();
@@ -23,7 +23,7 @@ pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
23
23
  // RuboCop keeps the enclosing class and block on instance variables that its callbacks fill in
24
24
  // as the walk reaches them, so what a modifier sees is whatever was visited last -- never
25
25
  // unwound on the way back out. A single pre-order pass reproduces that.
26
- walk_named(context.root_node(), &mut |node| match node.kind_str() {
26
+ walk_named(context.root_node(), context, &mut |node| match node.kind_str() {
27
27
  "class" => {
28
28
  let header = node
29
29
  .field("superclass")
@@ -270,8 +270,7 @@ fn enclosing_body<'tree>(node: Node<'tree>) -> Option<Body<'tree>> {
270
270
  return None;
271
271
  }
272
272
  let mut cursor = container.walk();
273
- let statements: Vec<Node<'tree>> = container
274
- .named_children(&mut cursor)
273
+ let statements: Vec<Node<'tree>> = container.named_children(&mut cursor)
275
274
  .filter(|child| !matches!(child.kind_str(), "rescue" | "ensure" | "else"))
276
275
  .collect();
277
276
  let wrapped_in_begin = statements.len() > 1;
@@ -84,7 +84,7 @@ fn send_view(context: &RuleContext<'_>, node: Node<'_>) -> Option<SendView> {
84
84
  "call" => {
85
85
  // An attribute write is one `:name=` send spanning the assignment, so the call on its
86
86
  // own is not what upstream inspects.
87
- if is_assignment_target(node) {
87
+ if is_assignment_target(node, context) {
88
88
  return None;
89
89
  }
90
90
  let list = child_of_kind(node, "argument_list");
@@ -100,7 +100,7 @@ fn send_view(context: &RuleContext<'_>, node: Node<'_>) -> Option<SendView> {
100
100
  })
101
101
  }
102
102
  "element_reference" => {
103
- if is_assignment_target(node) {
103
+ if is_assignment_target(node, context) {
104
104
  return None;
105
105
  }
106
106
  let bracket = child_of_kind(node, "[")?;
@@ -161,8 +161,8 @@ fn selector<'tree>(node: Node<'tree>) -> Option<Node<'tree>> {
161
161
  .filter(|method| !method.byte_range().is_empty())
162
162
  }
163
163
 
164
- fn is_assignment_target(node: Node<'_>) -> bool {
165
- node.parent().is_some_and(|parent| {
164
+ fn is_assignment_target(node: Node<'_>, context: &RuleContext<'_>) -> bool {
165
+ context.parent(node).is_some_and(|parent| {
166
166
  parent.kind_str() == "assignment" && parent.field("left") == Some(node)
167
167
  })
168
168
  }
@@ -98,8 +98,7 @@ fn body_clauses<'tree>(node: Node<'tree>) -> Vec<Node<'tree>> {
98
98
  },
99
99
  };
100
100
  let mut cursor = container.walk();
101
- container
102
- .named_children(&mut cursor)
101
+ container.named_children(&mut cursor)
103
102
  .filter(|child| matches!(child.kind_str(), "rescue" | "else" | "ensure"))
104
103
  .collect()
105
104
  }
@@ -6,6 +6,7 @@ use super::empty_lines_around_body::{Target, body_container, body_of, check as c
6
6
  use crate::diagnostic::{Edit, Offense};
7
7
  use crate::rules::RuleContext;
8
8
  use crate::rules::node_ext::NodeExt;
9
+ use crate::rules::send_node::all_children_iter;
9
10
 
10
11
  pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
11
12
  let mut targets = Vec::new();
@@ -45,8 +46,8 @@ fn check_endless(context: &RuleContext<'_>, node: Node<'_>, offenses: &mut Vec<O
45
46
  let Some(body) = node.field("body") else {
46
47
  return;
47
48
  };
48
- let mut cursor = node.walk();
49
- let Some(assignment) = node.children(&mut cursor).find(|child| child.kind_str() == "=") else {
49
+ let _cursor = node.walk();
50
+ let Some(assignment) = all_children_iter(node, context).find(|child| child.kind_str() == "=") else {
50
51
  return;
51
52
  };
52
53
  let assignment_line = assignment.start_position().row + 1;
@@ -11,7 +11,7 @@ use super::support::{
11
11
  };
12
12
  use crate::diagnostic::Offense;
13
13
  use crate::rules::node_ext::NodeExt;
14
- use crate::rules::{RuleContext, push_named_children};
14
+ use crate::rules::{RuleContext, push_named_children_in};
15
15
 
16
16
  /// `EnforcedStyleAlignWith`.
17
17
  #[derive(Clone, Copy, Eq, PartialEq)]
@@ -42,7 +42,7 @@ pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
42
42
  let mut stack = vec![context.root_node()];
43
43
  while let Some(node) = stack.pop() {
44
44
  checker.visit(node, offenses);
45
- push_named_children(node, &mut stack);
45
+ push_named_children_in(node, context, &mut stack);
46
46
  }
47
47
  }
48
48
 
@@ -19,6 +19,7 @@ use super::tokens::{Token, tokens};
19
19
  use crate::diagnostic::{Edit, Offense};
20
20
  use crate::rules::RuleContext;
21
21
  use crate::rules::node_ext::NodeExt;
22
+ use crate::rules::send_node::named_children_of;
22
23
 
23
24
  const MSG_UNNECESSARY: &str = "Unnecessary spacing detected.";
24
25
  const MSG_UNALIGNED_ASGN: &str = "`=` is not aligned with the preceding assignment.";
@@ -246,7 +247,7 @@ fn aligned_comment_lines(context: &RuleContext<'_>) -> HashSet<usize> {
246
247
  fn ignored_ranges(context: &RuleContext<'_>) -> Vec<Range<usize>> {
247
248
  let mut ranges = Vec::new();
248
249
  for elements in hash_literals(context) {
249
- let Some(span) = hash_span(&elements) else {
250
+ let Some(span) = hash_span(&elements, context) else {
250
251
  continue;
251
252
  };
252
253
  if context.source.line_column(span.start).0 == context.source.line_column(span.end).0 {
@@ -265,10 +266,10 @@ fn ignored_ranges(context: &RuleContext<'_>) -> Vec<Range<usize>> {
265
266
  /// Where the `hash` node upstream builds for these elements begins and ends. A braced literal is a
266
267
  /// node of its own, whose braces count towards `single_line?`; a brace-less one is only the run of
267
268
  /// pairs the parser folded together.
268
- fn hash_span(elements: &[Node<'_>]) -> Option<Range<usize>> {
269
+ fn hash_span(elements: &[Node<'_>], context: &RuleContext<'_>) -> Option<Range<usize>> {
269
270
  let first = elements.first()?;
270
271
  let last = elements.last()?;
271
- match first.parent().filter(|parent| parent.kind_str() == "hash") {
272
+ match context.parent(*first).filter(|parent| parent.kind_str() == "hash") {
272
273
  Some(hash) => Some(hash.byte_range()),
273
274
  None => Some(first.start_byte()..last.end_byte()),
274
275
  }
@@ -287,8 +288,8 @@ fn previous_character(text: &str, offset: usize) -> Option<usize> {
287
288
  /// nothing but comments.
288
289
  fn is_blank(context: &RuleContext<'_>) -> bool {
289
290
  let root = context.root_node();
290
- let mut cursor = root.walk();
291
- !root
292
- .named_children(&mut cursor)
291
+ let _cursor = root.walk();
292
+ !named_children_of(root, context)
293
+ .into_iter()
293
294
  .any(|child| child.kind_str() != "comment")
294
295
  }
@@ -100,8 +100,7 @@ fn inspect(
100
100
  /// first element spans the whole run rather than just its first pair.
101
101
  fn first_element<'tree>(array: Node<'tree>) -> Option<(Range<usize>, Option<Node<'tree>>)> {
102
102
  let mut cursor = array.walk();
103
- let children: Vec<Node<'tree>> = array
104
- .named_children(&mut cursor)
103
+ let children: Vec<Node<'tree>> = array.named_children(&mut cursor)
105
104
  .filter(|child| !matches!(child.kind_str(), "comment" | "heredoc_body"))
106
105
  .collect();
107
106
  let first = *children.first()?;
@@ -11,6 +11,8 @@ use super::support::{
11
11
  use crate::diagnostic::Offense;
12
12
  use crate::rules::RuleContext;
13
13
  use crate::rules::node_ext::NodeExt;
14
+ use crate::rules::send_node::named_children_of;
15
+ use crate::rules::send_node::all_children_of;
14
16
 
15
17
  pub(super) fn check(context: &RuleContext<'_>, offenses: &mut Vec<Offense>) {
16
18
  let style: String = context
@@ -93,9 +95,9 @@ fn first_pair<'tree>(hash: Node<'tree>) -> Option<Node<'tree>> {
93
95
  }
94
96
 
95
97
  fn separator_style(context: &RuleContext<'_>, first: Node<'_>) -> bool {
96
- let mut cursor = first.walk();
97
- let rocket = first
98
- .children(&mut cursor)
98
+ let _cursor = first.walk();
99
+ let rocket = all_children_of(first, context)
100
+ .into_iter()
99
101
  .any(|child| child.kind_str() == "=>");
100
102
  let key = if rocket {
101
103
  "EnforcedHashRocketStyle"
@@ -109,9 +111,9 @@ fn separator_style(context: &RuleContext<'_>, first: Node<'_>) -> bool {
109
111
  }
110
112
 
111
113
  fn longest_key_overhang(context: &RuleContext<'_>, hash: Node<'_>) -> i64 {
112
- let mut cursor = hash.walk();
113
- let lengths: Vec<i64> = hash
114
- .named_children(&mut cursor)
114
+ let _cursor = hash.walk();
115
+ let lengths: Vec<i64> = named_children_of(hash, context)
116
+ .into_iter()
115
117
  .filter(|child| child.kind_str() == "pair")
116
118
  .filter_map(|pair| pair.field("key"))
117
119
  .map(|key| context.source.text()[key.byte_range()].chars().count() as i64)
@@ -9,6 +9,7 @@ use super::support::{Edits, begins_its_line, hash_literals};
9
9
  use crate::diagnostic::{Edit, Offense};
10
10
  use crate::rules::RuleContext;
11
11
  use crate::rules::node_ext::NodeExt;
12
+ use crate::rules::send_node::named_children_iter;
12
13
 
13
14
  const KEY_MESSAGE: &str = "Align the keys of a hash literal if they span more than one line.";
14
15
  const SEPARATOR_MESSAGE: &str =
@@ -648,10 +649,9 @@ fn ignored_last_argument(elements: &[Node<'_>], context: &RuleContext<'_>, style
648
649
  let is_last_argument = match list.kind_str() {
649
650
  // `on_send`, `on_csend`, `on_super` and `on_yield`: an array literal is none of them.
650
651
  "argument_list" | "element_reference" => {
651
- let mut cursor = list.walk();
652
- list.named_children(&mut cursor)
653
- .filter(|child| !matches!(child.kind_str(), "comment" | "heredoc_body"))
654
- .last()
652
+ let _cursor = list.walk();
653
+ named_children_iter(list, context)
654
+ .rfind(|child| !matches!(child.kind_str(), "comment" | "heredoc_body"))
655
655
  .is_some_and(|node| node.id() == wanted.id())
656
656
  }
657
657
  // `x.foo = { … }` and `x[k] = { … }` are `send :foo=` and `send :[]=` to upstream's