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.
4 use std::{borrow::Cow, fmt, iter::successors};
6 use itertools::Itertools;
7 use parser::SyntaxKind;
8 use rowan::{GreenNodeData, GreenTokenData, WalkEvent};
11 ast::{self, support, AstChildren, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode},
12 NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
16 pub fn text(&self) -> TokenText<'_> {
17 text_of_first_token(self.syntax())
22 pub fn text(&self) -> TokenText<'_> {
23 text_of_first_token(self.syntax())
28 pub fn text(&self) -> TokenText<'_> {
29 text_of_first_token(self.syntax())
32 pub fn as_tuple_field(&self) -> Option<usize> {
33 self.text().parse().ok()
37 fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
38 fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
39 green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
43 Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()),
44 Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()),
49 pub fn items(&self) -> AstChildren<ast::Item> {
50 support::children(self.syntax())
53 pub fn is_empty(&self) -> bool {
54 self.statements().next().is_none() && self.tail_expr().is_none()
59 /// Preorder walk all the pattern's sub patterns.
60 pub fn walk(&self, cb: &mut dyn FnMut(ast::Pat)) {
61 let mut preorder = self.syntax().preorder();
62 while let Some(event) = preorder.next() {
63 let node = match event {
64 WalkEvent::Enter(node) => node,
65 WalkEvent::Leave(_) => continue,
67 let kind = node.kind();
68 match ast::Pat::cast(node) {
69 Some(pat @ ast::Pat::ConstBlockPat(_)) => {
70 preorder.skip_subtree();
77 None if ast::GenericArg::can_cast(kind) => {
78 preorder.skip_subtree();
87 /// Preorder walk all the type's sub types.
88 pub fn walk(&self, cb: &mut dyn FnMut(ast::Type)) {
89 let mut preorder = self.syntax().preorder();
90 while let Some(event) = preorder.next() {
91 let node = match event {
92 WalkEvent::Enter(node) => node,
93 WalkEvent::Leave(_) => continue,
95 let kind = node.kind();
96 match ast::Type::cast(node) {
97 Some(ty @ ast::Type::MacroType(_)) => {
98 preorder.skip_subtree();
105 None if ast::ConstArg::can_cast(kind) => {
106 preorder.skip_subtree();
114 #[derive(Debug, PartialEq, Eq, Clone)]
116 MacroRules(ast::MacroRules),
117 MacroDef(ast::MacroDef),
120 impl From<ast::MacroRules> for Macro {
121 fn from(it: ast::MacroRules) -> Self {
122 Macro::MacroRules(it)
126 impl From<ast::MacroDef> for Macro {
127 fn from(it: ast::MacroDef) -> Self {
132 impl AstNode for Macro {
133 fn can_cast(kind: SyntaxKind) -> bool {
134 matches!(kind, SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF)
136 fn cast(syntax: SyntaxNode) -> Option<Self> {
137 let res = match syntax.kind() {
138 SyntaxKind::MACRO_RULES => Macro::MacroRules(ast::MacroRules { syntax }),
139 SyntaxKind::MACRO_DEF => Macro::MacroDef(ast::MacroDef { syntax }),
144 fn syntax(&self) -> &SyntaxNode {
146 Macro::MacroRules(it) => it.syntax(),
147 Macro::MacroDef(it) => it.syntax(),
152 impl NameOwner for Macro {
153 fn name(&self) -> Option<ast::Name> {
155 Macro::MacroRules(mac) => mac.name(),
156 Macro::MacroDef(mac) => mac.name(),
161 impl AttrsOwner for Macro {}
163 /// Basically an owned `dyn AttrsOwner` without extra boxing.
164 pub struct AttrsOwnerNode {
168 impl AttrsOwnerNode {
169 pub fn new<N: AttrsOwner>(node: N) -> Self {
170 AttrsOwnerNode { node: node.syntax().clone() }
174 impl AttrsOwner for AttrsOwnerNode {}
175 impl AstNode for AttrsOwnerNode {
176 fn can_cast(_: SyntaxKind) -> bool
182 fn cast(_: SyntaxNode) -> Option<Self>
188 fn syntax(&self) -> &SyntaxNode {
193 #[derive(Debug, Clone, PartialEq, Eq)]
200 /// Returns `true` if the attr_kind is [`Inner`].
201 pub fn is_inner(&self) -> bool {
202 matches!(self, Self::Inner)
205 /// Returns `true` if the attr_kind is [`Outer`].
206 pub fn is_outer(&self) -> bool {
207 matches!(self, Self::Outer)
212 pub fn as_simple_atom(&self) -> Option<SmolStr> {
213 let meta = self.meta()?;
214 if meta.eq_token().is_some() || meta.token_tree().is_some() {
220 pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
221 let tt = self.meta()?.token_tree()?;
222 Some((self.simple_name()?, tt))
225 pub fn simple_name(&self) -> Option<SmolStr> {
226 let path = self.meta()?.path()?;
227 match (path.segment(), path.qualifier()) {
228 (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()),
233 pub fn kind(&self) -> AttrKind {
234 let first_token = self.syntax().first_token();
235 let first_token_kind = first_token.as_ref().map(SyntaxToken::kind);
236 let second_token_kind =
237 first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind);
239 match (first_token_kind, second_token_kind) {
240 (Some(T![#]), Some(T![!])) => AttrKind::Inner,
241 _ => AttrKind::Outer,
245 pub fn path(&self) -> Option<ast::Path> {
249 pub fn expr(&self) -> Option<ast::Expr> {
253 pub fn token_tree(&self) -> Option<ast::TokenTree> {
254 self.meta()?.token_tree()
258 #[derive(Debug, Clone, PartialEq, Eq)]
259 pub enum PathSegmentKind {
261 Type { type_ref: Option<ast::Type>, trait_ref: Option<ast::PathType> },
267 impl ast::PathSegment {
268 pub fn parent_path(&self) -> ast::Path {
271 .and_then(ast::Path::cast)
272 .expect("segments are always nested in paths")
275 pub fn crate_token(&self) -> Option<SyntaxToken> {
276 self.name_ref().and_then(|it| it.crate_token())
279 pub fn self_token(&self) -> Option<SyntaxToken> {
280 self.name_ref().and_then(|it| it.self_token())
283 pub fn super_token(&self) -> Option<SyntaxToken> {
284 self.name_ref().and_then(|it| it.super_token())
287 pub fn kind(&self) -> Option<PathSegmentKind> {
288 let res = if let Some(name_ref) = self.name_ref() {
289 match name_ref.syntax().first_token().map(|it| it.kind()) {
290 Some(T![self]) => PathSegmentKind::SelfKw,
291 Some(T![super]) => PathSegmentKind::SuperKw,
292 Some(T![crate]) => PathSegmentKind::CrateKw,
293 _ => PathSegmentKind::Name(name_ref),
296 match self.syntax().first_child_or_token()?.kind() {
298 // <T> or <T as Trait>
299 // T is any TypeRef, Trait has to be a PathType
301 self.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
302 let type_ref = type_refs.next().and_then(ast::Type::cast);
303 let trait_ref = type_refs.next().and_then(ast::PathType::cast);
304 PathSegmentKind::Type { type_ref, trait_ref }
314 pub fn parent_path(&self) -> Option<ast::Path> {
315 self.syntax().parent().and_then(ast::Path::cast)
318 pub fn as_single_segment(&self) -> Option<ast::PathSegment> {
319 match self.qualifier() {
321 None => self.segment(),
325 pub fn as_single_name_ref(&self) -> Option<ast::NameRef> {
326 match self.qualifier() {
328 None => self.segment()?.name_ref(),
332 pub fn first_qualifier_or_self(&self) -> ast::Path {
333 successors(Some(self.clone()), ast::Path::qualifier).last().unwrap()
336 pub fn first_segment(&self) -> Option<ast::PathSegment> {
337 self.first_qualifier_or_self().segment()
340 pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
341 successors(self.first_segment(), |p| {
342 p.parent_path().parent_path().and_then(|p| p.segment())
346 pub fn qualifiers(&self) -> impl Iterator<Item = ast::Path> + Clone {
347 successors(self.qualifier(), |p| p.qualifier())
350 pub fn top_path(&self) -> ast::Path {
351 let mut this = self.clone();
352 while let Some(path) = this.parent_path() {
360 pub fn is_simple_glob(&self) -> bool {
362 .map(|use_tree| use_tree.use_tree_list().is_none() && use_tree.star_token().is_some())
368 pub fn is_simple_path(&self) -> bool {
369 self.use_tree_list().is_none() && self.star_token().is_none()
373 impl ast::UseTreeList {
374 pub fn parent_use_tree(&self) -> ast::UseTree {
377 .and_then(ast::UseTree::cast)
378 .expect("UseTreeLists are always nested in UseTrees")
381 pub fn has_inner_comment(&self) -> bool {
383 .children_with_tokens()
384 .filter_map(|it| it.into_token())
385 .find_map(ast::Comment::cast)
391 pub fn self_ty(&self) -> Option<ast::Type> {
392 match self.target() {
393 (Some(t), None) | (_, Some(t)) => Some(t),
398 pub fn trait_(&self) -> Option<ast::Type> {
399 match self.target() {
400 (Some(t), Some(_)) => Some(t),
405 fn target(&self) -> (Option<ast::Type>, Option<ast::Type>) {
406 let mut types = support::children(self.syntax());
407 let first = types.next();
408 let second = types.next();
412 pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> {
413 let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?;
414 if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() {
422 #[derive(Debug, Clone, PartialEq, Eq)]
423 pub enum StructKind {
424 Record(ast::RecordFieldList),
425 Tuple(ast::TupleFieldList),
430 fn from_node<N: AstNode>(node: &N) -> StructKind {
431 if let Some(nfdl) = support::child::<ast::RecordFieldList>(node.syntax()) {
432 StructKind::Record(nfdl)
433 } else if let Some(pfl) = support::child::<ast::TupleFieldList>(node.syntax()) {
434 StructKind::Tuple(pfl)
442 pub fn kind(&self) -> StructKind {
443 StructKind::from_node(self)
447 impl ast::RecordExprField {
448 pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
449 let candidate = Self::for_name_ref(field_name)?;
450 if candidate.field_name().as_ref() == Some(field_name) {
457 pub fn for_name_ref(name_ref: &ast::NameRef) -> Option<ast::RecordExprField> {
458 let syn = name_ref.syntax();
460 .and_then(ast::RecordExprField::cast)
461 .or_else(|| syn.ancestors().nth(4).and_then(ast::RecordExprField::cast))
464 /// Deals with field init shorthand
465 pub fn field_name(&self) -> Option<ast::NameRef> {
466 if let Some(name_ref) = self.name_ref() {
467 return Some(name_ref);
469 self.expr()?.name_ref()
473 #[derive(Debug, Clone)]
475 NameRef(ast::NameRef),
477 Lifetime(ast::Lifetime),
481 pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
483 NameLike::NameRef(name_ref) => Some(name_ref),
489 impl ast::AstNode for NameLike {
490 fn can_cast(kind: SyntaxKind) -> bool {
491 matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME)
493 fn cast(syntax: SyntaxNode) -> Option<Self> {
494 let res = match syntax.kind() {
495 SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }),
496 SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }),
497 SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }),
502 fn syntax(&self) -> &SyntaxNode {
504 NameLike::NameRef(it) => it.syntax(),
505 NameLike::Name(it) => it.syntax(),
506 NameLike::Lifetime(it) => it.syntax(),
513 ast::{Lifetime, Name, NameRef},
516 stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
519 #[derive(Debug, Clone, PartialEq)]
520 pub enum NameOrNameRef {
522 NameRef(ast::NameRef),
525 impl fmt::Display for NameOrNameRef {
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
528 NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
529 NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
535 pub fn text(&self) -> TokenText<'_> {
537 NameOrNameRef::Name(name) => name.text(),
538 NameOrNameRef::NameRef(name_ref) => name_ref.text(),
543 impl ast::RecordPatField {
544 pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
545 let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
546 match candidate.field_name()? {
547 NameOrNameRef::NameRef(name_ref) if name_ref == *field_name => Some(candidate),
552 pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
554 field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
555 match candidate.field_name()? {
556 NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
561 /// Deals with field init shorthand
562 pub fn field_name(&self) -> Option<NameOrNameRef> {
563 if let Some(name_ref) = self.name_ref() {
564 return Some(NameOrNameRef::NameRef(name_ref));
567 Some(ast::Pat::IdentPat(pat)) => {
568 let name = pat.name()?;
569 Some(NameOrNameRef::Name(name))
571 Some(ast::Pat::BoxPat(pat)) => match pat.pat() {
572 Some(ast::Pat::IdentPat(pat)) => {
573 let name = pat.name()?;
574 Some(NameOrNameRef::Name(name))
584 pub fn parent_enum(&self) -> ast::Enum {
587 .and_then(|it| it.parent())
588 .and_then(ast::Enum::cast)
589 .expect("EnumVariants are always nested in Enums")
591 pub fn kind(&self) -> StructKind {
592 StructKind::from_node(self)
596 #[derive(Debug, Clone, PartialEq, Eq)]
602 impl ast::FieldExpr {
603 pub fn index_token(&self) -> Option<SyntaxToken> {
605 .children_with_tokens()
606 // FIXME: Accepting floats here to reject them in validation later
607 .find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
609 .and_then(SyntaxElement::as_token)
613 pub fn field_access(&self) -> Option<FieldKind> {
614 if let Some(nr) = self.name_ref() {
615 Some(FieldKind::Name(nr))
617 self.index_token().map(FieldKind::Index)
622 pub struct SlicePatComponents {
623 pub prefix: Vec<ast::Pat>,
624 pub slice: Option<ast::Pat>,
625 pub suffix: Vec<ast::Pat>,
629 pub fn components(&self) -> SlicePatComponents {
630 let mut args = self.pats().peekable();
632 .peeking_take_while(|p| match p {
633 ast::Pat::RestPat(_) => false,
634 ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
635 ast::Pat::RefPat(rp) => match rp.pat() {
636 Some(ast::Pat::RestPat(_)) => false,
637 Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
643 let slice = args.next();
644 let suffix = args.collect();
646 SlicePatComponents { prefix, slice, suffix }
651 pub fn is_simple_ident(&self) -> bool {
652 self.at_token().is_none()
653 && self.mut_token().is_none()
654 && self.ref_token().is_none()
655 && self.pat().is_none()
659 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
660 pub enum SelfParamKind {
669 impl ast::SelfParam {
670 pub fn kind(&self) -> SelfParamKind {
671 if self.amp_token().is_some() {
672 if self.mut_token().is_some() {
673 SelfParamKind::MutRef
683 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
684 pub enum TypeBoundKind {
686 PathType(ast::PathType),
688 ForType(ast::ForType),
690 Lifetime(ast::Lifetime),
693 impl ast::TypeBound {
694 pub fn kind(&self) -> TypeBoundKind {
695 if let Some(path_type) = support::children(self.syntax()).next() {
696 TypeBoundKind::PathType(path_type)
697 } else if let Some(for_type) = support::children(self.syntax()).next() {
698 TypeBoundKind::ForType(for_type)
699 } else if let Some(lifetime) = self.lifetime() {
700 TypeBoundKind::Lifetime(lifetime)
707 pub enum VisibilityKind {
715 impl ast::Visibility {
716 pub fn kind(&self) -> VisibilityKind {
719 if let Some(segment) =
720 path.as_single_segment().filter(|it| it.coloncolon_token().is_none())
722 if segment.crate_token().is_some() {
723 return VisibilityKind::PubCrate;
724 } else if segment.super_token().is_some() {
725 return VisibilityKind::PubSuper;
726 } else if segment.self_token().is_some() {
727 return VisibilityKind::PubSelf;
730 VisibilityKind::In(path)
732 None => VisibilityKind::Pub,
736 pub fn is_eq_to(&self, other: &Self) -> bool {
737 match (self.kind(), other.kind()) {
738 (VisibilityKind::In(this), VisibilityKind::In(other)) => {
739 stdx::iter_eq_by(this.segments(), other.segments(), |lhs, rhs| {
740 lhs.kind().zip(rhs.kind()).map_or(false, |it| match it {
741 (PathSegmentKind::CrateKw, PathSegmentKind::CrateKw)
742 | (PathSegmentKind::SelfKw, PathSegmentKind::SelfKw)
743 | (PathSegmentKind::SuperKw, PathSegmentKind::SuperKw) => true,
744 (PathSegmentKind::Name(lhs), PathSegmentKind::Name(rhs)) => {
745 lhs.text() == rhs.text()
751 (VisibilityKind::PubSelf, VisibilityKind::PubSelf)
752 | (VisibilityKind::PubSuper, VisibilityKind::PubSuper)
753 | (VisibilityKind::PubCrate, VisibilityKind::PubCrate)
754 | (VisibilityKind::Pub, VisibilityKind::Pub) => true,
760 impl ast::LifetimeParam {
761 pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
763 .children_with_tokens()
764 .filter_map(|it| it.into_token())
765 .skip_while(|x| x.kind() != T![:])
766 .filter(|it| it.kind() == T![lifetime_ident])
771 /// Returns the parent ast::Module, this is different than the semantic parent in that this only
772 /// considers parent declarations in the AST
773 pub fn parent(&self) -> Option<ast::Module> {
774 self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
779 pub fn start(&self) -> Option<ast::Pat> {
781 .children_with_tokens()
782 .take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
783 .filter_map(|it| it.into_node())
784 .find_map(ast::Pat::cast)
787 pub fn end(&self) -> Option<ast::Pat> {
789 .children_with_tokens()
790 .skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
791 .filter_map(|it| it.into_node())
792 .find_map(ast::Pat::cast)
796 impl ast::TokenTree {
797 pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
799 .first_child_or_token()?
801 .filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
804 pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
806 .last_child_or_token()?
808 .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
812 impl ast::GenericParamList {
813 pub fn lifetime_params(&self) -> impl Iterator<Item = ast::LifetimeParam> {
814 self.generic_params().filter_map(|param| match param {
815 ast::GenericParam::LifetimeParam(it) => Some(it),
816 ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
819 pub fn type_params(&self) -> impl Iterator<Item = ast::TypeParam> {
820 self.generic_params().filter_map(|param| match param {
821 ast::GenericParam::TypeParam(it) => Some(it),
822 ast::GenericParam::LifetimeParam(_) | ast::GenericParam::ConstParam(_) => None,
825 pub fn const_params(&self) -> impl Iterator<Item = ast::ConstParam> {
826 self.generic_params().filter_map(|param| match param {
827 ast::GenericParam::ConstParam(it) => Some(it),
828 ast::GenericParam::TypeParam(_) | ast::GenericParam::LifetimeParam(_) => None,
833 impl ast::DocCommentsOwner for ast::SourceFile {}
834 impl ast::DocCommentsOwner for ast::Fn {}
835 impl ast::DocCommentsOwner for ast::Struct {}
836 impl ast::DocCommentsOwner for ast::Union {}
837 impl ast::DocCommentsOwner for ast::RecordField {}
838 impl ast::DocCommentsOwner for ast::TupleField {}
839 impl ast::DocCommentsOwner for ast::Enum {}
840 impl ast::DocCommentsOwner for ast::Variant {}
841 impl ast::DocCommentsOwner for ast::Trait {}
842 impl ast::DocCommentsOwner for ast::Module {}
843 impl ast::DocCommentsOwner for ast::Static {}
844 impl ast::DocCommentsOwner for ast::Const {}
845 impl ast::DocCommentsOwner for ast::TypeAlias {}
846 impl ast::DocCommentsOwner for ast::Impl {}
847 impl ast::DocCommentsOwner for ast::MacroRules {}
848 impl ast::DocCommentsOwner for ast::MacroDef {}
849 impl ast::DocCommentsOwner for ast::Macro {}
850 impl ast::DocCommentsOwner for ast::Use {}