1use ruff_text_size::Ranged;
2
3use crate::visitor::source_order::SourceOrderVisitor;
4use crate::{
5 self as ast, Alias, AnyNodeRef, AnyParameterRef, ArgOrKeyword, MatchCase, PatternKeyword,
6};
7
8impl ast::ElifElseClause {
9 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
10 where
11 V: SourceOrderVisitor<'a> + ?Sized,
12 {
13 let ast::ElifElseClause {
14 range: _,
15 node_index: _,
16 test,
17 body,
18 ..
19 } = self;
20 if let Some(test) = test {
21 visitor.visit_expr(test);
22 }
23 visitor.visit_body(body);
24 }
25}
26
27impl ast::ExprDict {
28 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
29 where
30 V: SourceOrderVisitor<'a> + ?Sized,
31 {
32 let ast::ExprDict { items, .. } = self;
33
34 for ast::DictItem { key, value } in items {
35 if let Some(key) = key {
36 visitor.visit_expr(key);
37 }
38 visitor.visit_expr(value);
39 }
40 }
41}
42
43impl ast::ExprBoolOp {
44 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
45 where
46 V: SourceOrderVisitor<'a> + ?Sized,
47 {
48 let ast::ExprBoolOp { op, values, .. } = self;
49 match values.as_slice() {
50 [left, rest @ ..] => {
51 visitor.visit_expr(left);
52 visitor.visit_bool_op(op);
53 for expr in rest {
54 visitor.visit_expr(expr);
55 }
56 }
57 [] => {
58 visitor.visit_bool_op(op);
59 }
60 }
61 }
62}
63
64impl ast::ExprCompare {
65 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
66 where
67 V: SourceOrderVisitor<'a> + ?Sized,
68 {
69 visitor.visit_expr(self.first_operand());
70 for (_, op, right) in self.iter() {
71 visitor.visit_cmp_op(op);
72 visitor.visit_expr(right);
73 }
74 }
75}
76
77impl ast::InterpolatedStringFormatSpec {
78 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
79 where
80 V: SourceOrderVisitor<'a> + ?Sized,
81 {
82 for element in &self.elements {
83 visitor.visit_interpolated_string_element(element);
84 }
85 }
86}
87
88impl ast::InterpolatedElement {
89 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
90 where
91 V: SourceOrderVisitor<'a> + ?Sized,
92 {
93 let ast::InterpolatedElement {
94 expression,
95 format_spec,
96 ..
97 } = self;
98 visitor.visit_expr(expression);
99
100 if let Some(format_spec) = format_spec {
101 for spec_part in &format_spec.elements {
102 visitor.visit_interpolated_string_element(spec_part);
103 }
104 }
105 }
106}
107
108impl ast::InterpolatedStringLiteralElement {
109 pub(crate) fn visit_source_order<'a, V>(&'a self, _visitor: &mut V)
110 where
111 V: SourceOrderVisitor<'a> + ?Sized,
112 {
113 let ast::InterpolatedStringLiteralElement {
114 range: _,
115 node_index: _,
116 value: _,
117 } = self;
118 }
119}
120
121impl ast::ExprFString {
122 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
123 where
124 V: SourceOrderVisitor<'a> + ?Sized,
125 {
126 let ast::ExprFString { value, .. } = self;
127
128 for f_string_part in value {
129 match f_string_part {
130 ast::FStringPartRef::Literal(string_literal) => {
131 visitor.visit_string_literal(string_literal);
132 }
133 ast::FStringPartRef::FString(f_string) => {
134 visitor.visit_f_string(f_string);
135 }
136 }
137 }
138 }
139}
140
141impl ast::ExprTString {
142 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
143 where
144 V: SourceOrderVisitor<'a> + ?Sized,
145 {
146 let ast::ExprTString { value, .. } = self;
147
148 for t_string in value {
149 visitor.visit_t_string(t_string);
150 }
151 }
152}
153
154impl ast::ExprStringLiteral {
155 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
156 where
157 V: SourceOrderVisitor<'a> + ?Sized,
158 {
159 let ast::ExprStringLiteral { value, .. } = self;
160
161 for string_literal in value {
162 visitor.visit_string_literal(string_literal);
163 }
164 }
165}
166
167impl ast::ExprBytesLiteral {
168 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
169 where
170 V: SourceOrderVisitor<'a> + ?Sized,
171 {
172 let ast::ExprBytesLiteral { value, .. } = self;
173
174 for bytes_literal in value {
175 visitor.visit_bytes_literal(bytes_literal);
176 }
177 }
178}
179
180impl ast::ExceptHandlerExceptHandler {
181 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
182 where
183 V: SourceOrderVisitor<'a> + ?Sized,
184 {
185 let ast::ExceptHandlerExceptHandler {
186 range: _,
187 node_index: _,
188 type_,
189 name,
190 body,
191 ..
192 } = self;
193 if let Some(expr) = type_ {
194 visitor.visit_expr(expr);
195 }
196
197 if let Some(name) = name {
198 visitor.visit_identifier(name);
199 }
200
201 visitor.visit_body(body);
202 }
203}
204
205impl ast::PatternMatchMapping {
206 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
207 where
208 V: SourceOrderVisitor<'a> + ?Sized,
209 {
210 let ast::PatternMatchMapping {
211 keys,
212 patterns,
213 rest,
214 ..
215 } = self;
216
217 let mut rest = rest.as_ref();
218
219 for (key, pattern) in keys.iter().zip(patterns) {
220 if let Some(rest_identifier) = rest {
221 if rest_identifier.start() < key.start() {
222 visitor.visit_identifier(rest_identifier);
223 rest = None;
224 }
225 }
226 visitor.visit_expr(key);
227 visitor.visit_pattern(pattern);
228 }
229
230 if let Some(rest) = rest {
231 visitor.visit_identifier(rest);
232 }
233 }
234}
235
236impl ast::PatternArguments {
237 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
238 where
239 V: SourceOrderVisitor<'a> + ?Sized,
240 {
241 for pattern_or_keyword in self.iter_source_order() {
242 match pattern_or_keyword {
243 crate::PatternOrKeyword::Pattern(pattern) => visitor.visit_pattern(pattern),
244 crate::PatternOrKeyword::Keyword(keyword) => {
245 visitor.visit_pattern_keyword(keyword);
246 }
247 }
248 }
249 }
250}
251
252impl ast::PatternKeyword {
253 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
254 where
255 V: SourceOrderVisitor<'a> + ?Sized,
256 {
257 let PatternKeyword {
258 range: _,
259 node_index: _,
260 attr,
261 pattern,
262 } = self;
263
264 visitor.visit_identifier(attr);
265 visitor.visit_pattern(pattern);
266 }
267}
268
269impl ast::Comprehension {
270 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
271 where
272 V: SourceOrderVisitor<'a> + ?Sized,
273 {
274 let ast::Comprehension {
275 range: _,
276 node_index: _,
277 target,
278 iter,
279 ifs,
280 ..
281 } = self;
282 visitor.visit_expr(target);
283 visitor.visit_expr(iter);
284
285 for expr in ifs {
286 visitor.visit_expr(expr);
287 }
288 }
289}
290
291impl ast::Arguments {
292 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
293 where
294 V: SourceOrderVisitor<'a> + ?Sized,
295 {
296 for arg_or_keyword in self.iter_source_order() {
297 match arg_or_keyword {
298 ArgOrKeyword::Arg(arg) => visitor.visit_expr(arg),
299 ArgOrKeyword::Keyword(keyword) => visitor.visit_keyword(keyword),
300 }
301 }
302 }
303}
304
305impl ast::Parameters {
306 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
307 where
308 V: SourceOrderVisitor<'a> + ?Sized,
309 {
310 for parameter in self.iter_source_order() {
311 match parameter {
312 AnyParameterRef::NonVariadic(parameter_with_default) => {
313 visitor.visit_parameter_with_default(parameter_with_default);
314 }
315 AnyParameterRef::Variadic(parameter) => visitor.visit_parameter(parameter),
316 }
317 }
318 }
319}
320
321impl ast::Parameter {
322 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
323 where
324 V: SourceOrderVisitor<'a> + ?Sized,
325 {
326 let ast::Parameter {
327 range: _,
328 node_index: _,
329 name,
330 annotation,
331 ..
332 } = self;
333
334 visitor.visit_identifier(name);
335 if let Some(expr) = annotation {
336 visitor.visit_annotation(expr);
337 }
338 }
339}
340
341impl ast::ParameterWithDefault {
342 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
343 where
344 V: SourceOrderVisitor<'a> + ?Sized,
345 {
346 let ast::ParameterWithDefault {
347 range: _,
348 node_index: _,
349 parameter,
350 default,
351 } = self;
352 visitor.visit_parameter(parameter);
353 if let Some(expr) = default {
354 visitor.visit_expr(expr);
355 }
356 }
357}
358
359impl ast::Keyword {
360 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
361 where
362 V: SourceOrderVisitor<'a> + ?Sized,
363 {
364 let ast::Keyword {
365 range: _,
366 node_index: _,
367 arg,
368 value,
369 } = self;
370
371 if let Some(arg) = arg {
372 visitor.visit_identifier(arg);
373 }
374 visitor.visit_expr(value);
375 }
376}
377
378impl Alias {
379 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
380 where
381 V: SourceOrderVisitor<'a> + ?Sized,
382 {
383 let ast::Alias {
384 range: _,
385 node_index: _,
386 name,
387 asname,
388 } = self;
389
390 visitor.visit_identifier(name);
391 if let Some(asname) = asname {
392 visitor.visit_identifier(asname);
393 }
394 }
395}
396
397impl ast::WithItem {
398 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
399 where
400 V: SourceOrderVisitor<'a> + ?Sized,
401 {
402 let ast::WithItem {
403 range: _,
404 node_index: _,
405 context_expr,
406 optional_vars,
407 } = self;
408
409 visitor.visit_expr(context_expr);
410
411 if let Some(expr) = optional_vars {
412 visitor.visit_expr(expr);
413 }
414 }
415}
416
417impl ast::MatchCase {
418 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
419 where
420 V: SourceOrderVisitor<'a> + ?Sized,
421 {
422 let ast::MatchCase {
423 range: _,
424 node_index: _,
425 pattern,
426 guard,
427 body,
428 ..
429 } = self;
430
431 visitor.visit_pattern(pattern);
432 if let Some(expr) = guard {
433 visitor.visit_expr(expr);
434 }
435 visitor.visit_body(body);
436 }
437}
438
439impl ast::Decorator {
440 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
441 where
442 V: SourceOrderVisitor<'a> + ?Sized,
443 {
444 let ast::Decorator {
445 range: _,
446 node_index: _,
447 expression,
448 } = self;
449
450 visitor.visit_expr(expression);
451 }
452}
453
454impl ast::TypeParams {
455 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
456 where
457 V: SourceOrderVisitor<'a> + ?Sized,
458 {
459 let ast::TypeParams {
460 range: _,
461 node_index: _,
462 type_params,
463 ..
464 } = self;
465
466 for type_param in type_params {
467 visitor.visit_type_param(type_param);
468 }
469 }
470}
471
472impl ast::FString {
473 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
474 where
475 V: SourceOrderVisitor<'a> + ?Sized,
476 {
477 let ast::FString {
478 elements,
479 range: _,
480 node_index: _,
481 flags: _,
482 } = self;
483
484 for fstring_element in elements {
485 visitor.visit_interpolated_string_element(fstring_element);
486 }
487 }
488}
489
490impl ast::TString {
491 pub(crate) fn visit_source_order<'a, V>(&'a self, visitor: &mut V)
492 where
493 V: SourceOrderVisitor<'a> + ?Sized,
494 {
495 let ast::TString {
496 elements,
497 range: _,
498 node_index: _,
499 flags: _,
500 } = self;
501
502 for tstring_element in elements {
503 visitor.visit_interpolated_string_element(tstring_element);
504 }
505 }
506}
507
508impl ast::StringLiteral {
509 #[inline]
510 pub(crate) fn visit_source_order<'a, V>(&'a self, _visitor: &mut V)
511 where
512 V: SourceOrderVisitor<'a> + ?Sized,
513 {
514 let ast::StringLiteral {
515 range: _,
516 node_index: _,
517 value: _,
518 flags: _,
519 } = self;
520 }
521}
522
523impl ast::BytesLiteral {
524 #[inline]
525 pub(crate) fn visit_source_order<'a, V>(&'a self, _visitor: &mut V)
526 where
527 V: SourceOrderVisitor<'a> + ?Sized,
528 {
529 let ast::BytesLiteral {
530 range: _,
531 node_index: _,
532 value: _,
533 flags: _,
534 } = self;
535 }
536}
537
538impl ast::Identifier {
539 #[inline]
540 pub(crate) fn visit_source_order<'a, V>(&'a self, _visitor: &mut V)
541 where
542 V: SourceOrderVisitor<'a> + ?Sized,
543 {
544 let ast::Identifier {
545 range: _,
546 node_index: _,
547 id: _,
548 } = self;
549 }
550}
551
552impl<'a> AnyNodeRef<'a> {
553 pub fn ptr_eq(self, other: AnyNodeRef) -> bool {
555 self.as_ptr().eq(&other.as_ptr()) && self.kind() == other.kind()
556 }
557
558 pub const fn is_alternative_branch_with_node(self) -> bool {
562 matches!(
563 self,
564 AnyNodeRef::ExceptHandlerExceptHandler(_) | AnyNodeRef::ElifElseClause(_)
565 )
566 }
567
568 pub fn last_child_in_body(&self) -> Option<AnyNodeRef<'a>> {
570 let body =
571 match self {
572 AnyNodeRef::StmtFunctionDef(ast::StmtFunctionDef { body, .. })
573 | AnyNodeRef::StmtClassDef(ast::StmtClassDef { body, .. })
574 | AnyNodeRef::StmtWith(ast::StmtWith { body, .. })
575 | AnyNodeRef::MatchCase(MatchCase { body, .. })
576 | AnyNodeRef::ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler {
577 body,
578 ..
579 })
580 | AnyNodeRef::ElifElseClause(ast::ElifElseClause { body, .. }) => body,
581 AnyNodeRef::StmtIf(ast::StmtIf {
582 body,
583 elif_else_clauses,
584 ..
585 }) => elif_else_clauses.last().map_or(body, |clause| &clause.body),
586
587 AnyNodeRef::StmtFor(ast::StmtFor { body, orelse, .. })
588 | AnyNodeRef::StmtWhile(ast::StmtWhile { body, orelse, .. }) => {
589 if orelse.is_empty() { body } else { orelse }
590 }
591
592 AnyNodeRef::StmtMatch(ast::StmtMatch { cases, .. }) => {
593 return cases.last().map(AnyNodeRef::from);
594 }
595
596 AnyNodeRef::StmtTry(ast::StmtTry {
597 body,
598 handlers,
599 orelse,
600 finalbody,
601 ..
602 }) => {
603 if finalbody.is_empty() {
604 if orelse.is_empty() {
605 if handlers.is_empty() {
606 body
607 } else {
608 return handlers.last().map(AnyNodeRef::from);
609 }
610 } else {
611 orelse
612 }
613 } else {
614 finalbody
615 }
616 }
617
618 _ => return None,
620 };
621
622 body.last().map(AnyNodeRef::from)
623 }
624
625 pub fn is_first_statement_in_body(&self, body: AnyNodeRef) -> bool {
667 match body {
668 AnyNodeRef::StmtFor(ast::StmtFor { body, orelse, .. })
669 | AnyNodeRef::StmtWhile(ast::StmtWhile { body, orelse, .. }) => {
670 are_same_optional(*self, body.first()) || are_same_optional(*self, orelse.first())
671 }
672
673 AnyNodeRef::StmtTry(ast::StmtTry {
674 body,
675 orelse,
676 finalbody,
677 ..
678 }) => {
679 are_same_optional(*self, body.first())
680 || are_same_optional(*self, orelse.first())
681 || are_same_optional(*self, finalbody.first())
682 }
683
684 AnyNodeRef::StmtIf(ast::StmtIf { body, .. })
685 | AnyNodeRef::ElifElseClause(ast::ElifElseClause { body, .. })
686 | AnyNodeRef::StmtWith(ast::StmtWith { body, .. })
687 | AnyNodeRef::ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler {
688 body,
689 ..
690 })
691 | AnyNodeRef::MatchCase(MatchCase { body, .. })
692 | AnyNodeRef::StmtFunctionDef(ast::StmtFunctionDef { body, .. })
693 | AnyNodeRef::StmtClassDef(ast::StmtClassDef { body, .. }) => {
694 are_same_optional(*self, body.first())
695 }
696
697 AnyNodeRef::StmtMatch(ast::StmtMatch { cases, .. }) => {
698 are_same_optional(*self, cases.first())
699 }
700
701 _ => false,
702 }
703 }
704
705 pub fn is_first_statement_in_alternate_body(&self, body: AnyNodeRef) -> bool {
707 match body {
708 AnyNodeRef::StmtFor(ast::StmtFor { orelse, .. })
709 | AnyNodeRef::StmtWhile(ast::StmtWhile { orelse, .. }) => {
710 are_same_optional(*self, orelse.first())
711 }
712
713 AnyNodeRef::StmtTry(ast::StmtTry {
714 handlers,
715 orelse,
716 finalbody,
717 ..
718 }) => {
719 are_same_optional(*self, handlers.first())
720 || are_same_optional(*self, orelse.first())
721 || are_same_optional(*self, finalbody.first())
722 }
723
724 AnyNodeRef::StmtIf(ast::StmtIf {
725 elif_else_clauses, ..
726 }) => are_same_optional(*self, elif_else_clauses.first()),
727 _ => false,
728 }
729 }
730}
731
732fn are_same_optional<'a, T>(left: AnyNodeRef, right: Option<T>) -> bool
734where
735 T: Into<AnyNodeRef<'a>>,
736{
737 right.is_some_and(|right| left.ptr_eq(right.into()))
738}