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        match self.target() {
451            (Some(t), None) | (_, Some(t)) => Some(t),
452            _ => None,
453        }
454    }
455
456    pub fn trait_(&self) -> Option<ast::Type> {
457        match self.target() {
458            (Some(t), Some(_)) => Some(t),
459            _ => None,
460        }
461    }
462
463    fn target(&self) -> (Option<ast::Type>, Option<ast::Type>) {
464        let mut types = support::children(self.syntax());
465        let first = types.next();
466        let second = types.next();
467        (first, second)
468    }
469
470    pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> {
471        let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?;
472        if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() {
473            Some(this)
474        } else {
475            None
476        }
477    }
478}
479
480// [#15778](https://github.com/rust-lang/rust-analyzer/issues/15778)
481impl ast::PathSegment {
482    pub fn qualifying_trait(&self) -> Option<ast::PathType> {
483        let mut path_types = support::children(self.type_anchor()?.syntax());
484        let first = path_types.next()?;
485        path_types.next().or(Some(first))
486    }
487}
488
489#[derive(Debug, Clone, PartialEq, Eq)]
490pub enum StructKind {
491    Record(ast::RecordFieldList),
492    Tuple(ast::TupleFieldList),
493    Unit,
494}
495
496impl StructKind {
497    fn from_node<N: AstNode>(node: &N) -> StructKind {
498        if let Some(nfdl) = support::child::<ast::RecordFieldList>(node.syntax()) {
499            StructKind::Record(nfdl)
500        } else if let Some(pfl) = support::child::<ast::TupleFieldList>(node.syntax()) {
501            StructKind::Tuple(pfl)
502        } else {
503            StructKind::Unit
504        }
505    }
506}
507
508impl ast::Struct {
509    pub fn kind(&self) -> StructKind {
510        StructKind::from_node(self)
511    }
512}
513
514impl ast::Union {
515    pub fn kind(&self) -> StructKind {
516        StructKind::from_node(self)
517    }
518}
519
520impl ast::RecordExprField {
521    pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
522        let candidate = Self::for_name_ref(field_name)?;
523        if candidate.field_name().as_ref() == Some(field_name) { Some(candidate) } else { None }
524    }
525
526    pub fn for_name_ref(name_ref: &ast::NameRef) -> Option<ast::RecordExprField> {
527        let syn = name_ref.syntax();
528        syn.parent()
529            .and_then(ast::RecordExprField::cast)
530            .or_else(|| syn.ancestors().nth(4).and_then(ast::RecordExprField::cast))
531    }
532
533    /// Deals with field init shorthand
534    pub fn field_name(&self) -> Option<ast::NameRef> {
535        if let Some(name_ref) = self.name_ref() {
536            return Some(name_ref);
537        }
538        if let ast::Expr::PathExpr(expr) = self.expr()? {
539            let path = expr.path()?;
540            let segment = path.segment()?;
541            let name_ref = segment.name_ref()?;
542            if path.qualifier().is_none() {
543                return Some(name_ref);
544            }
545        }
546        None
547    }
548}
549
550#[derive(Debug, Clone)]
551pub enum NameLike {
552    NameRef(ast::NameRef),
553    Name(ast::Name),
554    Lifetime(ast::Lifetime),
555}
556
557impl NameLike {
558    pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
559        match self {
560            NameLike::NameRef(name_ref) => Some(name_ref),
561            _ => None,
562        }
563    }
564    pub fn as_lifetime(&self) -> Option<&ast::Lifetime> {
565        match self {
566            NameLike::Lifetime(lifetime) => Some(lifetime),
567            _ => None,
568        }
569    }
570    pub fn text(&self) -> TokenText<'_> {
571        match self {
572            NameLike::NameRef(name_ref) => name_ref.text(),
573            NameLike::Name(name) => name.text(),
574            NameLike::Lifetime(lifetime) => lifetime.text(),
575        }
576    }
577}
578
579impl ast::AstNode for NameLike {
580    fn can_cast(kind: SyntaxKind) -> bool {
581        matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME)
582    }
583    fn cast(syntax: SyntaxNode) -> Option<Self> {
584        let res = match syntax.kind() {
585            SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }),
586            SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }),
587            SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }),
588            _ => return None,
589        };
590        Some(res)
591    }
592    fn syntax(&self) -> &SyntaxNode {
593        match self {
594            NameLike::NameRef(it) => it.syntax(),
595            NameLike::Name(it) => it.syntax(),
596            NameLike::Lifetime(it) => it.syntax(),
597        }
598    }
599}
600
601const _: () = {
602    use ast::{Lifetime, Name, NameRef};
603    stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
604};
605
606#[derive(Debug, Clone, PartialEq)]
607pub enum NameOrNameRef {
608    Name(ast::Name),
609    NameRef(ast::NameRef),
610}
611
612impl fmt::Display for NameOrNameRef {
613    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
614        match self {
615            NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
616            NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
617        }
618    }
619}
620
621impl ast::AstNode for NameOrNameRef {
622    fn can_cast(kind: SyntaxKind) -> bool {
623        matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF)
624    }
625    fn cast(syntax: SyntaxNode) -> Option<Self> {
626        let res = match syntax.kind() {
627            SyntaxKind::NAME => NameOrNameRef::Name(ast::Name { syntax }),
628            SyntaxKind::NAME_REF => NameOrNameRef::NameRef(ast::NameRef { syntax }),
629            _ => return None,
630        };
631        Some(res)
632    }
633    fn syntax(&self) -> &SyntaxNode {
634        match self {
635            NameOrNameRef::NameRef(it) => it.syntax(),
636            NameOrNameRef::Name(it) => it.syntax(),
637        }
638    }
639}
640
641impl NameOrNameRef {
642    pub fn text(&self) -> TokenText<'_> {
643        match self {
644            NameOrNameRef::Name(name) => name.text(),
645            NameOrNameRef::NameRef(name_ref) => name_ref.text(),
646        }
647    }
648}
649
650impl ast::RecordPatField {
651    pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
652        let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
653        match candidate.field_name()? {
654            NameOrNameRef::NameRef(name_ref) if name_ref == *field_name => Some(candidate),
655            _ => None,
656        }
657    }
658
659    pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
660        let candidate =
661            field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
662        match candidate.field_name()? {
663            NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
664            _ => None,
665        }
666    }
667
668    pub fn parent_record_pat(&self) -> ast::RecordPat {
669        self.syntax().ancestors().find_map(ast::RecordPat::cast).unwrap()
670    }
671
672    /// Deals with field init shorthand
673    pub fn field_name(&self) -> Option<NameOrNameRef> {
674        if let Some(name_ref) = self.name_ref() {
675            return Some(NameOrNameRef::NameRef(name_ref));
676        }
677        match self.pat() {
678            Some(ast::Pat::IdentPat(pat)) => {
679                let name = pat.name()?;
680                Some(NameOrNameRef::Name(name))
681            }
682            Some(ast::Pat::BoxPat(pat)) => match pat.pat() {
683                Some(ast::Pat::IdentPat(pat)) => {
684                    let name = pat.name()?;
685                    Some(NameOrNameRef::Name(name))
686                }
687                _ => None,
688            },
689            _ => None,
690        }
691    }
692}
693
694impl ast::Variant {
695    pub fn parent_enum(&self) -> ast::Enum {
696        self.syntax()
697            .parent()
698            .and_then(|it| it.parent())
699            .and_then(ast::Enum::cast)
700            .expect("EnumVariants are always nested in Enums")
701    }
702    pub fn kind(&self) -> StructKind {
703        StructKind::from_node(self)
704    }
705}
706
707impl ast::Item {
708    pub fn generic_param_list(&self) -> Option<ast::GenericParamList> {
709        ast::AnyHasGenericParams::cast(self.syntax().clone())?.generic_param_list()
710    }
711}
712
713impl ast::Type {
714    pub fn generic_arg_list(&self) -> Option<ast::GenericArgList> {
715        if let ast::Type::PathType(path_type) = self {
716            path_type.path()?.segment()?.generic_arg_list()
717        } else {
718            None
719        }
720    }
721}
722
723#[derive(Debug, Clone, PartialEq, Eq)]
724pub enum FieldKind {
725    Name(ast::NameRef),
726    Index(SyntaxToken),
727}
728
729impl ast::FieldExpr {
730    pub fn index_token(&self) -> Option<SyntaxToken> {
731        self.syntax
732            .children_with_tokens()
733            // FIXME: Accepting floats here to reject them in validation later
734            .find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
735            .as_ref()
736            .and_then(SyntaxElement::as_token)
737            .cloned()
738    }
739
740    pub fn field_access(&self) -> Option<FieldKind> {
741        match self.name_ref() {
742            Some(nr) => Some(FieldKind::Name(nr)),
743            None => self.index_token().map(FieldKind::Index),
744        }
745    }
746}
747
748pub struct SlicePatComponents {
749    pub prefix: Vec<ast::Pat>,
750    pub slice: Option<ast::Pat>,
751    pub suffix: Vec<ast::Pat>,
752}
753
754impl ast::SlicePat {
755    pub fn components(&self) -> SlicePatComponents {
756        let mut args = self.pats().peekable();
757        let prefix = args
758            .peeking_take_while(|p| match p {
759                ast::Pat::RestPat(_) => false,
760                ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
761                ast::Pat::RefPat(rp) => match rp.pat() {
762                    Some(ast::Pat::RestPat(_)) => false,
763                    Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
764                    _ => true,
765                },
766                _ => true,
767            })
768            .collect();
769        let slice = args.next();
770        let suffix = args.collect();
771
772        SlicePatComponents { prefix, slice, suffix }
773    }
774}
775
776impl ast::IdentPat {
777    pub fn is_simple_ident(&self) -> bool {
778        self.at_token().is_none()
779            && self.mut_token().is_none()
780            && self.ref_token().is_none()
781            && self.pat().is_none()
782    }
783}
784
785#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
786pub enum SelfParamKind {
787    /// self
788    Owned,
789    /// &self
790    Ref,
791    /// &mut self
792    MutRef,
793}
794
795impl ast::SelfParam {
796    pub fn kind(&self) -> SelfParamKind {
797        if self.amp_token().is_some() {
798            if self.mut_token().is_some() { SelfParamKind::MutRef } else { SelfParamKind::Ref }
799        } else {
800            SelfParamKind::Owned
801        }
802    }
803}
804
805#[derive(Clone, Debug, PartialEq, Eq, Hash)]
806pub enum TypeBoundKind {
807    /// Trait
808    PathType(Option<ast::ForBinder>, ast::PathType),
809    /// use
810    Use(ast::UseBoundGenericArgs),
811    /// 'a
812    Lifetime(ast::Lifetime),
813}
814
815impl ast::TypeBound {
816    pub fn kind(&self) -> Option<TypeBoundKind> {
817        if let Some(path_type) = support::children(self.syntax()).next() {
818            Some(TypeBoundKind::PathType(self.for_binder(), path_type))
819        } else if let Some(for_binder) = support::children::<ast::ForType>(&self.syntax).next() {
820            let Some(ast::Type::PathType(path_type)) = for_binder.ty() else { return None };
821            Some(TypeBoundKind::PathType(for_binder.for_binder(), path_type))
822        } else if let Some(args) = self.use_bound_generic_args() {
823            Some(TypeBoundKind::Use(args))
824        } else if let Some(lifetime) = self.lifetime() {
825            Some(TypeBoundKind::Lifetime(lifetime))
826        } else {
827            unreachable!()
828        }
829    }
830}
831
832#[derive(Debug, Clone)]
833pub enum TypeOrConstParam {
834    Type(ast::TypeParam),
835    Const(ast::ConstParam),
836}
837
838impl From<TypeOrConstParam> for GenericParam {
839    fn from(value: TypeOrConstParam) -> Self {
840        match value {
841            TypeOrConstParam::Type(it) => GenericParam::TypeParam(it),
842            TypeOrConstParam::Const(it) => GenericParam::ConstParam(it),
843        }
844    }
845}
846
847impl TypeOrConstParam {
848    pub fn name(&self) -> Option<ast::Name> {
849        match self {
850            TypeOrConstParam::Type(x) => x.name(),
851            TypeOrConstParam::Const(x) => x.name(),
852        }
853    }
854}
855
856impl AstNode for TypeOrConstParam {
857    fn can_cast(kind: SyntaxKind) -> bool
858    where
859        Self: Sized,
860    {
861        matches!(kind, SyntaxKind::TYPE_PARAM | SyntaxKind::CONST_PARAM)
862    }
863
864    fn cast(syntax: SyntaxNode) -> Option<Self>
865    where
866        Self: Sized,
867    {
868        let res = match syntax.kind() {
869            SyntaxKind::TYPE_PARAM => TypeOrConstParam::Type(ast::TypeParam { syntax }),
870            SyntaxKind::CONST_PARAM => TypeOrConstParam::Const(ast::ConstParam { syntax }),
871            _ => return None,
872        };
873        Some(res)
874    }
875
876    fn syntax(&self) -> &SyntaxNode {
877        match self {
878            TypeOrConstParam::Type(it) => it.syntax(),
879            TypeOrConstParam::Const(it) => it.syntax(),
880        }
881    }
882}
883
884impl HasAttrs for TypeOrConstParam {}
885
886pub enum VisibilityKind {
887    In(ast::Path),
888    PubCrate,
889    PubSuper,
890    PubSelf,
891    Pub,
892}
893
894impl ast::Visibility {
895    pub fn kind(&self) -> VisibilityKind {
896        match self.path() {
897            Some(path) => {
898                if let Some(segment) =
899                    path.as_single_segment().filter(|it| it.coloncolon_token().is_none())
900                {
901                    if segment.crate_token().is_some() {
902                        return VisibilityKind::PubCrate;
903                    } else if segment.super_token().is_some() {
904                        return VisibilityKind::PubSuper;
905                    } else if segment.self_token().is_some() {
906                        return VisibilityKind::PubSelf;
907                    }
908                }
909                VisibilityKind::In(path)
910            }
911            None => VisibilityKind::Pub,
912        }
913    }
914}
915
916impl ast::LifetimeParam {
917    pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
918        self.type_bound_list()
919            .into_iter()
920            .flat_map(|it| it.bounds())
921            .filter_map(|it| it.lifetime()?.lifetime_ident_token())
922    }
923}
924
925impl ast::Module {
926    /// Returns the parent ast::Module, this is different than the semantic parent in that this only
927    /// considers parent declarations in the AST
928    pub fn parent(&self) -> Option<ast::Module> {
929        self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
930    }
931}
932
933impl RangeItem for ast::RangePat {
934    type Bound = ast::Pat;
935
936    fn start(&self) -> Option<ast::Pat> {
937        self.syntax()
938            .children_with_tokens()
939            .take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
940            .filter_map(|it| it.into_node())
941            .find_map(ast::Pat::cast)
942    }
943
944    fn end(&self) -> Option<ast::Pat> {
945        self.syntax()
946            .children_with_tokens()
947            .skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
948            .filter_map(|it| it.into_node())
949            .find_map(ast::Pat::cast)
950    }
951
952    fn op_token(&self) -> Option<SyntaxToken> {
953        self.syntax().children_with_tokens().find_map(|it| {
954            let token = it.into_token()?;
955
956            match token.kind() {
957                T![..] => Some(token),
958                T![..=] => Some(token),
959                _ => None,
960            }
961        })
962    }
963
964    fn op_kind(&self) -> Option<RangeOp> {
965        self.syntax().children_with_tokens().find_map(|it| {
966            let token = it.into_token()?;
967
968            match token.kind() {
969                T![..] => Some(RangeOp::Exclusive),
970                T![..=] => Some(RangeOp::Inclusive),
971                _ => None,
972            }
973        })
974    }
975}
976
977impl ast::TokenTree {
978    pub fn token_trees_and_tokens(
979        &self,
980    ) -> impl Iterator<Item = NodeOrToken<ast::TokenTree, SyntaxToken>> {
981        self.syntax().children_with_tokens().filter_map(|not| match not {
982            NodeOrToken::Node(node) => ast::TokenTree::cast(node).map(NodeOrToken::Node),
983            NodeOrToken::Token(t) => Some(NodeOrToken::Token(t)),
984        })
985    }
986
987    pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
988        self.syntax()
989            .first_child_or_token()?
990            .into_token()
991            .filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
992    }
993
994    pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
995        self.syntax()
996            .last_child_or_token()?
997            .into_token()
998            .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
999    }
1000
1001    pub fn parent_meta(&self) -> Option<ast::Meta> {
1002        self.syntax().parent().and_then(ast::Meta::cast)
1003    }
1004}
1005
1006impl ast::Meta {
1007    pub fn parent_attr(&self) -> Option<ast::Attr> {
1008        self.syntax().parent().and_then(ast::Attr::cast)
1009    }
1010}
1011
1012impl ast::GenericArgList {
1013    pub fn lifetime_args(&self) -> impl Iterator<Item = ast::LifetimeArg> {
1014        self.generic_args().filter_map(|arg| match arg {
1015            ast::GenericArg::LifetimeArg(it) => Some(it),
1016            _ => None,
1017        })
1018    }
1019}
1020
1021impl ast::GenericParamList {
1022    pub fn lifetime_params(&self) -> impl Iterator<Item = ast::LifetimeParam> {
1023        self.generic_params().filter_map(|param| match param {
1024            ast::GenericParam::LifetimeParam(it) => Some(it),
1025            ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
1026        })
1027    }
1028    pub fn type_or_const_params(&self) -> impl Iterator<Item = ast::TypeOrConstParam> + use<> {
1029        self.generic_params().filter_map(|param| match param {
1030            ast::GenericParam::TypeParam(it) => Some(ast::TypeOrConstParam::Type(it)),
1031            ast::GenericParam::LifetimeParam(_) => None,
1032            ast::GenericParam::ConstParam(it) => Some(ast::TypeOrConstParam::Const(it)),
1033        })
1034    }
1035}
1036
1037impl ast::ForExpr {
1038    pub fn iterable(&self) -> Option<ast::Expr> {
1039        // If the iterable is a BlockExpr, check if the body is missing.
1040        // If it is assume the iterable is the expression that is missing instead.
1041        let mut exprs = support::children(self.syntax());
1042        let first = exprs.next();
1043        match first {
1044            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
1045            first => first,
1046        }
1047    }
1048}
1049
1050impl ast::HasLoopBody for ast::ForExpr {
1051    fn loop_body(&self) -> Option<ast::BlockExpr> {
1052        let mut exprs = support::children(self.syntax());
1053        let first = exprs.next();
1054        let second = exprs.next();
1055        second.or(first)
1056    }
1057}
1058
1059impl ast::WhileExpr {
1060    pub fn condition(&self) -> Option<ast::Expr> {
1061        // If the condition is a BlockExpr, check if the body is missing.
1062        // If it is assume the condition is the expression that is missing instead.
1063        let mut exprs = support::children(self.syntax());
1064        let first = exprs.next();
1065        match first {
1066            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
1067            first => first,
1068        }
1069    }
1070}
1071
1072impl ast::HasLoopBody for ast::WhileExpr {
1073    fn loop_body(&self) -> Option<ast::BlockExpr> {
1074        let mut exprs = support::children(self.syntax());
1075        let first = exprs.next();
1076        let second = exprs.next();
1077        second.or(first)
1078    }
1079}
1080
1081impl ast::HasAttrs for ast::AnyHasDocComments {}
1082
1083impl From<ast::Adt> for ast::Item {
1084    fn from(it: ast::Adt) -> Self {
1085        match it {
1086            ast::Adt::Enum(it) => ast::Item::Enum(it),
1087            ast::Adt::Struct(it) => ast::Item::Struct(it),
1088            ast::Adt::Union(it) => ast::Item::Union(it),
1089        }
1090    }
1091}
1092
1093impl ast::MatchGuard {
1094    pub fn condition(&self) -> Option<ast::Expr> {
1095        support::child(&self.syntax)
1096    }
1097}
1098
1099impl From<ast::Item> for ast::AnyHasAttrs {
1100    fn from(node: ast::Item) -> Self {
1101        Self::new(node)
1102    }
1103}
1104
1105impl From<ast::AssocItem> for ast::AnyHasAttrs {
1106    fn from(node: ast::AssocItem) -> Self {
1107        Self::new(node)
1108    }
1109}
1110
1111impl ast::OrPat {
1112    pub fn leading_pipe(&self) -> Option<SyntaxToken> {
1113        self.syntax
1114            .children_with_tokens()
1115            .find(|it| !it.kind().is_trivia())
1116            .and_then(NodeOrToken::into_token)
1117            .filter(|it| it.kind() == T![|])
1118    }
1119}
1120
1121/// An iterator over the elements in an [`ast::TokenTree`].
1122///
1123/// Does not yield trivia or the delimiters.
1124#[derive(Clone)]
1125pub struct TokenTreeChildren {
1126    iter: SyntaxElementChildren,
1127}
1128
1129impl TokenTreeChildren {
1130    #[inline]
1131    pub fn new(tt: &ast::TokenTree) -> Self {
1132        let mut iter = tt.syntax.children_with_tokens();
1133        iter.next(); // Bump the opening delimiter.
1134        Self { iter }
1135    }
1136}
1137
1138impl Iterator for TokenTreeChildren {
1139    type Item = NodeOrToken<ast::TokenTree, SyntaxToken>;
1140
1141    #[inline]
1142    fn next(&mut self) -> Option<Self::Item> {
1143        self.iter.find_map(|item| match item {
1144            NodeOrToken::Node(node) => ast::TokenTree::cast(node).map(NodeOrToken::Node),
1145            NodeOrToken::Token(token) => {
1146                let kind = token.kind();
1147                (!matches!(
1148                    kind,
1149                    SyntaxKind::WHITESPACE | SyntaxKind::COMMENT | T![')'] | T![']'] | T!['}']
1150                ))
1151                .then_some(NodeOrToken::Token(token))
1152            }
1153        })
1154    }
1155}