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 //! These methods should only do simple, shallow tasks related to the syntax of the node itself.
6 use std::{borrow::Cow, fmt, iter::successors};
8 use itertools::Itertools;
9 use parser::SyntaxKind;
10 use rowan::{GreenNodeData, GreenTokenData};
13 ast::{self, support, AstNode, AstToken, HasAttrs, HasGenericParams, HasName, SyntaxNode},
14 NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
18 pub fn text(&self) -> TokenText<'_> {
19 text_of_first_token(self.syntax())
24 pub fn text(&self) -> TokenText<'_> {
25 text_of_first_token(self.syntax())
30 pub fn text(&self) -> TokenText<'_> {
31 text_of_first_token(self.syntax())
34 pub fn as_tuple_field(&self) -> Option<usize> {
35 self.text().parse().ok()
38 pub fn token_kind(&self) -> SyntaxKind {
39 self.syntax().first_token().map_or(SyntaxKind::ERROR, |it| it.kind())
43 fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
44 fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
45 green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
49 Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()),
50 Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()),
54 impl ast::HasModuleItem for ast::StmtList {}
57 // FIXME: remove all these methods, they belong to ast::StmtList
58 pub fn statements(&self) -> impl Iterator<Item = ast::Stmt> {
59 self.stmt_list().into_iter().flat_map(|it| it.statements())
61 pub fn tail_expr(&self) -> Option<ast::Expr> {
62 self.stmt_list()?.tail_expr()
66 #[derive(Debug, PartialEq, Eq, Clone)]
68 MacroRules(ast::MacroRules),
69 MacroDef(ast::MacroDef),
72 impl From<ast::MacroRules> for Macro {
73 fn from(it: ast::MacroRules) -> Self {
78 impl From<ast::MacroDef> for Macro {
79 fn from(it: ast::MacroDef) -> Self {
84 impl AstNode for Macro {
85 fn can_cast(kind: SyntaxKind) -> bool {
86 matches!(kind, SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF)
88 fn cast(syntax: SyntaxNode) -> Option<Self> {
89 let res = match syntax.kind() {
90 SyntaxKind::MACRO_RULES => Macro::MacroRules(ast::MacroRules { syntax }),
91 SyntaxKind::MACRO_DEF => Macro::MacroDef(ast::MacroDef { syntax }),
96 fn syntax(&self) -> &SyntaxNode {
98 Macro::MacroRules(it) => it.syntax(),
99 Macro::MacroDef(it) => it.syntax(),
104 impl HasName for Macro {
105 fn name(&self) -> Option<ast::Name> {
107 Macro::MacroRules(mac) => mac.name(),
108 Macro::MacroDef(mac) => mac.name(),
113 impl HasAttrs for Macro {}
115 impl From<ast::AssocItem> for ast::Item {
116 fn from(assoc: ast::AssocItem) -> Self {
118 ast::AssocItem::Const(it) => ast::Item::Const(it),
119 ast::AssocItem::Fn(it) => ast::Item::Fn(it),
120 ast::AssocItem::MacroCall(it) => ast::Item::MacroCall(it),
121 ast::AssocItem::TypeAlias(it) => ast::Item::TypeAlias(it),
126 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
133 /// Returns `true` if the attr_kind is [`Inner`](Self::Inner).
134 pub fn is_inner(&self) -> bool {
135 matches!(self, Self::Inner)
138 /// Returns `true` if the attr_kind is [`Outer`](Self::Outer).
139 pub fn is_outer(&self) -> bool {
140 matches!(self, Self::Outer)
145 pub fn as_simple_atom(&self) -> Option<SmolStr> {
146 let meta = self.meta()?;
147 if meta.eq_token().is_some() || meta.token_tree().is_some() {
153 pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
154 let tt = self.meta()?.token_tree()?;
155 Some((self.simple_name()?, tt))
158 pub fn simple_name(&self) -> Option<SmolStr> {
159 let path = self.meta()?.path()?;
160 match (path.segment(), path.qualifier()) {
161 (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()),
166 pub fn kind(&self) -> AttrKind {
167 match self.excl_token() {
168 Some(_) => AttrKind::Inner,
169 None => AttrKind::Outer,
173 pub fn path(&self) -> Option<ast::Path> {
177 pub fn expr(&self) -> Option<ast::Expr> {
181 pub fn token_tree(&self) -> Option<ast::TokenTree> {
182 self.meta()?.token_tree()
186 #[derive(Debug, Clone, PartialEq, Eq)]
187 pub enum PathSegmentKind {
189 Type { type_ref: Option<ast::Type>, trait_ref: Option<ast::PathType> },
196 impl ast::PathSegment {
197 pub fn parent_path(&self) -> ast::Path {
200 .and_then(ast::Path::cast)
201 .expect("segments are always nested in paths")
204 pub fn crate_token(&self) -> Option<SyntaxToken> {
205 self.name_ref().and_then(|it| it.crate_token())
208 pub fn self_token(&self) -> Option<SyntaxToken> {
209 self.name_ref().and_then(|it| it.self_token())
212 pub fn self_type_token(&self) -> Option<SyntaxToken> {
213 self.name_ref().and_then(|it| it.Self_token())
216 pub fn super_token(&self) -> Option<SyntaxToken> {
217 self.name_ref().and_then(|it| it.super_token())
220 pub fn kind(&self) -> Option<PathSegmentKind> {
221 let res = if let Some(name_ref) = self.name_ref() {
222 match name_ref.token_kind() {
223 T![Self] => PathSegmentKind::SelfTypeKw,
224 T![self] => PathSegmentKind::SelfKw,
225 T![super] => PathSegmentKind::SuperKw,
226 T![crate] => PathSegmentKind::CrateKw,
227 _ => PathSegmentKind::Name(name_ref),
230 match self.syntax().first_child_or_token()?.kind() {
232 // <T> or <T as Trait>
233 // T is any TypeRef, Trait has to be a PathType
235 self.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
236 let type_ref = type_refs.next().and_then(ast::Type::cast);
237 let trait_ref = type_refs.next().and_then(ast::PathType::cast);
238 PathSegmentKind::Type { type_ref, trait_ref }
248 pub fn parent_path(&self) -> Option<ast::Path> {
249 self.syntax().parent().and_then(ast::Path::cast)
252 pub fn as_single_segment(&self) -> Option<ast::PathSegment> {
253 match self.qualifier() {
255 None => self.segment(),
259 pub fn as_single_name_ref(&self) -> Option<ast::NameRef> {
260 match self.qualifier() {
262 None => self.segment()?.name_ref(),
266 pub fn first_qualifier_or_self(&self) -> ast::Path {
267 successors(Some(self.clone()), ast::Path::qualifier).last().unwrap()
270 pub fn first_segment(&self) -> Option<ast::PathSegment> {
271 self.first_qualifier_or_self().segment()
274 pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
275 successors(self.first_segment(), |p| {
276 p.parent_path().parent_path().and_then(|p| p.segment())
280 pub fn qualifiers(&self) -> impl Iterator<Item = ast::Path> + Clone {
281 successors(self.qualifier(), |p| p.qualifier())
284 pub fn top_path(&self) -> ast::Path {
285 let mut this = self.clone();
286 while let Some(path) = this.parent_path() {
294 pub fn is_simple_glob(&self) -> bool {
295 self.use_tree().map_or(false, |use_tree| {
296 use_tree.use_tree_list().is_none() && use_tree.star_token().is_some()
302 pub fn is_simple_path(&self) -> bool {
303 self.use_tree_list().is_none() && self.star_token().is_none()
307 impl ast::UseTreeList {
308 pub fn parent_use_tree(&self) -> ast::UseTree {
311 .and_then(ast::UseTree::cast)
312 .expect("UseTreeLists are always nested in UseTrees")
315 pub fn has_inner_comment(&self) -> bool {
317 .children_with_tokens()
318 .filter_map(|it| it.into_token())
319 .find_map(ast::Comment::cast)
325 pub fn self_ty(&self) -> Option<ast::Type> {
326 match self.target() {
327 (Some(t), None) | (_, Some(t)) => Some(t),
332 pub fn trait_(&self) -> Option<ast::Type> {
333 match self.target() {
334 (Some(t), Some(_)) => Some(t),
339 fn target(&self) -> (Option<ast::Type>, Option<ast::Type>) {
340 let mut types = support::children(self.syntax());
341 let first = types.next();
342 let second = types.next();
346 pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> {
347 let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?;
348 if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() {
356 #[derive(Debug, Clone, PartialEq, Eq)]
357 pub enum StructKind {
358 Record(ast::RecordFieldList),
359 Tuple(ast::TupleFieldList),
364 fn from_node<N: AstNode>(node: &N) -> StructKind {
365 if let Some(nfdl) = support::child::<ast::RecordFieldList>(node.syntax()) {
366 StructKind::Record(nfdl)
367 } else if let Some(pfl) = support::child::<ast::TupleFieldList>(node.syntax()) {
368 StructKind::Tuple(pfl)
376 pub fn kind(&self) -> StructKind {
377 StructKind::from_node(self)
381 impl ast::RecordExprField {
382 pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
383 let candidate = Self::for_name_ref(field_name)?;
384 if candidate.field_name().as_ref() == Some(field_name) {
391 pub fn for_name_ref(name_ref: &ast::NameRef) -> Option<ast::RecordExprField> {
392 let syn = name_ref.syntax();
394 .and_then(ast::RecordExprField::cast)
395 .or_else(|| syn.ancestors().nth(4).and_then(ast::RecordExprField::cast))
398 /// Deals with field init shorthand
399 pub fn field_name(&self) -> Option<ast::NameRef> {
400 if let Some(name_ref) = self.name_ref() {
401 return Some(name_ref);
403 if let ast::Expr::PathExpr(expr) = self.expr()? {
404 let path = expr.path()?;
405 let segment = path.segment()?;
406 let name_ref = segment.name_ref()?;
407 if path.qualifier().is_none() {
408 return Some(name_ref);
415 #[derive(Debug, Clone)]
417 NameRef(ast::NameRef),
419 Lifetime(ast::Lifetime),
423 pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
425 NameLike::NameRef(name_ref) => Some(name_ref),
429 pub fn as_lifetime(&self) -> Option<&ast::Lifetime> {
431 NameLike::Lifetime(lifetime) => Some(lifetime),
435 pub fn text(&self) -> TokenText<'_> {
437 NameLike::NameRef(name_ref) => name_ref.text(),
438 NameLike::Name(name) => name.text(),
439 NameLike::Lifetime(lifetime) => lifetime.text(),
444 impl ast::AstNode for NameLike {
445 fn can_cast(kind: SyntaxKind) -> bool {
446 matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME)
448 fn cast(syntax: SyntaxNode) -> Option<Self> {
449 let res = match syntax.kind() {
450 SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }),
451 SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }),
452 SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }),
457 fn syntax(&self) -> &SyntaxNode {
459 NameLike::NameRef(it) => it.syntax(),
460 NameLike::Name(it) => it.syntax(),
461 NameLike::Lifetime(it) => it.syntax(),
467 use ast::{Lifetime, Name, NameRef};
468 stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
471 #[derive(Debug, Clone, PartialEq)]
472 pub enum NameOrNameRef {
474 NameRef(ast::NameRef),
477 impl fmt::Display for NameOrNameRef {
478 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
480 NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
481 NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
487 pub fn text(&self) -> TokenText<'_> {
489 NameOrNameRef::Name(name) => name.text(),
490 NameOrNameRef::NameRef(name_ref) => name_ref.text(),
495 impl ast::RecordPatField {
496 pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
497 let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
498 match candidate.field_name()? {
499 NameOrNameRef::NameRef(name_ref) if name_ref == *field_name => Some(candidate),
504 pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
506 field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
507 match candidate.field_name()? {
508 NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
513 pub fn parent_record_pat(&self) -> ast::RecordPat {
514 self.syntax().ancestors().find_map(ast::RecordPat::cast).unwrap()
517 /// Deals with field init shorthand
518 pub fn field_name(&self) -> Option<NameOrNameRef> {
519 if let Some(name_ref) = self.name_ref() {
520 return Some(NameOrNameRef::NameRef(name_ref));
523 Some(ast::Pat::IdentPat(pat)) => {
524 let name = pat.name()?;
525 Some(NameOrNameRef::Name(name))
527 Some(ast::Pat::BoxPat(pat)) => match pat.pat() {
528 Some(ast::Pat::IdentPat(pat)) => {
529 let name = pat.name()?;
530 Some(NameOrNameRef::Name(name))
540 pub fn parent_enum(&self) -> ast::Enum {
543 .and_then(|it| it.parent())
544 .and_then(ast::Enum::cast)
545 .expect("EnumVariants are always nested in Enums")
547 pub fn kind(&self) -> StructKind {
548 StructKind::from_node(self)
553 pub fn generic_param_list(&self) -> Option<ast::GenericParamList> {
554 ast::AnyHasGenericParams::cast(self.syntax().clone())?.generic_param_list()
558 #[derive(Debug, Clone, PartialEq, Eq)]
564 impl ast::FieldExpr {
565 pub fn index_token(&self) -> Option<SyntaxToken> {
567 .children_with_tokens()
568 // FIXME: Accepting floats here to reject them in validation later
569 .find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
571 .and_then(SyntaxElement::as_token)
575 pub fn field_access(&self) -> Option<FieldKind> {
576 match self.name_ref() {
577 Some(nr) => Some(FieldKind::Name(nr)),
578 None => self.index_token().map(FieldKind::Index),
583 pub struct SlicePatComponents {
584 pub prefix: Vec<ast::Pat>,
585 pub slice: Option<ast::Pat>,
586 pub suffix: Vec<ast::Pat>,
590 pub fn components(&self) -> SlicePatComponents {
591 let mut args = self.pats().peekable();
593 .peeking_take_while(|p| match p {
594 ast::Pat::RestPat(_) => false,
595 ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
596 ast::Pat::RefPat(rp) => match rp.pat() {
597 Some(ast::Pat::RestPat(_)) => false,
598 Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
604 let slice = args.next();
605 let suffix = args.collect();
607 SlicePatComponents { prefix, slice, suffix }
612 pub fn is_simple_ident(&self) -> bool {
613 self.at_token().is_none()
614 && self.mut_token().is_none()
615 && self.ref_token().is_none()
616 && self.pat().is_none()
620 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
621 pub enum SelfParamKind {
630 impl ast::SelfParam {
631 pub fn kind(&self) -> SelfParamKind {
632 if self.amp_token().is_some() {
633 if self.mut_token().is_some() {
634 SelfParamKind::MutRef
644 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
645 pub enum TypeBoundKind {
647 PathType(ast::PathType),
649 ForType(ast::ForType),
651 Lifetime(ast::Lifetime),
654 impl ast::TypeBound {
655 pub fn kind(&self) -> TypeBoundKind {
656 if let Some(path_type) = support::children(self.syntax()).next() {
657 TypeBoundKind::PathType(path_type)
658 } else if let Some(for_type) = support::children(self.syntax()).next() {
659 TypeBoundKind::ForType(for_type)
660 } else if let Some(lifetime) = self.lifetime() {
661 TypeBoundKind::Lifetime(lifetime)
668 #[derive(Debug, Clone)]
669 pub enum TypeOrConstParam {
670 Type(ast::TypeParam),
671 Const(ast::ConstParam),
674 impl TypeOrConstParam {
675 pub fn name(&self) -> Option<ast::Name> {
677 TypeOrConstParam::Type(x) => x.name(),
678 TypeOrConstParam::Const(x) => x.name(),
683 pub enum VisibilityKind {
691 impl ast::Visibility {
692 pub fn kind(&self) -> VisibilityKind {
695 if let Some(segment) =
696 path.as_single_segment().filter(|it| it.coloncolon_token().is_none())
698 if segment.crate_token().is_some() {
699 return VisibilityKind::PubCrate;
700 } else if segment.super_token().is_some() {
701 return VisibilityKind::PubSuper;
702 } else if segment.self_token().is_some() {
703 return VisibilityKind::PubSelf;
706 VisibilityKind::In(path)
708 None => VisibilityKind::Pub,
713 impl ast::LifetimeParam {
714 pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
716 .children_with_tokens()
717 .filter_map(|it| it.into_token())
718 .skip_while(|x| x.kind() != T![:])
719 .filter(|it| it.kind() == T![lifetime_ident])
724 /// Returns the parent ast::Module, this is different than the semantic parent in that this only
725 /// considers parent declarations in the AST
726 pub fn parent(&self) -> Option<ast::Module> {
727 self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
732 pub fn start(&self) -> Option<ast::Pat> {
734 .children_with_tokens()
735 .take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
736 .filter_map(|it| it.into_node())
737 .find_map(ast::Pat::cast)
740 pub fn end(&self) -> Option<ast::Pat> {
742 .children_with_tokens()
743 .skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
744 .filter_map(|it| it.into_node())
745 .find_map(ast::Pat::cast)
749 impl ast::TokenTree {
750 pub fn token_trees_and_tokens(
752 ) -> impl Iterator<Item = NodeOrToken<ast::TokenTree, SyntaxToken>> {
753 self.syntax().children_with_tokens().filter_map(|not| match not {
754 NodeOrToken::Node(node) => ast::TokenTree::cast(node).map(NodeOrToken::Node),
755 NodeOrToken::Token(t) => Some(NodeOrToken::Token(t)),
759 pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
761 .first_child_or_token()?
763 .filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
766 pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
768 .last_child_or_token()?
770 .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
773 pub fn parent_meta(&self) -> Option<ast::Meta> {
774 self.syntax().parent().and_then(ast::Meta::cast)
779 pub fn parent_attr(&self) -> Option<ast::Attr> {
780 self.syntax().parent().and_then(ast::Attr::cast)
784 impl ast::GenericArgList {
785 pub fn lifetime_args(&self) -> impl Iterator<Item = ast::LifetimeArg> {
786 self.generic_args().filter_map(|arg| match arg {
787 ast::GenericArg::LifetimeArg(it) => Some(it),
793 impl ast::GenericParamList {
794 pub fn lifetime_params(&self) -> impl Iterator<Item = ast::LifetimeParam> {
795 self.generic_params().filter_map(|param| match param {
796 ast::GenericParam::LifetimeParam(it) => Some(it),
797 ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
800 pub fn type_or_const_params(&self) -> impl Iterator<Item = ast::TypeOrConstParam> {
801 self.generic_params().filter_map(|param| match param {
802 ast::GenericParam::TypeParam(it) => Some(ast::TypeOrConstParam::Type(it)),
803 ast::GenericParam::LifetimeParam(_) => None,
804 ast::GenericParam::ConstParam(it) => Some(ast::TypeOrConstParam::Const(it)),
810 pub fn iterable(&self) -> Option<ast::Expr> {
811 // If the iterable is a BlockExpr, check if the body is missing.
812 // If it is assume the iterable is the expression that is missing instead.
813 let mut exprs = support::children(self.syntax());
814 let first = exprs.next();
816 Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
822 impl ast::HasLoopBody for ast::ForExpr {
823 fn loop_body(&self) -> Option<ast::BlockExpr> {
824 let mut exprs = support::children(self.syntax());
825 let first = exprs.next();
826 let second = exprs.next();
831 impl ast::WhileExpr {
832 pub fn condition(&self) -> Option<ast::Expr> {
833 // If the condition is a BlockExpr, check if the body is missing.
834 // If it is assume the condition is the expression that is missing instead.
835 let mut exprs = support::children(self.syntax());
836 let first = exprs.next();
838 Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
844 impl ast::HasLoopBody for ast::WhileExpr {
845 fn loop_body(&self) -> Option<ast::BlockExpr> {
846 let mut exprs = support::children(self.syntax());
847 let first = exprs.next();
848 let second = exprs.next();
853 impl ast::HasAttrs for ast::AnyHasDocComments {}
855 impl From<ast::Adt> for ast::Item {
856 fn from(it: ast::Adt) -> Self {
858 ast::Adt::Enum(it) => ast::Item::Enum(it),
859 ast::Adt::Struct(it) => ast::Item::Struct(it),
860 ast::Adt::Union(it) => ast::Item::Union(it),
866 pub fn condition(&self) -> Option<ast::Expr> {
867 support::child(&self.syntax)
871 impl ast::MatchGuard {
872 pub fn condition(&self) -> Option<ast::Expr> {
873 support::child(&self.syntax)
877 impl From<ast::Item> for ast::AnyHasAttrs {
878 fn from(node: ast::Item) -> Self {
883 impl From<ast::AssocItem> for ast::AnyHasAttrs {
884 fn from(node: ast::AssocItem) -> Self {
889 impl From<ast::Variant> for ast::AnyHasAttrs {
890 fn from(node: ast::Variant) -> Self {
895 impl From<ast::RecordField> for ast::AnyHasAttrs {
896 fn from(node: ast::RecordField) -> Self {
901 impl From<ast::TupleField> for ast::AnyHasAttrs {
902 fn from(node: ast::TupleField) -> Self {