2019-04-02 05:02:23 -05:00
|
|
|
//! Various extension methods to ast Nodes, which are hard to code-generate.
|
|
|
|
//! Extensions for various expressions live in a sibling `expr_extensions` module.
|
|
|
|
|
2020-02-11 15:33:11 -06:00
|
|
|
use itertools::Itertools;
|
2020-04-09 11:20:06 -05:00
|
|
|
use ra_parser::SyntaxKind;
|
2020-02-11 15:33:11 -06:00
|
|
|
|
2019-05-20 17:04:20 -05:00
|
|
|
use crate::{
|
2020-04-03 14:12:09 -05:00
|
|
|
ast::{
|
2020-04-09 06:00:09 -05:00
|
|
|
self, child_opt, children, support, AstNode, AstToken, AttrInput, NameOwner, SyntaxNode,
|
2020-04-03 14:12:09 -05:00
|
|
|
},
|
2020-04-09 11:20:06 -05:00
|
|
|
SmolStr, SyntaxElement, SyntaxToken, T,
|
2019-05-20 17:04:20 -05:00
|
|
|
};
|
2019-04-02 04:47:39 -05:00
|
|
|
|
|
|
|
impl ast::Name {
|
|
|
|
pub fn text(&self) -> &SmolStr {
|
2019-07-18 11:23:05 -05:00
|
|
|
text_of_first_token(self.syntax())
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::NameRef {
|
|
|
|
pub fn text(&self) -> &SmolStr {
|
2019-07-18 11:23:05 -05:00
|
|
|
text_of_first_token(self.syntax())
|
|
|
|
}
|
2019-09-26 13:04:47 -05:00
|
|
|
|
|
|
|
pub fn as_tuple_field(&self) -> Option<usize> {
|
2020-04-09 11:25:36 -05:00
|
|
|
if let Some(ast::NameRefToken::IntNumber(token)) = self.name_ref_token_token() {
|
2020-04-09 11:20:06 -05:00
|
|
|
token.text().as_str().parse().ok()
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2019-09-26 13:04:47 -05:00
|
|
|
}
|
2019-07-18 11:23:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn text_of_first_token(node: &SyntaxNode) -> &SmolStr {
|
2019-11-19 12:13:36 -06:00
|
|
|
node.green().children().next().and_then(|it| it.into_token()).unwrap().text()
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
2020-02-12 08:44:52 -06:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub enum AttrKind {
|
|
|
|
Inner,
|
|
|
|
Outer,
|
|
|
|
}
|
|
|
|
|
2019-04-02 04:47:39 -05:00
|
|
|
impl ast::Attr {
|
2019-09-29 16:15:03 -05:00
|
|
|
pub fn as_simple_atom(&self) -> Option<SmolStr> {
|
|
|
|
match self.input() {
|
|
|
|
None => self.simple_name(),
|
|
|
|
Some(_) => None,
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-29 16:15:03 -05:00
|
|
|
pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
|
|
|
|
match self.input() {
|
|
|
|
Some(AttrInput::TokenTree(tt)) => Some((self.simple_name()?, tt)),
|
|
|
|
_ => None,
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-29 16:15:03 -05:00
|
|
|
pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> {
|
|
|
|
match self.input() {
|
|
|
|
Some(AttrInput::Literal(lit)) => {
|
|
|
|
let key = self.simple_name()?;
|
|
|
|
// FIXME: escape? raw string?
|
|
|
|
let value = lit.syntax().first_token()?.text().trim_matches('"').into();
|
|
|
|
Some((key, value))
|
|
|
|
}
|
|
|
|
_ => None,
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
2019-04-14 17:03:54 -05:00
|
|
|
|
2019-09-29 16:15:03 -05:00
|
|
|
pub fn simple_name(&self) -> Option<SmolStr> {
|
|
|
|
let path = self.path()?;
|
|
|
|
match (path.segment(), path.qualifier()) {
|
|
|
|
(Some(segment), None) => Some(segment.syntax().first_token()?.text().clone()),
|
|
|
|
_ => None,
|
2019-04-14 17:03:54 -05:00
|
|
|
}
|
|
|
|
}
|
2020-02-12 08:21:55 -06:00
|
|
|
|
2020-02-12 08:44:52 -06:00
|
|
|
pub fn kind(&self) -> AttrKind {
|
2020-02-12 08:21:55 -06:00
|
|
|
let first_token = self.syntax().first_token();
|
|
|
|
let first_token_kind = first_token.as_ref().map(SyntaxToken::kind);
|
|
|
|
let second_token_kind =
|
|
|
|
first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind);
|
2020-02-12 08:44:52 -06:00
|
|
|
|
|
|
|
match (first_token_kind, second_token_kind) {
|
|
|
|
(Some(SyntaxKind::POUND), Some(SyntaxKind::EXCL)) => AttrKind::Inner,
|
|
|
|
_ => AttrKind::Outer,
|
|
|
|
}
|
2020-02-12 08:21:55 -06:00
|
|
|
}
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
2019-07-18 11:23:05 -05:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub enum PathSegmentKind {
|
|
|
|
Name(ast::NameRef),
|
2019-08-05 15:42:38 -05:00
|
|
|
Type { type_ref: Option<ast::TypeRef>, trait_ref: Option<ast::PathType> },
|
2019-04-02 04:47:39 -05:00
|
|
|
SelfKw,
|
|
|
|
SuperKw,
|
|
|
|
CrateKw,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::PathSegment {
|
2019-07-18 11:23:05 -05:00
|
|
|
pub fn parent_path(&self) -> ast::Path {
|
2019-04-02 04:47:39 -05:00
|
|
|
self.syntax()
|
|
|
|
.parent()
|
|
|
|
.and_then(ast::Path::cast)
|
|
|
|
.expect("segments are always nested in paths")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn kind(&self) -> Option<PathSegmentKind> {
|
|
|
|
let res = if let Some(name_ref) = self.name_ref() {
|
|
|
|
PathSegmentKind::Name(name_ref)
|
|
|
|
} else {
|
|
|
|
match self.syntax().first_child_or_token()?.kind() {
|
2019-05-15 07:35:47 -05:00
|
|
|
T![self] => PathSegmentKind::SelfKw,
|
|
|
|
T![super] => PathSegmentKind::SuperKw,
|
|
|
|
T![crate] => PathSegmentKind::CrateKw,
|
2019-08-05 15:42:38 -05:00
|
|
|
T![<] => {
|
|
|
|
// <T> or <T as Trait>
|
|
|
|
// T is any TypeRef, Trait has to be a PathType
|
|
|
|
let mut type_refs =
|
|
|
|
self.syntax().children().filter(|node| ast::TypeRef::can_cast(node.kind()));
|
|
|
|
let type_ref = type_refs.next().and_then(ast::TypeRef::cast);
|
|
|
|
let trait_ref = type_refs.next().and_then(ast::PathType::cast);
|
|
|
|
PathSegmentKind::Type { type_ref, trait_ref }
|
|
|
|
}
|
2019-04-02 04:47:39 -05:00
|
|
|
_ => return None,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Some(res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::Path {
|
2019-07-18 11:23:05 -05:00
|
|
|
pub fn parent_path(&self) -> Option<ast::Path> {
|
2019-04-02 04:47:39 -05:00
|
|
|
self.syntax().parent().and_then(ast::Path::cast)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::Module {
|
|
|
|
pub fn has_semi(&self) -> bool {
|
2020-04-09 11:25:36 -05:00
|
|
|
self.semi_token().is_some()
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::UseTreeList {
|
2019-07-18 11:23:05 -05:00
|
|
|
pub fn parent_use_tree(&self) -> ast::UseTree {
|
2019-04-02 04:47:39 -05:00
|
|
|
self.syntax()
|
|
|
|
.parent()
|
|
|
|
.and_then(ast::UseTree::cast)
|
|
|
|
.expect("UseTreeLists are always nested in UseTrees")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-29 14:24:40 -06:00
|
|
|
impl ast::ImplDef {
|
2019-07-18 11:23:05 -05:00
|
|
|
pub fn target_type(&self) -> Option<ast::TypeRef> {
|
2019-04-02 04:47:39 -05:00
|
|
|
match self.target() {
|
|
|
|
(Some(t), None) | (_, Some(t)) => Some(t),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-18 11:23:05 -05:00
|
|
|
pub fn target_trait(&self) -> Option<ast::TypeRef> {
|
2019-04-02 04:47:39 -05:00
|
|
|
match self.target() {
|
|
|
|
(Some(t), Some(_)) => Some(t),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-18 11:23:05 -05:00
|
|
|
fn target(&self) -> (Option<ast::TypeRef>, Option<ast::TypeRef>) {
|
2019-04-02 04:47:39 -05:00
|
|
|
let mut types = children(self);
|
|
|
|
let first = types.next();
|
|
|
|
let second = types.next();
|
|
|
|
(first, second)
|
|
|
|
}
|
2019-05-07 11:53:16 -05:00
|
|
|
|
|
|
|
pub fn is_negative(&self) -> bool {
|
2020-04-09 11:25:36 -05:00
|
|
|
self.excl_token().is_some()
|
2019-05-07 11:53:16 -05:00
|
|
|
}
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2019-07-18 11:23:05 -05:00
|
|
|
pub enum StructKind {
|
2019-11-22 12:52:06 -06:00
|
|
|
Record(ast::RecordFieldDefList),
|
2019-08-23 07:55:21 -05:00
|
|
|
Tuple(ast::TupleFieldDefList),
|
2019-04-02 04:47:39 -05:00
|
|
|
Unit,
|
|
|
|
}
|
|
|
|
|
2019-07-18 11:23:05 -05:00
|
|
|
impl StructKind {
|
2019-04-02 04:48:14 -05:00
|
|
|
fn from_node<N: AstNode>(node: &N) -> StructKind {
|
2019-08-23 07:55:21 -05:00
|
|
|
if let Some(nfdl) = child_opt::<_, ast::RecordFieldDefList>(node) {
|
2019-11-22 12:52:06 -06:00
|
|
|
StructKind::Record(nfdl)
|
2019-08-23 07:55:21 -05:00
|
|
|
} else if let Some(pfl) = child_opt::<_, ast::TupleFieldDefList>(node) {
|
2019-04-02 04:48:14 -05:00
|
|
|
StructKind::Tuple(pfl)
|
2019-04-02 04:47:39 -05:00
|
|
|
} else {
|
2019-04-02 04:48:14 -05:00
|
|
|
StructKind::Unit
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::StructDef {
|
2019-04-02 04:48:14 -05:00
|
|
|
pub fn kind(&self) -> StructKind {
|
|
|
|
StructKind::from_node(self)
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::EnumVariant {
|
2019-07-18 11:23:05 -05:00
|
|
|
pub fn parent_enum(&self) -> ast::EnumDef {
|
2019-04-02 04:47:39 -05:00
|
|
|
self.syntax()
|
|
|
|
.parent()
|
|
|
|
.and_then(|it| it.parent())
|
|
|
|
.and_then(ast::EnumDef::cast)
|
|
|
|
.expect("EnumVariants are always nested in Enums")
|
|
|
|
}
|
2019-04-02 04:48:14 -05:00
|
|
|
pub fn kind(&self) -> StructKind {
|
|
|
|
StructKind::from_node(self)
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-22 05:01:33 -05:00
|
|
|
impl ast::FnDef {
|
2019-07-18 11:23:05 -05:00
|
|
|
pub fn semicolon_token(&self) -> Option<SyntaxToken> {
|
2020-04-09 11:25:36 -05:00
|
|
|
Some(self.semi_token()?.syntax().clone())
|
2019-04-22 05:01:33 -05:00
|
|
|
}
|
2019-12-24 10:25:18 -06:00
|
|
|
|
|
|
|
pub fn is_async(&self) -> bool {
|
2020-04-09 11:25:36 -05:00
|
|
|
self.async_kw_token().is_some()
|
2019-12-24 10:25:18 -06:00
|
|
|
}
|
2019-04-22 05:01:33 -05:00
|
|
|
}
|
|
|
|
|
2019-04-02 04:47:39 -05:00
|
|
|
impl ast::LetStmt {
|
|
|
|
pub fn has_semi(&self) -> bool {
|
|
|
|
match self.syntax().last_child_or_token() {
|
|
|
|
None => false,
|
2019-05-15 07:35:47 -05:00
|
|
|
Some(node) => node.kind() == T![;],
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::ExprStmt {
|
|
|
|
pub fn has_semi(&self) -> bool {
|
2020-04-09 11:25:36 -05:00
|
|
|
self.semi_token().is_some()
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-05 15:34:45 -05:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2019-07-18 11:23:05 -05:00
|
|
|
pub enum FieldKind {
|
|
|
|
Name(ast::NameRef),
|
|
|
|
Index(SyntaxToken),
|
2019-04-05 15:34:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::FieldExpr {
|
|
|
|
pub fn index_token(&self) -> Option<SyntaxToken> {
|
|
|
|
self.syntax
|
|
|
|
.children_with_tokens()
|
|
|
|
// FIXME: Accepting floats here to reject them in validation later
|
|
|
|
.find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
|
|
|
|
.as_ref()
|
|
|
|
.and_then(SyntaxElement::as_token)
|
2019-07-18 11:23:05 -05:00
|
|
|
.cloned()
|
2019-04-05 15:34:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn field_access(&self) -> Option<FieldKind> {
|
|
|
|
if let Some(nr) = self.name_ref() {
|
|
|
|
Some(FieldKind::Name(nr))
|
|
|
|
} else if let Some(tok) = self.index_token() {
|
|
|
|
Some(FieldKind::Index(tok))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 04:47:39 -05:00
|
|
|
impl ast::RefPat {
|
|
|
|
pub fn is_mut(&self) -> bool {
|
2019-05-15 07:35:47 -05:00
|
|
|
self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::BindPat {
|
|
|
|
pub fn is_mutable(&self) -> bool {
|
2019-05-15 07:35:47 -05:00
|
|
|
self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_ref(&self) -> bool {
|
2019-05-15 07:35:47 -05:00
|
|
|
self.syntax().children_with_tokens().any(|n| n.kind() == T![ref])
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
2020-04-03 12:59:28 -05:00
|
|
|
pub fn has_at(&self) -> bool {
|
|
|
|
self.syntax().children_with_tokens().any(|it| it.kind() == T![@])
|
|
|
|
}
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
2020-02-11 15:33:11 -06:00
|
|
|
pub struct SlicePatComponents {
|
|
|
|
pub prefix: Vec<ast::Pat>,
|
|
|
|
pub slice: Option<ast::Pat>,
|
|
|
|
pub suffix: Vec<ast::Pat>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::SlicePat {
|
|
|
|
pub fn components(&self) -> SlicePatComponents {
|
|
|
|
let mut args = self.args().peekable();
|
|
|
|
let prefix = args
|
|
|
|
.peeking_take_while(|p| match p {
|
|
|
|
ast::Pat::DotDotPat(_) => false,
|
|
|
|
ast::Pat::BindPat(bp) => match bp.pat() {
|
|
|
|
Some(ast::Pat::DotDotPat(_)) => false,
|
|
|
|
_ => true,
|
|
|
|
},
|
|
|
|
ast::Pat::RefPat(rp) => match rp.pat() {
|
|
|
|
Some(ast::Pat::DotDotPat(_)) => false,
|
|
|
|
Some(ast::Pat::BindPat(bp)) => match bp.pat() {
|
|
|
|
Some(ast::Pat::DotDotPat(_)) => false,
|
|
|
|
_ => true,
|
|
|
|
},
|
|
|
|
_ => true,
|
|
|
|
},
|
|
|
|
_ => true,
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let slice = args.next();
|
|
|
|
let suffix = args.collect();
|
|
|
|
|
|
|
|
SlicePatComponents { prefix, slice, suffix }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 04:47:39 -05:00
|
|
|
impl ast::PointerType {
|
|
|
|
pub fn is_mut(&self) -> bool {
|
2019-05-15 07:35:47 -05:00
|
|
|
self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::ReferenceType {
|
|
|
|
pub fn is_mut(&self) -> bool {
|
2019-05-15 07:35:47 -05:00
|
|
|
self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
2019-04-02 04:48:14 -05:00
|
|
|
pub enum SelfParamKind {
|
2019-04-02 04:47:39 -05:00
|
|
|
/// self
|
|
|
|
Owned,
|
|
|
|
/// &self
|
|
|
|
Ref,
|
|
|
|
/// &mut self
|
|
|
|
MutRef,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::SelfParam {
|
2019-04-02 04:48:14 -05:00
|
|
|
pub fn kind(&self) -> SelfParamKind {
|
2020-04-09 11:25:36 -05:00
|
|
|
if self.amp_token().is_some() {
|
2020-04-03 14:12:09 -05:00
|
|
|
if self.amp_mut_kw().is_some() {
|
2019-04-02 04:48:14 -05:00
|
|
|
SelfParamKind::MutRef
|
2019-04-02 04:47:39 -05:00
|
|
|
} else {
|
2019-04-02 04:48:14 -05:00
|
|
|
SelfParamKind::Ref
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
} else {
|
2019-04-02 04:48:14 -05:00
|
|
|
SelfParamKind::Owned
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 14:12:09 -05:00
|
|
|
/// the "mut" in "mut self", not the one in "&mut self"
|
|
|
|
pub fn mut_kw(&self) -> Option<ast::MutKw> {
|
2019-04-02 04:47:39 -05:00
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
2019-07-19 11:05:34 -05:00
|
|
|
.filter_map(|it| it.into_token())
|
2020-04-03 14:12:09 -05:00
|
|
|
.take_while(|it| it.kind() != T![&])
|
|
|
|
.find_map(ast::MutKw::cast)
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
2020-04-03 14:12:09 -05:00
|
|
|
/// the "mut" in "&mut self", not the one in "mut self"
|
|
|
|
pub fn amp_mut_kw(&self) -> Option<ast::MutKw> {
|
2019-09-25 09:57:12 -05:00
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
|
|
|
.filter_map(|it| it.into_token())
|
2020-04-03 14:12:09 -05:00
|
|
|
.skip_while(|it| it.kind() != T![&])
|
|
|
|
.find_map(ast::MutKw::cast)
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
}
|
2019-05-07 11:53:16 -05:00
|
|
|
|
2019-08-22 10:43:09 -05:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub enum TypeBoundKind {
|
|
|
|
/// Trait
|
|
|
|
PathType(ast::PathType),
|
|
|
|
/// for<'a> ...
|
|
|
|
ForType(ast::ForType),
|
|
|
|
/// 'a
|
2020-04-03 14:12:09 -05:00
|
|
|
Lifetime(ast::Lifetime),
|
2019-08-22 10:43:09 -05:00
|
|
|
}
|
|
|
|
|
2019-08-22 07:28:08 -05:00
|
|
|
impl ast::TypeBound {
|
2019-08-22 10:43:09 -05:00
|
|
|
pub fn kind(&self) -> TypeBoundKind {
|
|
|
|
if let Some(path_type) = children(self).next() {
|
|
|
|
TypeBoundKind::PathType(path_type)
|
|
|
|
} else if let Some(for_type) = children(self).next() {
|
|
|
|
TypeBoundKind::ForType(for_type)
|
2020-04-09 11:25:36 -05:00
|
|
|
} else if let Some(lifetime) = self.lifetime_token() {
|
2019-08-22 10:43:09 -05:00
|
|
|
TypeBoundKind::Lifetime(lifetime)
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 14:12:09 -05:00
|
|
|
pub fn has_question_mark(&self) -> bool {
|
|
|
|
self.question().is_some()
|
2019-08-22 10:43:09 -05:00
|
|
|
}
|
|
|
|
|
2020-04-03 14:12:09 -05:00
|
|
|
pub fn const_question(&self) -> Option<ast::Question> {
|
2019-08-22 07:28:08 -05:00
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
|
|
|
.filter_map(|it| it.into_token())
|
2020-04-03 14:12:09 -05:00
|
|
|
.take_while(|it| it.kind() != T![const])
|
|
|
|
.find_map(ast::Question::cast)
|
2019-08-22 07:28:08 -05:00
|
|
|
}
|
2020-04-03 14:12:09 -05:00
|
|
|
|
|
|
|
pub fn question(&self) -> Option<ast::Question> {
|
2020-04-09 11:25:36 -05:00
|
|
|
if self.const_kw_token().is_some() {
|
2020-04-03 14:12:09 -05:00
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
|
|
|
.filter_map(|it| it.into_token())
|
|
|
|
.skip_while(|it| it.kind() != T![const])
|
|
|
|
.find_map(ast::Question::cast)
|
|
|
|
} else {
|
2020-04-09 06:00:09 -05:00
|
|
|
support::token(&self.syntax)
|
2020-04-03 14:12:09 -05:00
|
|
|
}
|
2019-08-22 07:28:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-07 11:53:16 -05:00
|
|
|
impl ast::TraitDef {
|
|
|
|
pub fn is_auto(&self) -> bool {
|
2019-05-15 07:35:47 -05:00
|
|
|
self.syntax().children_with_tokens().any(|t| t.kind() == T![auto])
|
2019-05-07 11:53:16 -05:00
|
|
|
}
|
|
|
|
}
|
2019-12-24 13:32:42 -06:00
|
|
|
|
|
|
|
pub enum VisibilityKind {
|
|
|
|
In(ast::Path),
|
|
|
|
PubCrate,
|
|
|
|
PubSuper,
|
2020-04-03 14:12:09 -05:00
|
|
|
PubSelf,
|
2019-12-24 13:32:42 -06:00
|
|
|
Pub,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::Visibility {
|
|
|
|
pub fn kind(&self) -> VisibilityKind {
|
|
|
|
if let Some(path) = children(self).next() {
|
|
|
|
VisibilityKind::In(path)
|
|
|
|
} else if self.is_pub_crate() {
|
|
|
|
VisibilityKind::PubCrate
|
|
|
|
} else if self.is_pub_super() {
|
|
|
|
VisibilityKind::PubSuper
|
2020-04-03 14:12:09 -05:00
|
|
|
} else if self.is_pub_self() {
|
|
|
|
VisibilityKind::PubSuper
|
2019-12-24 13:32:42 -06:00
|
|
|
} else {
|
|
|
|
VisibilityKind::Pub
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_pub_crate(&self) -> bool {
|
|
|
|
self.syntax().children_with_tokens().any(|it| it.kind() == T![crate])
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_pub_super(&self) -> bool {
|
|
|
|
self.syntax().children_with_tokens().any(|it| it.kind() == T![super])
|
|
|
|
}
|
2020-04-03 14:12:09 -05:00
|
|
|
|
|
|
|
fn is_pub_self(&self) -> bool {
|
|
|
|
self.syntax().children_with_tokens().any(|it| it.kind() == T![self])
|
|
|
|
}
|
2019-12-24 13:32:42 -06:00
|
|
|
}
|
2020-03-22 02:00:44 -05:00
|
|
|
|
|
|
|
impl ast::MacroCall {
|
|
|
|
pub fn is_macro_rules(&self) -> Option<ast::Name> {
|
|
|
|
let name_ref = self.path()?.segment()?.name_ref()?;
|
|
|
|
if name_ref.text() == "macro_rules" {
|
|
|
|
self.name()
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 14:12:09 -05:00
|
|
|
|
|
|
|
impl ast::LifetimeParam {
|
|
|
|
pub fn lifetime_bounds(&self) -> impl Iterator<Item = ast::Lifetime> {
|
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
|
|
|
.filter_map(|it| it.into_token())
|
|
|
|
.skip_while(|x| x.kind() != T![:])
|
|
|
|
.filter_map(ast::Lifetime::cast)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::RangePat {
|
|
|
|
pub fn start(&self) -> Option<ast::Pat> {
|
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
2020-04-09 06:00:09 -05:00
|
|
|
.take_while(|it| !ast::RangeSeparator::can_cast(it.kind()))
|
2020-04-03 14:12:09 -05:00
|
|
|
.filter_map(|it| it.into_node())
|
|
|
|
.find_map(ast::Pat::cast)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn end(&self) -> Option<ast::Pat> {
|
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
2020-04-09 06:00:09 -05:00
|
|
|
.skip_while(|it| !ast::RangeSeparator::can_cast(it.kind()))
|
2020-04-03 14:12:09 -05:00
|
|
|
.filter_map(|it| it.into_node())
|
|
|
|
.find_map(ast::Pat::cast)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::TokenTree {
|
|
|
|
pub fn left_delimiter(&self) -> Option<ast::LeftDelimiter> {
|
2020-04-09 06:00:09 -05:00
|
|
|
self.syntax().first_child_or_token()?.into_token().and_then(ast::LeftDelimiter::cast)
|
2020-04-03 14:12:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn right_delimiter(&self) -> Option<ast::RightDelimiter> {
|
2020-04-09 06:00:09 -05:00
|
|
|
self.syntax().last_child_or_token()?.into_token().and_then(ast::RightDelimiter::cast)
|
2020-04-03 14:12:09 -05:00
|
|
|
}
|
|
|
|
}
|