syntax/ast/
node_ext.rs

1//! Various extension methods to ast Nodes, which are hard to code-generate.
2//! Extensions for various expressions live in a sibling `expr_extensions` module.
3//!
4//! These methods should only do simple, shallow tasks related to the syntax of the node itself.
5
6use 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    // FIXME: remove all these methods, they belong to ast::StmtList
90    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    /// Block expressions accept outer and inner attributes, but only when they are the outer
97    /// expression of an expression statement or the final expression of another block expression.
98    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    /// Returns `true` if the attr_kind is [`Inner`](Self::Inner).
185    pub fn is_inner(&self) -> bool {
186        matches!(self, Self::Inner)
187    }
188
189    /// Returns `true` if the attr_kind is [`Outer`](Self::Outer).
190    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            // FIXME: Move this over to `ast::TypeAnchor`
291            // <T> or <T as Trait>
292            // T is any TypeRef, Trait has to be a PathType
293            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    /// Remove the unnecessary braces in current `UseTreeList`
405    pub fn remove_unnecessary_braces(mut self) {
406        // Returns true iff there is a single subtree and it is not the self keyword. The braces in
407        // `use x::{self};` are necessary and so we should not remove them.
408        let has_single_subtree_that_is_not_self = |u: &ast::UseTreeList| {
409            if let Some((single_subtree,)) = u.use_trees().collect_tuple() {
410                // We have a single subtree, check whether it is self.
411
412                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                // Not a single subtree
420                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        // take `use crate::{{{{A}}}}` for example
437        // the below remove the innermost {}, got `use crate::{{{A}}}`
438        remove_brace_in_use_tree_list(&self);
439
440        // the below remove other unnecessary {}, got `use crate::A`
441        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
479// [#15778](https://github.com/rust-lang/rust-analyzer/issues/15778)
480impl 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    /// Deals with field init shorthand
533    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    /// Deals with field init shorthand
672    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            // FIXME: Accepting floats here to reject them in validation later
733            .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    /// self
787    Owned,
788    /// &self
789    Ref,
790    /// &mut self
791    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    /// Trait
807    PathType(Option<ast::ForBinder>, ast::PathType),
808    /// use
809    Use(ast::UseBoundGenericArgs),
810    /// 'a
811    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    /// Returns the parent ast::Module, this is different than the semantic parent in that this only
926    /// considers parent declarations in the AST
927    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        // If the iterable is a BlockExpr, check if the body is missing.
1039        // If it is assume the iterable is the expression that is missing instead.
1040        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        // If the condition is a BlockExpr, check if the body is missing.
1061        // If it is assume the condition is the expression that is missing instead.
1062        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    /// This is not a [`ast::Name`], because the name may be a keyword.
1122    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/// An iterator over the elements in an [`ast::TokenTree`].
1140///
1141/// Does not yield trivia or the delimiters.
1142#[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(); // Bump the opening delimiter.
1152        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}