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