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()
39 fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
40 fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
41 green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
45 Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()),
46 Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()),
50 impl ast::HasModuleItem for ast::StmtList {}
53 // FIXME: remove all these methods, they belong to ast::StmtList
54 pub fn statements(&self) -> impl Iterator<Item = ast::Stmt> {
55 self.stmt_list().into_iter().flat_map(|it| it.statements())
57 pub fn tail_expr(&self) -> Option<ast::Expr> {
58 self.stmt_list()?.tail_expr()
62 #[derive(Debug, PartialEq, Eq, Clone)]
64 MacroRules(ast::MacroRules),
65 MacroDef(ast::MacroDef),
68 impl From<ast::MacroRules> for Macro {
69 fn from(it: ast::MacroRules) -> Self {
74 impl From<ast::MacroDef> for Macro {
75 fn from(it: ast::MacroDef) -> Self {
80 impl AstNode for Macro {
81 fn can_cast(kind: SyntaxKind) -> bool {
82 matches!(kind, SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF)
84 fn cast(syntax: SyntaxNode) -> Option<Self> {
85 let res = match syntax.kind() {
86 SyntaxKind::MACRO_RULES => Macro::MacroRules(ast::MacroRules { syntax }),
87 SyntaxKind::MACRO_DEF => Macro::MacroDef(ast::MacroDef { syntax }),
92 fn syntax(&self) -> &SyntaxNode {
94 Macro::MacroRules(it) => it.syntax(),
95 Macro::MacroDef(it) => it.syntax(),
100 impl HasName for Macro {
101 fn name(&self) -> Option<ast::Name> {
103 Macro::MacroRules(mac) => mac.name(),
104 Macro::MacroDef(mac) => mac.name(),
109 impl HasAttrs for Macro {}
111 impl From<ast::AssocItem> for ast::Item {
112 fn from(assoc: ast::AssocItem) -> Self {
114 ast::AssocItem::Const(it) => ast::Item::Const(it),
115 ast::AssocItem::Fn(it) => ast::Item::Fn(it),
116 ast::AssocItem::MacroCall(it) => ast::Item::MacroCall(it),
117 ast::AssocItem::TypeAlias(it) => ast::Item::TypeAlias(it),
122 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
129 /// Returns `true` if the attr_kind is [`Inner`](Self::Inner).
130 pub fn is_inner(&self) -> bool {
131 matches!(self, Self::Inner)
134 /// Returns `true` if the attr_kind is [`Outer`](Self::Outer).
135 pub fn is_outer(&self) -> bool {
136 matches!(self, Self::Outer)
141 pub fn as_simple_atom(&self) -> Option<SmolStr> {
142 let meta = self.meta()?;
143 if meta.eq_token().is_some() || meta.token_tree().is_some() {
149 pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
150 let tt = self.meta()?.token_tree()?;
151 Some((self.simple_name()?, tt))
154 pub fn simple_name(&self) -> Option<SmolStr> {
155 let path = self.meta()?.path()?;
156 match (path.segment(), path.qualifier()) {
157 (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()),
162 pub fn kind(&self) -> AttrKind {
163 match self.excl_token() {
164 Some(_) => AttrKind::Inner,
165 None => AttrKind::Outer,
169 pub fn path(&self) -> Option<ast::Path> {
173 pub fn expr(&self) -> Option<ast::Expr> {
177 pub fn token_tree(&self) -> Option<ast::TokenTree> {
178 self.meta()?.token_tree()
182 #[derive(Debug, Clone, PartialEq, Eq)]
183 pub enum PathSegmentKind {
185 Type { type_ref: Option<ast::Type>, trait_ref: Option<ast::PathType> },
191 impl ast::PathSegment {
192 pub fn parent_path(&self) -> ast::Path {
195 .and_then(ast::Path::cast)
196 .expect("segments are always nested in paths")
199 pub fn crate_token(&self) -> Option<SyntaxToken> {
200 self.name_ref().and_then(|it| it.crate_token())
203 pub fn self_token(&self) -> Option<SyntaxToken> {
204 self.name_ref().and_then(|it| it.self_token())
207 pub fn super_token(&self) -> Option<SyntaxToken> {
208 self.name_ref().and_then(|it| it.super_token())
211 pub fn kind(&self) -> Option<PathSegmentKind> {
212 let res = if let Some(name_ref) = self.name_ref() {
213 match name_ref.syntax().first_token().map(|it| it.kind()) {
214 Some(T![self]) => PathSegmentKind::SelfKw,
215 Some(T![super]) => PathSegmentKind::SuperKw,
216 Some(T![crate]) => PathSegmentKind::CrateKw,
217 _ => PathSegmentKind::Name(name_ref),
220 match self.syntax().first_child_or_token()?.kind() {
222 // <T> or <T as Trait>
223 // T is any TypeRef, Trait has to be a PathType
225 self.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
226 let type_ref = type_refs.next().and_then(ast::Type::cast);
227 let trait_ref = type_refs.next().and_then(ast::PathType::cast);
228 PathSegmentKind::Type { type_ref, trait_ref }
238 pub fn parent_path(&self) -> Option<ast::Path> {
239 self.syntax().parent().and_then(ast::Path::cast)
242 pub fn as_single_segment(&self) -> Option<ast::PathSegment> {
243 match self.qualifier() {
245 None => self.segment(),
249 pub fn as_single_name_ref(&self) -> Option<ast::NameRef> {
250 match self.qualifier() {
252 None => self.segment()?.name_ref(),
256 pub fn first_qualifier_or_self(&self) -> ast::Path {
257 successors(Some(self.clone()), ast::Path::qualifier).last().unwrap()
260 pub fn first_segment(&self) -> Option<ast::PathSegment> {
261 self.first_qualifier_or_self().segment()
264 pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
265 successors(self.first_segment(), |p| {
266 p.parent_path().parent_path().and_then(|p| p.segment())
270 pub fn qualifiers(&self) -> impl Iterator<Item = ast::Path> + Clone {
271 successors(self.qualifier(), |p| p.qualifier())
274 pub fn top_path(&self) -> ast::Path {
275 let mut this = self.clone();
276 while let Some(path) = this.parent_path() {
284 pub fn is_simple_glob(&self) -> bool {
285 self.use_tree().map_or(false, |use_tree| {
286 use_tree.use_tree_list().is_none() && use_tree.star_token().is_some()
292 pub fn is_simple_path(&self) -> bool {
293 self.use_tree_list().is_none() && self.star_token().is_none()
297 impl ast::UseTreeList {
298 pub fn parent_use_tree(&self) -> ast::UseTree {
301 .and_then(ast::UseTree::cast)
302 .expect("UseTreeLists are always nested in UseTrees")
305 pub fn has_inner_comment(&self) -> bool {
307 .children_with_tokens()
308 .filter_map(|it| it.into_token())
309 .find_map(ast::Comment::cast)
315 pub fn self_ty(&self) -> Option<ast::Type> {
316 match self.target() {
317 (Some(t), None) | (_, Some(t)) => Some(t),
322 pub fn trait_(&self) -> Option<ast::Type> {
323 match self.target() {
324 (Some(t), Some(_)) => Some(t),
329 fn target(&self) -> (Option<ast::Type>, Option<ast::Type>) {
330 let mut types = support::children(self.syntax());
331 let first = types.next();
332 let second = types.next();
336 pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> {
337 let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?;
338 if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() {
346 #[derive(Debug, Clone, PartialEq, Eq)]
347 pub enum StructKind {
348 Record(ast::RecordFieldList),
349 Tuple(ast::TupleFieldList),
354 fn from_node<N: AstNode>(node: &N) -> StructKind {
355 if let Some(nfdl) = support::child::<ast::RecordFieldList>(node.syntax()) {
356 StructKind::Record(nfdl)
357 } else if let Some(pfl) = support::child::<ast::TupleFieldList>(node.syntax()) {
358 StructKind::Tuple(pfl)
366 pub fn kind(&self) -> StructKind {
367 StructKind::from_node(self)
371 impl ast::RecordExprField {
372 pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
373 let candidate = Self::for_name_ref(field_name)?;
374 if candidate.field_name().as_ref() == Some(field_name) {
381 pub fn for_name_ref(name_ref: &ast::NameRef) -> Option<ast::RecordExprField> {
382 let syn = name_ref.syntax();
384 .and_then(ast::RecordExprField::cast)
385 .or_else(|| syn.ancestors().nth(4).and_then(ast::RecordExprField::cast))
388 /// Deals with field init shorthand
389 pub fn field_name(&self) -> Option<ast::NameRef> {
390 if let Some(name_ref) = self.name_ref() {
391 return Some(name_ref);
393 if let ast::Expr::PathExpr(expr) = self.expr()? {
394 let path = expr.path()?;
395 let segment = path.segment()?;
396 let name_ref = segment.name_ref()?;
397 if path.qualifier().is_none() {
398 return Some(name_ref);
405 #[derive(Debug, Clone)]
407 NameRef(ast::NameRef),
409 Lifetime(ast::Lifetime),
413 pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
415 NameLike::NameRef(name_ref) => Some(name_ref),
421 impl ast::AstNode for NameLike {
422 fn can_cast(kind: SyntaxKind) -> bool {
423 matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME)
425 fn cast(syntax: SyntaxNode) -> Option<Self> {
426 let res = match syntax.kind() {
427 SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }),
428 SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }),
429 SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }),
434 fn syntax(&self) -> &SyntaxNode {
436 NameLike::NameRef(it) => it.syntax(),
437 NameLike::Name(it) => it.syntax(),
438 NameLike::Lifetime(it) => it.syntax(),
444 use ast::{Lifetime, Name, NameRef};
445 stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
448 #[derive(Debug, Clone, PartialEq)]
449 pub enum NameOrNameRef {
451 NameRef(ast::NameRef),
454 impl fmt::Display for NameOrNameRef {
455 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457 NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
458 NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
464 pub fn text(&self) -> TokenText<'_> {
466 NameOrNameRef::Name(name) => name.text(),
467 NameOrNameRef::NameRef(name_ref) => name_ref.text(),
472 impl ast::RecordPatField {
473 pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
474 let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
475 match candidate.field_name()? {
476 NameOrNameRef::NameRef(name_ref) if name_ref == *field_name => Some(candidate),
481 pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
483 field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
484 match candidate.field_name()? {
485 NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
490 /// Deals with field init shorthand
491 pub fn field_name(&self) -> Option<NameOrNameRef> {
492 if let Some(name_ref) = self.name_ref() {
493 return Some(NameOrNameRef::NameRef(name_ref));
496 Some(ast::Pat::IdentPat(pat)) => {
497 let name = pat.name()?;
498 Some(NameOrNameRef::Name(name))
500 Some(ast::Pat::BoxPat(pat)) => match pat.pat() {
501 Some(ast::Pat::IdentPat(pat)) => {
502 let name = pat.name()?;
503 Some(NameOrNameRef::Name(name))
513 pub fn parent_enum(&self) -> ast::Enum {
516 .and_then(|it| it.parent())
517 .and_then(ast::Enum::cast)
518 .expect("EnumVariants are always nested in Enums")
520 pub fn kind(&self) -> StructKind {
521 StructKind::from_node(self)
526 pub fn generic_param_list(&self) -> Option<ast::GenericParamList> {
527 ast::AnyHasGenericParams::cast(self.syntax().clone())?.generic_param_list()
531 #[derive(Debug, Clone, PartialEq, Eq)]
537 impl ast::FieldExpr {
538 pub fn index_token(&self) -> Option<SyntaxToken> {
540 .children_with_tokens()
541 // FIXME: Accepting floats here to reject them in validation later
542 .find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
544 .and_then(SyntaxElement::as_token)
548 pub fn field_access(&self) -> Option<FieldKind> {
549 match self.name_ref() {
550 Some(nr) => Some(FieldKind::Name(nr)),
551 None => self.index_token().map(FieldKind::Index),
556 pub struct SlicePatComponents {
557 pub prefix: Vec<ast::Pat>,
558 pub slice: Option<ast::Pat>,
559 pub suffix: Vec<ast::Pat>,
563 pub fn components(&self) -> SlicePatComponents {
564 let mut args = self.pats().peekable();
566 .peeking_take_while(|p| match p {
567 ast::Pat::RestPat(_) => false,
568 ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
569 ast::Pat::RefPat(rp) => match rp.pat() {
570 Some(ast::Pat::RestPat(_)) => false,
571 Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
577 let slice = args.next();
578 let suffix = args.collect();
580 SlicePatComponents { prefix, slice, suffix }
585 pub fn is_simple_ident(&self) -> bool {
586 self.at_token().is_none()
587 && self.mut_token().is_none()
588 && self.ref_token().is_none()
589 && self.pat().is_none()
593 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
594 pub enum SelfParamKind {
603 impl ast::SelfParam {
604 pub fn kind(&self) -> SelfParamKind {
605 if self.amp_token().is_some() {
606 if self.mut_token().is_some() {
607 SelfParamKind::MutRef
617 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
618 pub enum TypeBoundKind {
620 PathType(ast::PathType),
622 ForType(ast::ForType),
624 Lifetime(ast::Lifetime),
627 impl ast::TypeBound {
628 pub fn kind(&self) -> TypeBoundKind {
629 if let Some(path_type) = support::children(self.syntax()).next() {
630 TypeBoundKind::PathType(path_type)
631 } else if let Some(for_type) = support::children(self.syntax()).next() {
632 TypeBoundKind::ForType(for_type)
633 } else if let Some(lifetime) = self.lifetime() {
634 TypeBoundKind::Lifetime(lifetime)
641 pub enum VisibilityKind {
649 impl ast::Visibility {
650 pub fn kind(&self) -> VisibilityKind {
653 if let Some(segment) =
654 path.as_single_segment().filter(|it| it.coloncolon_token().is_none())
656 if segment.crate_token().is_some() {
657 return VisibilityKind::PubCrate;
658 } else if segment.super_token().is_some() {
659 return VisibilityKind::PubSuper;
660 } else if segment.self_token().is_some() {
661 return VisibilityKind::PubSelf;
664 VisibilityKind::In(path)
666 None => VisibilityKind::Pub,
671 impl ast::LifetimeParam {
672 pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
674 .children_with_tokens()
675 .filter_map(|it| it.into_token())
676 .skip_while(|x| x.kind() != T![:])
677 .filter(|it| it.kind() == T![lifetime_ident])
682 /// Returns the parent ast::Module, this is different than the semantic parent in that this only
683 /// considers parent declarations in the AST
684 pub fn parent(&self) -> Option<ast::Module> {
685 self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
690 pub fn start(&self) -> Option<ast::Pat> {
692 .children_with_tokens()
693 .take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
694 .filter_map(|it| it.into_node())
695 .find_map(ast::Pat::cast)
698 pub fn end(&self) -> Option<ast::Pat> {
700 .children_with_tokens()
701 .skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
702 .filter_map(|it| it.into_node())
703 .find_map(ast::Pat::cast)
707 impl ast::TokenTree {
708 pub fn token_trees_and_tokens(
710 ) -> impl Iterator<Item = NodeOrToken<ast::TokenTree, SyntaxToken>> {
711 self.syntax().children_with_tokens().filter_map(|not| match not {
712 NodeOrToken::Node(node) => ast::TokenTree::cast(node).map(NodeOrToken::Node),
713 NodeOrToken::Token(t) => Some(NodeOrToken::Token(t)),
717 pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
719 .first_child_or_token()?
721 .filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
724 pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
726 .last_child_or_token()?
728 .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
731 pub fn parent_meta(&self) -> Option<ast::Meta> {
732 self.syntax().parent().and_then(ast::Meta::cast)
737 pub fn parent_attr(&self) -> Option<ast::Attr> {
738 self.syntax().parent().and_then(ast::Attr::cast)
742 impl ast::GenericParamList {
743 pub fn lifetime_params(&self) -> impl Iterator<Item = ast::LifetimeParam> {
744 self.generic_params().filter_map(|param| match param {
745 ast::GenericParam::LifetimeParam(it) => Some(it),
746 ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
749 pub fn type_params(&self) -> impl Iterator<Item = ast::TypeParam> {
750 self.generic_params().filter_map(|param| match param {
751 ast::GenericParam::TypeParam(it) => Some(it),
752 ast::GenericParam::LifetimeParam(_) | ast::GenericParam::ConstParam(_) => None,
755 pub fn const_params(&self) -> impl Iterator<Item = ast::ConstParam> {
756 self.generic_params().filter_map(|param| match param {
757 ast::GenericParam::ConstParam(it) => Some(it),
758 ast::GenericParam::TypeParam(_) | ast::GenericParam::LifetimeParam(_) => None,
763 impl ast::HasLoopBody for ast::ForExpr {
764 fn loop_body(&self) -> Option<ast::BlockExpr> {
765 let mut exprs = support::children(self.syntax());
766 let first = exprs.next();
767 let second = exprs.next();
772 impl ast::HasAttrs for ast::AnyHasDocComments {}
774 impl From<ast::Adt> for ast::Item {
775 fn from(it: ast::Adt) -> Self {
777 ast::Adt::Enum(it) => ast::Item::Enum(it),
778 ast::Adt::Struct(it) => ast::Item::Struct(it),
779 ast::Adt::Union(it) => ast::Item::Union(it),