Skip to main content

ra_ap_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};
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    // FIXME: remove all these methods, they belong to ast::StmtList
100    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    /// Block expressions accept outer and inner attributes, but only when they are the outer
107    /// expression of an expression statement or the final expression of another block expression.
108    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    /// Returns `true` if the attr_kind is [`Inner`](Self::Inner).
195    pub fn is_inner(&self) -> bool {
196        matches!(self, Self::Inner)
197    }
198
199    /// Returns `true` if the attr_kind is [`Outer`](Self::Outer).
200    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    /// Includes `cfg_attr()` inner metas (without considering the predicate).
245    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    /// FIXME: Calling this is almost always incorrect, as `cfg_attr` can contains multiple `Meta`s.
255    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    /// Includes `cfg_attr()` inner metas (without considering the predicate).
289    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            // FIXME: Move this over to `ast::TypeAnchor`
343            // <T> or <T as Trait>
344            // T is any TypeRef, Trait has to be a PathType
345            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    /// Remove the unnecessary braces in current `UseTreeList`
457    pub fn remove_unnecessary_braces(mut self, editor: &SyntaxEditor) {
458        // Returns true iff there is a single subtree and it is not the self keyword. The braces in
459        // `use x::{self};` are necessary and so we should not remove them.
460        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                // We have a single subtree, check whether it is self.
464
465                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                // Not a single subtree
473                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        // take `use crate::{{{{A}}}}` for example
490        // the below remove the innermost {}, got `use crate::{{{A}}}`
491        remove_brace_in_use_tree_list(&self);
492
493        // the below remove other unnecessary {}, got `use crate::A`
494        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
532// [#15778](https://github.com/rust-lang/rust-analyzer/issues/15778)
533impl 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    /// Deals with field init shorthand
586    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    /// Deals with field init shorthand
725    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            // FIXME: Accepting floats here to reject them in validation later
790            .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    /// self
844    Owned,
845    /// &self
846    Ref,
847    /// &mut self
848    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    /// Trait
864    PathType(Option<ast::ForBinder>, ast::PathType),
865    /// use
866    Use(ast::UseBoundGenericArgs),
867    /// 'a
868    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    /// Returns the parent ast::Module, this is different than the semantic parent in that this only
992    /// considers parent declarations in the AST
993    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    /// Comma separated args, argument may be empty
1098    pub fn args_maybe_empty(&self) -> impl Iterator<Item = Option<ast::Expr>> {
1099        // (Expr? ','?)*
1100        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        // If the iterable is a BlockExpr, check if the body is missing.
1114        // If it is assume the iterable is the expression that is missing instead.
1115        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        // If the condition is a BlockExpr, check if the body is missing.
1136        // If it is assume the condition is the expression that is missing instead.
1137        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    /// This is not a [`ast::Name`], because the name may be a keyword.
1197    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/// An iterator over the elements in an [`ast::TokenTree`].
1234///
1235/// Does not yield trivia or the delimiters.
1236#[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(); // Bump the opening delimiter.
1246        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}