1use std::{borrow::Cow, fmt, iter::successors};
7
8use itertools::Itertools;
9use parser::SyntaxKind;
10use rowan::{GreenNodeData, GreenTokenData};
11
12use crate::{
13 NodeOrToken, SmolStr, SyntaxElement, SyntaxElementChildren, SyntaxToken, T, TokenText,
14 ast::{
15 self, AstNode, AstToken, HasAttrs, HasGenericArgs, HasGenericParams, HasName,
16 HasTypeBounds, SyntaxNode, support,
17 },
18 ted,
19};
20
21use super::{GenericParam, RangeItem, RangeOp};
22
23impl ast::Lifetime {
24 pub fn text(&self) -> TokenText<'_> {
25 text_of_first_token(self.syntax())
26 }
27}
28
29impl ast::Name {
30 pub fn text(&self) -> TokenText<'_> {
31 text_of_first_token(self.syntax())
32 }
33 pub fn text_non_mutable(&self) -> &str {
34 fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
35 green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
36 }
37
38 match self.syntax().green() {
39 Cow::Borrowed(green_ref) => first_token(green_ref).text(),
40 Cow::Owned(_) => unreachable!(),
41 }
42 }
43}
44
45impl ast::NameRef {
46 pub fn text(&self) -> TokenText<'_> {
47 text_of_first_token(self.syntax())
48 }
49 pub fn text_non_mutable(&self) -> &str {
50 fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
51 green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
52 }
53
54 match self.syntax().green() {
55 Cow::Borrowed(green_ref) => first_token(green_ref).text(),
56 Cow::Owned(_) => unreachable!(),
57 }
58 }
59
60 pub fn as_tuple_field(&self) -> Option<usize> {
61 self.text().parse().ok()
62 }
63
64 pub fn token_kind(&self) -> SyntaxKind {
65 self.syntax().first_token().map_or(SyntaxKind::ERROR, |it| it.kind())
66 }
67}
68
69fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
70 fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
71 green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
72 }
73
74 match node.green() {
75 Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()),
76 Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()),
77 }
78}
79
80impl ast::Abi {
81 pub fn abi_string(&self) -> Option<ast::String> {
82 support::token(&self.syntax, SyntaxKind::STRING).and_then(ast::String::cast)
83 }
84}
85
86impl ast::HasModuleItem for ast::StmtList {}
87
88impl ast::BlockExpr {
89 pub fn statements(&self) -> impl Iterator<Item = ast::Stmt> {
91 self.stmt_list().into_iter().flat_map(|it| it.statements())
92 }
93 pub fn tail_expr(&self) -> Option<ast::Expr> {
94 self.stmt_list()?.tail_expr()
95 }
96 pub fn may_carry_attributes(&self) -> bool {
99 matches!(
100 self.syntax().parent().map(|it| it.kind()),
101 Some(SyntaxKind::BLOCK_EXPR | SyntaxKind::EXPR_STMT)
102 )
103 }
104}
105
106#[derive(Debug, PartialEq, Eq, Clone)]
107pub enum Macro {
108 MacroRules(ast::MacroRules),
109 MacroDef(ast::MacroDef),
110}
111
112impl From<ast::MacroRules> for Macro {
113 fn from(it: ast::MacroRules) -> Self {
114 Macro::MacroRules(it)
115 }
116}
117
118impl From<ast::MacroDef> for Macro {
119 fn from(it: ast::MacroDef) -> Self {
120 Macro::MacroDef(it)
121 }
122}
123
124impl AstNode for Macro {
125 fn can_cast(kind: SyntaxKind) -> bool {
126 matches!(kind, SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF)
127 }
128 fn cast(syntax: SyntaxNode) -> Option<Self> {
129 let res = match syntax.kind() {
130 SyntaxKind::MACRO_RULES => Macro::MacroRules(ast::MacroRules { syntax }),
131 SyntaxKind::MACRO_DEF => Macro::MacroDef(ast::MacroDef { syntax }),
132 _ => return None,
133 };
134 Some(res)
135 }
136 fn syntax(&self) -> &SyntaxNode {
137 match self {
138 Macro::MacroRules(it) => it.syntax(),
139 Macro::MacroDef(it) => it.syntax(),
140 }
141 }
142}
143
144impl HasName for Macro {
145 fn name(&self) -> Option<ast::Name> {
146 match self {
147 Macro::MacroRules(mac) => mac.name(),
148 Macro::MacroDef(mac) => mac.name(),
149 }
150 }
151}
152
153impl HasAttrs for Macro {}
154
155impl From<ast::AssocItem> for ast::Item {
156 fn from(assoc: ast::AssocItem) -> Self {
157 match assoc {
158 ast::AssocItem::Const(it) => ast::Item::Const(it),
159 ast::AssocItem::Fn(it) => ast::Item::Fn(it),
160 ast::AssocItem::MacroCall(it) => ast::Item::MacroCall(it),
161 ast::AssocItem::TypeAlias(it) => ast::Item::TypeAlias(it),
162 }
163 }
164}
165
166impl From<ast::ExternItem> for ast::Item {
167 fn from(extern_item: ast::ExternItem) -> Self {
168 match extern_item {
169 ast::ExternItem::Static(it) => ast::Item::Static(it),
170 ast::ExternItem::Fn(it) => ast::Item::Fn(it),
171 ast::ExternItem::MacroCall(it) => ast::Item::MacroCall(it),
172 ast::ExternItem::TypeAlias(it) => ast::Item::TypeAlias(it),
173 }
174 }
175}
176
177#[derive(Debug, Copy, Clone, PartialEq, Eq)]
178pub enum AttrKind {
179 Inner,
180 Outer,
181}
182
183impl AttrKind {
184 pub fn is_inner(&self) -> bool {
186 matches!(self, Self::Inner)
187 }
188
189 pub fn is_outer(&self) -> bool {
191 matches!(self, Self::Outer)
192 }
193}
194
195impl ast::Attr {
196 pub fn as_simple_atom(&self) -> Option<SmolStr> {
197 let meta = self.meta()?;
198 if meta.eq_token().is_some() || meta.token_tree().is_some() {
199 return None;
200 }
201 self.simple_name()
202 }
203
204 pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
205 let tt = self.meta()?.token_tree()?;
206 Some((self.simple_name()?, tt))
207 }
208
209 pub fn as_simple_path(&self) -> Option<ast::Path> {
210 let meta = self.meta()?;
211 if meta.eq_token().is_some() || meta.token_tree().is_some() {
212 return None;
213 }
214 self.path()
215 }
216
217 pub fn simple_name(&self) -> Option<SmolStr> {
218 let path = self.meta()?.path()?;
219 match (path.segment(), path.qualifier()) {
220 (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()),
221 _ => None,
222 }
223 }
224
225 pub fn kind(&self) -> AttrKind {
226 match self.excl_token() {
227 Some(_) => AttrKind::Inner,
228 None => AttrKind::Outer,
229 }
230 }
231
232 pub fn path(&self) -> Option<ast::Path> {
233 self.meta()?.path()
234 }
235
236 pub fn expr(&self) -> Option<ast::Expr> {
237 self.meta()?.expr()
238 }
239
240 pub fn token_tree(&self) -> Option<ast::TokenTree> {
241 self.meta()?.token_tree()
242 }
243}
244
245#[derive(Debug, Clone, PartialEq, Eq)]
246pub enum PathSegmentKind {
247 Name(ast::NameRef),
248 Type { type_ref: Option<ast::Type>, trait_ref: Option<ast::PathType> },
249 SelfTypeKw,
250 SelfKw,
251 SuperKw,
252 CrateKw,
253}
254
255impl ast::PathSegment {
256 pub fn parent_path(&self) -> ast::Path {
257 self.syntax()
258 .parent()
259 .and_then(ast::Path::cast)
260 .expect("segments are always nested in paths")
261 }
262
263 pub fn crate_token(&self) -> Option<SyntaxToken> {
264 self.name_ref().and_then(|it| it.crate_token())
265 }
266
267 pub fn self_token(&self) -> Option<SyntaxToken> {
268 self.name_ref().and_then(|it| it.self_token())
269 }
270
271 pub fn self_type_token(&self) -> Option<SyntaxToken> {
272 self.name_ref().and_then(|it| it.Self_token())
273 }
274
275 pub fn super_token(&self) -> Option<SyntaxToken> {
276 self.name_ref().and_then(|it| it.super_token())
277 }
278
279 pub fn kind(&self) -> Option<PathSegmentKind> {
280 let res = if let Some(name_ref) = self.name_ref() {
281 match name_ref.token_kind() {
282 T![Self] => PathSegmentKind::SelfTypeKw,
283 T![self] => PathSegmentKind::SelfKw,
284 T![super] => PathSegmentKind::SuperKw,
285 T![crate] => PathSegmentKind::CrateKw,
286 _ => PathSegmentKind::Name(name_ref),
287 }
288 } else {
289 let anchor = self.type_anchor()?;
290 let mut type_refs =
294 anchor.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
295 let type_ref = type_refs.next().and_then(ast::Type::cast);
296 let trait_ref = type_refs.next().and_then(ast::PathType::cast);
297 PathSegmentKind::Type { type_ref, trait_ref }
298 };
299 Some(res)
300 }
301}
302
303impl ast::Path {
304 pub fn parent_path(&self) -> Option<ast::Path> {
305 self.syntax().parent().and_then(ast::Path::cast)
306 }
307
308 pub fn as_single_segment(&self) -> Option<ast::PathSegment> {
309 match self.qualifier() {
310 Some(_) => None,
311 None => self.segment(),
312 }
313 }
314
315 pub fn as_single_name_ref(&self) -> Option<ast::NameRef> {
316 match self.qualifier() {
317 Some(_) => None,
318 None => self.segment()?.name_ref(),
319 }
320 }
321
322 pub fn first_qualifier_or_self(&self) -> ast::Path {
323 successors(Some(self.clone()), ast::Path::qualifier).last().unwrap()
324 }
325
326 pub fn first_qualifier(&self) -> Option<ast::Path> {
327 successors(self.qualifier(), ast::Path::qualifier).last()
328 }
329
330 pub fn first_segment(&self) -> Option<ast::PathSegment> {
331 self.first_qualifier_or_self().segment()
332 }
333
334 pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
335 let path_range = self.syntax().text_range();
336 successors(self.first_segment(), move |p| {
337 p.parent_path().parent_path().and_then(|p| {
338 if path_range.contains_range(p.syntax().text_range()) { p.segment() } else { None }
339 })
340 })
341 }
342
343 pub fn qualifiers(&self) -> impl Iterator<Item = ast::Path> + Clone {
344 successors(self.qualifier(), |p| p.qualifier())
345 }
346
347 pub fn top_path(&self) -> ast::Path {
348 let mut this = self.clone();
349 while let Some(path) = this.parent_path() {
350 this = path;
351 }
352 this
353 }
354}
355
356impl ast::Use {
357 pub fn is_simple_glob(&self) -> bool {
358 self.use_tree().is_some_and(|use_tree| {
359 use_tree.use_tree_list().is_none() && use_tree.star_token().is_some()
360 })
361 }
362}
363
364impl ast::UseTree {
365 pub fn is_simple_path(&self) -> bool {
366 self.use_tree_list().is_none() && self.star_token().is_none()
367 }
368
369 pub fn parent_use_tree_list(&self) -> Option<ast::UseTreeList> {
370 self.syntax().parent().and_then(ast::UseTreeList::cast)
371 }
372
373 pub fn top_use_tree(&self) -> ast::UseTree {
374 let mut this = self.clone();
375 while let Some(use_tree_list) = this.parent_use_tree_list() {
376 this = use_tree_list.parent_use_tree();
377 }
378 this
379 }
380}
381
382impl ast::UseTreeList {
383 pub fn parent_use_tree(&self) -> ast::UseTree {
384 self.syntax()
385 .parent()
386 .and_then(ast::UseTree::cast)
387 .expect("UseTreeLists are always nested in UseTrees")
388 }
389
390 pub fn has_inner_comment(&self) -> bool {
391 self.syntax()
392 .children_with_tokens()
393 .filter_map(|it| it.into_token())
394 .find_map(ast::Comment::cast)
395 .is_some()
396 }
397
398 pub fn comma(&self) -> impl Iterator<Item = SyntaxToken> {
399 self.syntax()
400 .children_with_tokens()
401 .filter_map(|it| it.into_token().filter(|it| it.kind() == T![,]))
402 }
403
404 pub fn remove_unnecessary_braces(mut self) {
406 let has_single_subtree_that_is_not_self = |u: &ast::UseTreeList| {
409 if let Some((single_subtree,)) = u.use_trees().collect_tuple() {
410 let is_self = single_subtree.path().as_ref().is_some_and(|path| {
413 path.segment().and_then(|seg| seg.self_token()).is_some()
414 && path.qualifier().is_none()
415 });
416
417 !is_self
418 } else {
419 false
421 }
422 };
423
424 let remove_brace_in_use_tree_list = |u: &ast::UseTreeList| {
425 if has_single_subtree_that_is_not_self(u) {
426 if let Some(a) = u.l_curly_token() {
427 ted::remove(a)
428 }
429 if let Some(a) = u.r_curly_token() {
430 ted::remove(a)
431 }
432 u.comma().for_each(ted::remove);
433 }
434 };
435
436 remove_brace_in_use_tree_list(&self);
439
440 while let Some(parent_use_tree_list) = self.parent_use_tree().parent_use_tree_list() {
442 remove_brace_in_use_tree_list(&parent_use_tree_list);
443 self = parent_use_tree_list;
444 }
445 }
446}
447
448impl ast::Impl {
449 pub fn self_ty(&self) -> Option<ast::Type> {
450 self.target().1
451 }
452
453 pub fn trait_(&self) -> Option<ast::Type> {
454 self.target().0
455 }
456
457 fn target(&self) -> (Option<ast::Type>, Option<ast::Type>) {
458 let mut types = support::children(self.syntax()).peekable();
459 let for_kw = self.for_token();
460 let trait_ = types.next_if(|trait_: &ast::Type| {
461 for_kw.is_some_and(|for_kw| {
462 trait_.syntax().text_range().start() < for_kw.text_range().start()
463 })
464 });
465 let self_ty = types.next();
466 (trait_, self_ty)
467 }
468
469 pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> {
470 let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?;
471 if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() {
472 Some(this)
473 } else {
474 None
475 }
476 }
477}
478
479impl ast::PathSegment {
481 pub fn qualifying_trait(&self) -> Option<ast::PathType> {
482 let mut path_types = support::children(self.type_anchor()?.syntax());
483 let first = path_types.next()?;
484 path_types.next().or(Some(first))
485 }
486}
487
488#[derive(Debug, Clone, PartialEq, Eq)]
489pub enum StructKind {
490 Record(ast::RecordFieldList),
491 Tuple(ast::TupleFieldList),
492 Unit,
493}
494
495impl StructKind {
496 fn from_node<N: AstNode>(node: &N) -> StructKind {
497 if let Some(nfdl) = support::child::<ast::RecordFieldList>(node.syntax()) {
498 StructKind::Record(nfdl)
499 } else if let Some(pfl) = support::child::<ast::TupleFieldList>(node.syntax()) {
500 StructKind::Tuple(pfl)
501 } else {
502 StructKind::Unit
503 }
504 }
505}
506
507impl ast::Struct {
508 pub fn kind(&self) -> StructKind {
509 StructKind::from_node(self)
510 }
511}
512
513impl ast::Union {
514 pub fn kind(&self) -> StructKind {
515 StructKind::from_node(self)
516 }
517}
518
519impl ast::RecordExprField {
520 pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
521 let candidate = Self::for_name_ref(field_name)?;
522 if candidate.field_name().as_ref() == Some(field_name) { Some(candidate) } else { None }
523 }
524
525 pub fn for_name_ref(name_ref: &ast::NameRef) -> Option<ast::RecordExprField> {
526 let syn = name_ref.syntax();
527 syn.parent()
528 .and_then(ast::RecordExprField::cast)
529 .or_else(|| syn.ancestors().nth(4).and_then(ast::RecordExprField::cast))
530 }
531
532 pub fn field_name(&self) -> Option<ast::NameRef> {
534 if let Some(name_ref) = self.name_ref() {
535 return Some(name_ref);
536 }
537 if let ast::Expr::PathExpr(expr) = self.expr()? {
538 let path = expr.path()?;
539 let segment = path.segment()?;
540 let name_ref = segment.name_ref()?;
541 if path.qualifier().is_none() {
542 return Some(name_ref);
543 }
544 }
545 None
546 }
547}
548
549#[derive(Debug, Clone)]
550pub enum NameLike {
551 NameRef(ast::NameRef),
552 Name(ast::Name),
553 Lifetime(ast::Lifetime),
554}
555
556impl NameLike {
557 pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
558 match self {
559 NameLike::NameRef(name_ref) => Some(name_ref),
560 _ => None,
561 }
562 }
563 pub fn as_lifetime(&self) -> Option<&ast::Lifetime> {
564 match self {
565 NameLike::Lifetime(lifetime) => Some(lifetime),
566 _ => None,
567 }
568 }
569 pub fn text(&self) -> TokenText<'_> {
570 match self {
571 NameLike::NameRef(name_ref) => name_ref.text(),
572 NameLike::Name(name) => name.text(),
573 NameLike::Lifetime(lifetime) => lifetime.text(),
574 }
575 }
576}
577
578impl ast::AstNode for NameLike {
579 fn can_cast(kind: SyntaxKind) -> bool {
580 matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME)
581 }
582 fn cast(syntax: SyntaxNode) -> Option<Self> {
583 let res = match syntax.kind() {
584 SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }),
585 SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }),
586 SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }),
587 _ => return None,
588 };
589 Some(res)
590 }
591 fn syntax(&self) -> &SyntaxNode {
592 match self {
593 NameLike::NameRef(it) => it.syntax(),
594 NameLike::Name(it) => it.syntax(),
595 NameLike::Lifetime(it) => it.syntax(),
596 }
597 }
598}
599
600const _: () = {
601 use ast::{Lifetime, Name, NameRef};
602 stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
603};
604
605#[derive(Debug, Clone, PartialEq)]
606pub enum NameOrNameRef {
607 Name(ast::Name),
608 NameRef(ast::NameRef),
609}
610
611impl fmt::Display for NameOrNameRef {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 match self {
614 NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
615 NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
616 }
617 }
618}
619
620impl ast::AstNode for NameOrNameRef {
621 fn can_cast(kind: SyntaxKind) -> bool {
622 matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF)
623 }
624 fn cast(syntax: SyntaxNode) -> Option<Self> {
625 let res = match syntax.kind() {
626 SyntaxKind::NAME => NameOrNameRef::Name(ast::Name { syntax }),
627 SyntaxKind::NAME_REF => NameOrNameRef::NameRef(ast::NameRef { syntax }),
628 _ => return None,
629 };
630 Some(res)
631 }
632 fn syntax(&self) -> &SyntaxNode {
633 match self {
634 NameOrNameRef::NameRef(it) => it.syntax(),
635 NameOrNameRef::Name(it) => it.syntax(),
636 }
637 }
638}
639
640impl NameOrNameRef {
641 pub fn text(&self) -> TokenText<'_> {
642 match self {
643 NameOrNameRef::Name(name) => name.text(),
644 NameOrNameRef::NameRef(name_ref) => name_ref.text(),
645 }
646 }
647}
648
649impl ast::RecordPatField {
650 pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
651 let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
652 match candidate.field_name()? {
653 NameOrNameRef::NameRef(name_ref) if name_ref == *field_name => Some(candidate),
654 _ => None,
655 }
656 }
657
658 pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
659 let candidate =
660 field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
661 match candidate.field_name()? {
662 NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
663 _ => None,
664 }
665 }
666
667 pub fn parent_record_pat(&self) -> ast::RecordPat {
668 self.syntax().ancestors().find_map(ast::RecordPat::cast).unwrap()
669 }
670
671 pub fn field_name(&self) -> Option<NameOrNameRef> {
673 if let Some(name_ref) = self.name_ref() {
674 return Some(NameOrNameRef::NameRef(name_ref));
675 }
676 match self.pat() {
677 Some(ast::Pat::IdentPat(pat)) => {
678 let name = pat.name()?;
679 Some(NameOrNameRef::Name(name))
680 }
681 Some(ast::Pat::BoxPat(pat)) => match pat.pat() {
682 Some(ast::Pat::IdentPat(pat)) => {
683 let name = pat.name()?;
684 Some(NameOrNameRef::Name(name))
685 }
686 _ => None,
687 },
688 _ => None,
689 }
690 }
691}
692
693impl ast::Variant {
694 pub fn parent_enum(&self) -> ast::Enum {
695 self.syntax()
696 .parent()
697 .and_then(|it| it.parent())
698 .and_then(ast::Enum::cast)
699 .expect("EnumVariants are always nested in Enums")
700 }
701 pub fn kind(&self) -> StructKind {
702 StructKind::from_node(self)
703 }
704}
705
706impl ast::Item {
707 pub fn generic_param_list(&self) -> Option<ast::GenericParamList> {
708 ast::AnyHasGenericParams::cast(self.syntax().clone())?.generic_param_list()
709 }
710}
711
712impl ast::Type {
713 pub fn generic_arg_list(&self) -> Option<ast::GenericArgList> {
714 if let ast::Type::PathType(path_type) = self {
715 path_type.path()?.segment()?.generic_arg_list()
716 } else {
717 None
718 }
719 }
720}
721
722#[derive(Debug, Clone, PartialEq, Eq)]
723pub enum FieldKind {
724 Name(ast::NameRef),
725 Index(SyntaxToken),
726}
727
728impl ast::FieldExpr {
729 pub fn index_token(&self) -> Option<SyntaxToken> {
730 self.syntax
731 .children_with_tokens()
732 .find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
734 .as_ref()
735 .and_then(SyntaxElement::as_token)
736 .cloned()
737 }
738
739 pub fn field_access(&self) -> Option<FieldKind> {
740 match self.name_ref() {
741 Some(nr) => Some(FieldKind::Name(nr)),
742 None => self.index_token().map(FieldKind::Index),
743 }
744 }
745}
746
747pub struct SlicePatComponents {
748 pub prefix: Vec<ast::Pat>,
749 pub slice: Option<ast::Pat>,
750 pub suffix: Vec<ast::Pat>,
751}
752
753impl ast::SlicePat {
754 pub fn components(&self) -> SlicePatComponents {
755 let mut args = self.pats().peekable();
756 let prefix = args
757 .peeking_take_while(|p| match p {
758 ast::Pat::RestPat(_) => false,
759 ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
760 ast::Pat::RefPat(rp) => match rp.pat() {
761 Some(ast::Pat::RestPat(_)) => false,
762 Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
763 _ => true,
764 },
765 _ => true,
766 })
767 .collect();
768 let slice = args.next();
769 let suffix = args.collect();
770
771 SlicePatComponents { prefix, slice, suffix }
772 }
773}
774
775impl ast::IdentPat {
776 pub fn is_simple_ident(&self) -> bool {
777 self.at_token().is_none()
778 && self.mut_token().is_none()
779 && self.ref_token().is_none()
780 && self.pat().is_none()
781 }
782}
783
784#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
785pub enum SelfParamKind {
786 Owned,
788 Ref,
790 MutRef,
792}
793
794impl ast::SelfParam {
795 pub fn kind(&self) -> SelfParamKind {
796 if self.amp_token().is_some() {
797 if self.mut_token().is_some() { SelfParamKind::MutRef } else { SelfParamKind::Ref }
798 } else {
799 SelfParamKind::Owned
800 }
801 }
802}
803
804#[derive(Clone, Debug, PartialEq, Eq, Hash)]
805pub enum TypeBoundKind {
806 PathType(Option<ast::ForBinder>, ast::PathType),
808 Use(ast::UseBoundGenericArgs),
810 Lifetime(ast::Lifetime),
812}
813
814impl ast::TypeBound {
815 pub fn kind(&self) -> Option<TypeBoundKind> {
816 if let Some(path_type) = support::children(self.syntax()).next() {
817 Some(TypeBoundKind::PathType(self.for_binder(), path_type))
818 } else if let Some(for_binder) = support::children::<ast::ForType>(&self.syntax).next() {
819 let Some(ast::Type::PathType(path_type)) = for_binder.ty() else { return None };
820 Some(TypeBoundKind::PathType(for_binder.for_binder(), path_type))
821 } else if let Some(args) = self.use_bound_generic_args() {
822 Some(TypeBoundKind::Use(args))
823 } else if let Some(lifetime) = self.lifetime() {
824 Some(TypeBoundKind::Lifetime(lifetime))
825 } else {
826 unreachable!()
827 }
828 }
829}
830
831#[derive(Debug, Clone)]
832pub enum TypeOrConstParam {
833 Type(ast::TypeParam),
834 Const(ast::ConstParam),
835}
836
837impl From<TypeOrConstParam> for GenericParam {
838 fn from(value: TypeOrConstParam) -> Self {
839 match value {
840 TypeOrConstParam::Type(it) => GenericParam::TypeParam(it),
841 TypeOrConstParam::Const(it) => GenericParam::ConstParam(it),
842 }
843 }
844}
845
846impl TypeOrConstParam {
847 pub fn name(&self) -> Option<ast::Name> {
848 match self {
849 TypeOrConstParam::Type(x) => x.name(),
850 TypeOrConstParam::Const(x) => x.name(),
851 }
852 }
853}
854
855impl AstNode for TypeOrConstParam {
856 fn can_cast(kind: SyntaxKind) -> bool
857 where
858 Self: Sized,
859 {
860 matches!(kind, SyntaxKind::TYPE_PARAM | SyntaxKind::CONST_PARAM)
861 }
862
863 fn cast(syntax: SyntaxNode) -> Option<Self>
864 where
865 Self: Sized,
866 {
867 let res = match syntax.kind() {
868 SyntaxKind::TYPE_PARAM => TypeOrConstParam::Type(ast::TypeParam { syntax }),
869 SyntaxKind::CONST_PARAM => TypeOrConstParam::Const(ast::ConstParam { syntax }),
870 _ => return None,
871 };
872 Some(res)
873 }
874
875 fn syntax(&self) -> &SyntaxNode {
876 match self {
877 TypeOrConstParam::Type(it) => it.syntax(),
878 TypeOrConstParam::Const(it) => it.syntax(),
879 }
880 }
881}
882
883impl HasAttrs for TypeOrConstParam {}
884
885pub enum VisibilityKind {
886 In(ast::Path),
887 PubCrate,
888 PubSuper,
889 PubSelf,
890 Pub,
891}
892
893impl ast::Visibility {
894 pub fn kind(&self) -> VisibilityKind {
895 match self.path() {
896 Some(path) => {
897 if let Some(segment) =
898 path.as_single_segment().filter(|it| it.coloncolon_token().is_none())
899 {
900 if segment.crate_token().is_some() {
901 return VisibilityKind::PubCrate;
902 } else if segment.super_token().is_some() {
903 return VisibilityKind::PubSuper;
904 } else if segment.self_token().is_some() {
905 return VisibilityKind::PubSelf;
906 }
907 }
908 VisibilityKind::In(path)
909 }
910 None => VisibilityKind::Pub,
911 }
912 }
913}
914
915impl ast::LifetimeParam {
916 pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
917 self.type_bound_list()
918 .into_iter()
919 .flat_map(|it| it.bounds())
920 .filter_map(|it| it.lifetime()?.lifetime_ident_token())
921 }
922}
923
924impl ast::Module {
925 pub fn parent(&self) -> Option<ast::Module> {
928 self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
929 }
930}
931
932impl RangeItem for ast::RangePat {
933 type Bound = ast::Pat;
934
935 fn start(&self) -> Option<ast::Pat> {
936 self.syntax()
937 .children_with_tokens()
938 .take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
939 .filter_map(|it| it.into_node())
940 .find_map(ast::Pat::cast)
941 }
942
943 fn end(&self) -> Option<ast::Pat> {
944 self.syntax()
945 .children_with_tokens()
946 .skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
947 .filter_map(|it| it.into_node())
948 .find_map(ast::Pat::cast)
949 }
950
951 fn op_token(&self) -> Option<SyntaxToken> {
952 self.syntax().children_with_tokens().find_map(|it| {
953 let token = it.into_token()?;
954
955 match token.kind() {
956 T![..] => Some(token),
957 T![..=] => Some(token),
958 _ => None,
959 }
960 })
961 }
962
963 fn op_kind(&self) -> Option<RangeOp> {
964 self.syntax().children_with_tokens().find_map(|it| {
965 let token = it.into_token()?;
966
967 match token.kind() {
968 T![..] => Some(RangeOp::Exclusive),
969 T![..=] => Some(RangeOp::Inclusive),
970 _ => None,
971 }
972 })
973 }
974}
975
976impl ast::TokenTree {
977 pub fn token_trees_and_tokens(
978 &self,
979 ) -> impl Iterator<Item = NodeOrToken<ast::TokenTree, SyntaxToken>> {
980 self.syntax().children_with_tokens().filter_map(|not| match not {
981 NodeOrToken::Node(node) => ast::TokenTree::cast(node).map(NodeOrToken::Node),
982 NodeOrToken::Token(t) => Some(NodeOrToken::Token(t)),
983 })
984 }
985
986 pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
987 self.syntax()
988 .first_child_or_token()?
989 .into_token()
990 .filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
991 }
992
993 pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
994 self.syntax()
995 .last_child_or_token()?
996 .into_token()
997 .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
998 }
999
1000 pub fn parent_meta(&self) -> Option<ast::Meta> {
1001 self.syntax().parent().and_then(ast::Meta::cast)
1002 }
1003}
1004
1005impl ast::Meta {
1006 pub fn parent_attr(&self) -> Option<ast::Attr> {
1007 self.syntax().parent().and_then(ast::Attr::cast)
1008 }
1009}
1010
1011impl ast::GenericArgList {
1012 pub fn lifetime_args(&self) -> impl Iterator<Item = ast::LifetimeArg> {
1013 self.generic_args().filter_map(|arg| match arg {
1014 ast::GenericArg::LifetimeArg(it) => Some(it),
1015 _ => None,
1016 })
1017 }
1018}
1019
1020impl ast::GenericParamList {
1021 pub fn lifetime_params(&self) -> impl Iterator<Item = ast::LifetimeParam> {
1022 self.generic_params().filter_map(|param| match param {
1023 ast::GenericParam::LifetimeParam(it) => Some(it),
1024 ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
1025 })
1026 }
1027 pub fn type_or_const_params(&self) -> impl Iterator<Item = ast::TypeOrConstParam> + use<> {
1028 self.generic_params().filter_map(|param| match param {
1029 ast::GenericParam::TypeParam(it) => Some(ast::TypeOrConstParam::Type(it)),
1030 ast::GenericParam::LifetimeParam(_) => None,
1031 ast::GenericParam::ConstParam(it) => Some(ast::TypeOrConstParam::Const(it)),
1032 })
1033 }
1034}
1035
1036impl ast::ForExpr {
1037 pub fn iterable(&self) -> Option<ast::Expr> {
1038 let mut exprs = support::children(self.syntax());
1041 let first = exprs.next();
1042 match first {
1043 Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
1044 first => first,
1045 }
1046 }
1047}
1048
1049impl ast::HasLoopBody for ast::ForExpr {
1050 fn loop_body(&self) -> Option<ast::BlockExpr> {
1051 let mut exprs = support::children(self.syntax());
1052 let first = exprs.next();
1053 let second = exprs.next();
1054 second.or(first)
1055 }
1056}
1057
1058impl ast::WhileExpr {
1059 pub fn condition(&self) -> Option<ast::Expr> {
1060 let mut exprs = support::children(self.syntax());
1063 let first = exprs.next();
1064 match first {
1065 Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
1066 first => first,
1067 }
1068 }
1069}
1070
1071impl ast::HasLoopBody for ast::WhileExpr {
1072 fn loop_body(&self) -> Option<ast::BlockExpr> {
1073 let mut exprs = support::children(self.syntax());
1074 let first = exprs.next();
1075 let second = exprs.next();
1076 second.or(first)
1077 }
1078}
1079
1080impl ast::HasAttrs for ast::AnyHasDocComments {}
1081
1082impl From<ast::Adt> for ast::Item {
1083 fn from(it: ast::Adt) -> Self {
1084 match it {
1085 ast::Adt::Enum(it) => ast::Item::Enum(it),
1086 ast::Adt::Struct(it) => ast::Item::Struct(it),
1087 ast::Adt::Union(it) => ast::Item::Union(it),
1088 }
1089 }
1090}
1091
1092impl ast::MatchGuard {
1093 pub fn condition(&self) -> Option<ast::Expr> {
1094 support::child(&self.syntax)
1095 }
1096}
1097
1098impl ast::MatchArm {
1099 pub fn parent_match(&self) -> ast::MatchExpr {
1100 self.syntax()
1101 .parent()
1102 .and_then(|it| it.parent())
1103 .and_then(ast::MatchExpr::cast)
1104 .expect("MatchArms are always nested in MatchExprs")
1105 }
1106}
1107
1108impl From<ast::Item> for ast::AnyHasAttrs {
1109 fn from(node: ast::Item) -> Self {
1110 Self::new(node)
1111 }
1112}
1113
1114impl From<ast::AssocItem> for ast::AnyHasAttrs {
1115 fn from(node: ast::AssocItem) -> Self {
1116 Self::new(node)
1117 }
1118}
1119
1120impl ast::FormatArgsArgName {
1121 pub fn name(&self) -> SyntaxToken {
1123 let name = self.syntax.first_token().unwrap();
1124 assert!(name.kind().is_any_identifier());
1125 name
1126 }
1127}
1128
1129impl ast::OrPat {
1130 pub fn leading_pipe(&self) -> Option<SyntaxToken> {
1131 self.syntax
1132 .children_with_tokens()
1133 .find(|it| !it.kind().is_trivia())
1134 .and_then(NodeOrToken::into_token)
1135 .filter(|it| it.kind() == T![|])
1136 }
1137}
1138
1139#[derive(Clone)]
1143pub struct TokenTreeChildren {
1144 iter: SyntaxElementChildren,
1145}
1146
1147impl TokenTreeChildren {
1148 #[inline]
1149 pub fn new(tt: &ast::TokenTree) -> Self {
1150 let mut iter = tt.syntax.children_with_tokens();
1151 iter.next(); Self { iter }
1153 }
1154}
1155
1156impl Iterator for TokenTreeChildren {
1157 type Item = NodeOrToken<ast::TokenTree, SyntaxToken>;
1158
1159 #[inline]
1160 fn next(&mut self) -> Option<Self::Item> {
1161 self.iter.find_map(|item| match item {
1162 NodeOrToken::Node(node) => ast::TokenTree::cast(node).map(NodeOrToken::Node),
1163 NodeOrToken::Token(token) => {
1164 let kind = token.kind();
1165 (!matches!(
1166 kind,
1167 SyntaxKind::WHITESPACE | SyntaxKind::COMMENT | T![')'] | T![']'] | T!['}']
1168 ))
1169 .then_some(NodeOrToken::Token(token))
1170 }
1171 })
1172 }
1173}