rust/crates/ra_syntax/src/ast/extensions.rs

361 lines
9.5 KiB
Rust
Raw Normal View History

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.
2019-04-02 04:47:39 -05:00
use itertools::Itertools;
2019-05-15 07:35:47 -05:00
use crate::{SmolStr, SyntaxToken, ast::{self, AstNode, children, child_opt}, SyntaxKind::*, SyntaxElement, T};
2019-04-05 15:34:45 -05:00
use ra_parser::SyntaxKind;
2019-04-02 04:47:39 -05:00
impl ast::Name {
pub fn text(&self) -> &SmolStr {
let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
ident.text()
}
}
impl ast::NameRef {
pub fn text(&self) -> &SmolStr {
let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
ident.text()
}
}
impl ast::Attr {
pub fn is_inner(&self) -> bool {
let tt = match self.value() {
None => return false,
Some(tt) => tt,
};
let prev = match tt.syntax().prev_sibling() {
None => return false,
Some(prev) => prev,
};
2019-05-15 07:35:47 -05:00
prev.kind() == T![!]
2019-04-02 04:47:39 -05:00
}
pub fn as_atom(&self) -> Option<SmolStr> {
let tt = self.value()?;
let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
if attr.kind() == IDENT {
Some(attr.as_token()?.text().clone())
} else {
None
}
}
pub fn as_call(&self) -> Option<(SmolStr, &ast::TokenTree)> {
let tt = self.value()?;
let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
let args = ast::TokenTree::cast(args.as_node()?)?;
if attr.kind() == IDENT {
Some((attr.as_token()?.text().clone(), args))
} else {
None
}
}
pub fn as_named(&self) -> Option<SmolStr> {
let tt = self.value()?;
let attr = tt.syntax().children_with_tokens().nth(1)?;
if attr.kind() == IDENT {
Some(attr.as_token()?.text().clone())
} else {
None
}
}
2019-04-14 17:03:54 -05:00
pub fn as_key_value(&self) -> Option<(SmolStr, SmolStr)> {
let tt = self.value()?;
let tt_node = tt.syntax();
let attr = tt_node.children_with_tokens().nth(1)?;
if attr.kind() == IDENT {
let key = attr.as_token()?.text().clone();
let val_node = tt_node.children_with_tokens().find(|t| t.kind() == STRING)?;
let val = val_node.as_token()?.text().trim_start_matches("\"").trim_end_matches("\"");
Some((key, SmolStr::new(val)))
} else {
None
}
}
2019-04-02 04:47:39 -05:00
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PathSegmentKind<'a> {
Name(&'a ast::NameRef),
SelfKw,
SuperKw,
CrateKw,
}
impl ast::PathSegment {
pub fn parent_path(&self) -> &ast::Path {
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-04-02 04:47:39 -05:00
_ => return None,
}
};
Some(res)
}
pub fn has_colon_colon(&self) -> bool {
match self.syntax.first_child_or_token().map(|s| s.kind()) {
2019-05-15 07:35:47 -05:00
Some(T![::]) => true,
2019-04-02 04:47:39 -05:00
_ => false,
}
}
}
impl ast::Path {
pub fn parent_path(&self) -> Option<&ast::Path> {
self.syntax().parent().and_then(ast::Path::cast)
}
}
impl ast::Module {
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::UseTree {
pub fn has_star(&self) -> bool {
2019-05-15 07:35:47 -05:00
self.syntax().children_with_tokens().any(|it| it.kind() == T![*])
2019-04-02 04:47:39 -05:00
}
}
impl ast::UseTreeList {
pub fn parent_use_tree(&self) -> &ast::UseTree {
self.syntax()
.parent()
.and_then(ast::UseTree::cast)
.expect("UseTreeLists are always nested in UseTrees")
}
}
impl ast::ImplBlock {
pub fn target_type(&self) -> Option<&ast::TypeRef> {
match self.target() {
(Some(t), None) | (_, Some(t)) => Some(t),
_ => None,
}
}
pub fn target_trait(&self) -> Option<&ast::TypeRef> {
match self.target() {
(Some(t), Some(_)) => Some(t),
_ => None,
}
}
fn target(&self) -> (Option<&ast::TypeRef>, Option<&ast::TypeRef>) {
let mut types = children(self);
let first = types.next();
let second = types.next();
(first, second)
}
pub fn is_negative(&self) -> bool {
2019-05-15 07:35:47 -05:00
self.syntax().children_with_tokens().any(|t| t.kind() == T![!])
}
2019-04-02 04:47:39 -05:00
}
#[derive(Debug, Clone, PartialEq, Eq)]
2019-04-02 04:48:14 -05:00
pub enum StructKind<'a> {
2019-04-02 04:47:39 -05:00
Tuple(&'a ast::PosFieldDefList),
Named(&'a ast::NamedFieldDefList),
Unit,
}
2019-04-02 04:48:14 -05:00
impl StructKind<'_> {
fn from_node<N: AstNode>(node: &N) -> StructKind {
2019-04-02 04:47:39 -05:00
if let Some(nfdl) = child_opt::<_, ast::NamedFieldDefList>(node) {
2019-04-02 04:48:14 -05:00
StructKind::Named(nfdl)
2019-04-02 04:47:39 -05:00
} else if let Some(pfl) = child_opt::<_, ast::PosFieldDefList>(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 {
pub fn parent_enum(&self) -> &ast::EnumDef {
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
}
}
impl ast::FnDef {
pub fn semicolon_token(&self) -> Option<SyntaxToken<'_>> {
self.syntax()
.last_child_or_token()
.and_then(|it| it.as_token())
2019-05-15 07:35:47 -05:00
.filter(|it| it.kind() == T![;])
}
}
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 {
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
}
}
}
2019-04-05 15:34:45 -05:00
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FieldKind<'a> {
Name(&'a ast::NameRef),
Index(SyntaxToken<'a>),
}
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)
}
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
}
}
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 {
pub fn self_kw_token(&self) -> SyntaxToken {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.as_token())
2019-05-15 07:35:47 -05:00
.find(|it| it.kind() == T![self])
2019-04-02 04:47:39 -05:00
.expect("invalid tree: self param must have self")
}
2019-04-02 04:48:14 -05:00
pub fn kind(&self) -> SelfParamKind {
2019-05-15 07:35:47 -05:00
let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == T![&]);
2019-04-02 04:47:39 -05:00
if borrowed {
// check for a `mut` coming after the & -- `mut &self` != `&mut self`
if self
.syntax()
.children_with_tokens()
2019-05-15 07:35:47 -05:00
.skip_while(|n| n.kind() != T![&])
.any(|n| n.kind() == T![mut])
2019-04-02 04:47:39 -05:00
{
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
}
}
}
impl ast::LifetimeParam {
pub fn lifetime_token(&self) -> Option<SyntaxToken> {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.as_token())
.find(|it| it.kind() == LIFETIME)
}
}
impl ast::WherePred {
pub fn lifetime_token(&self) -> Option<SyntaxToken> {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.as_token())
.find(|it| it.kind() == LIFETIME)
}
}
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])
}
}