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.
|
2021-09-26 09:29:42 -05:00
|
|
|
//!
|
|
|
|
//! These methods should only do simple, shallow tasks related to the syntax of the node itself.
|
2019-04-02 05:02:23 -05:00
|
|
|
|
2021-05-06 00:07:06 -05:00
|
|
|
use std::{borrow::Cow, fmt, iter::successors};
|
2020-04-11 16:33:17 -05:00
|
|
|
|
2020-02-11 15:33:11 -06:00
|
|
|
use itertools::Itertools;
|
2020-08-12 10:06:49 -05:00
|
|
|
use parser::SyntaxKind;
|
2021-09-26 09:29:42 -05:00
|
|
|
use rowan::{GreenNodeData, GreenTokenData};
|
2020-02-11 15:33:11 -06:00
|
|
|
|
2019-05-20 17:04:20 -05:00
|
|
|
use crate::{
|
2021-10-02 07:32:23 -05:00
|
|
|
ast::{self, support, AstNode, AstToken, HasAttrs, HasGenericParams, HasName, SyntaxNode},
|
2021-05-06 00:07:06 -05:00
|
|
|
NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
|
2019-05-20 17:04:20 -05:00
|
|
|
};
|
2019-04-02 04:47:39 -05:00
|
|
|
|
2020-12-15 12:23:51 -06:00
|
|
|
impl ast::Lifetime {
|
2021-05-06 00:07:06 -05:00
|
|
|
pub fn text(&self) -> TokenText<'_> {
|
2020-12-15 12:23:51 -06:00
|
|
|
text_of_first_token(self.syntax())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 04:47:39 -05:00
|
|
|
impl ast::Name {
|
2021-05-06 00:07:06 -05:00
|
|
|
pub fn text(&self) -> TokenText<'_> {
|
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 {
|
2021-05-06 00:07:06 -05:00
|
|
|
pub fn text(&self) -> TokenText<'_> {
|
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-10 04:49:13 -05:00
|
|
|
self.text().parse().ok()
|
2019-09-26 13:04:47 -05:00
|
|
|
}
|
2019-07-18 11:23:05 -05:00
|
|
|
}
|
|
|
|
|
2021-05-06 00:07:06 -05:00
|
|
|
fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
|
|
|
|
fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
|
|
|
|
green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
match node.green() {
|
2021-05-06 00:07:06 -05:00
|
|
|
Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()),
|
|
|
|
Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()),
|
2021-05-06 00:07:06 -05:00
|
|
|
}
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
2021-09-27 05:54:24 -05:00
|
|
|
impl ast::HasModuleItem for ast::StmtList {}
|
2021-09-26 04:12:57 -05:00
|
|
|
|
2021-06-18 16:53:41 -05:00
|
|
|
impl ast::BlockExpr {
|
2021-09-26 04:12:57 -05:00
|
|
|
// FIXME: remove all these methods, they belong to ast::StmtList
|
|
|
|
pub fn statements(&self) -> impl Iterator<Item = ast::Stmt> {
|
|
|
|
self.stmt_list().into_iter().flat_map(|it| it.statements())
|
|
|
|
}
|
|
|
|
pub fn tail_expr(&self) -> Option<ast::Expr> {
|
|
|
|
self.stmt_list()?.tail_expr()
|
|
|
|
}
|
2021-06-26 18:11:57 -05:00
|
|
|
}
|
|
|
|
|
2021-03-27 00:44:54 -05:00
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
2020-12-15 11:43:19 -06:00
|
|
|
pub enum Macro {
|
|
|
|
MacroRules(ast::MacroRules),
|
|
|
|
MacroDef(ast::MacroDef),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ast::MacroRules> for Macro {
|
|
|
|
fn from(it: ast::MacroRules) -> Self {
|
|
|
|
Macro::MacroRules(it)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ast::MacroDef> for Macro {
|
|
|
|
fn from(it: ast::MacroDef) -> Self {
|
|
|
|
Macro::MacroDef(it)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AstNode for Macro {
|
|
|
|
fn can_cast(kind: SyntaxKind) -> bool {
|
2021-03-21 09:33:18 -05:00
|
|
|
matches!(kind, SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF)
|
2020-12-15 11:43:19 -06:00
|
|
|
}
|
|
|
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
|
|
|
let res = match syntax.kind() {
|
|
|
|
SyntaxKind::MACRO_RULES => Macro::MacroRules(ast::MacroRules { syntax }),
|
|
|
|
SyntaxKind::MACRO_DEF => Macro::MacroDef(ast::MacroDef { syntax }),
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
Some(res)
|
|
|
|
}
|
|
|
|
fn syntax(&self) -> &SyntaxNode {
|
|
|
|
match self {
|
|
|
|
Macro::MacroRules(it) => it.syntax(),
|
|
|
|
Macro::MacroDef(it) => it.syntax(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 05:54:24 -05:00
|
|
|
impl HasName for Macro {
|
2020-12-15 11:43:19 -06:00
|
|
|
fn name(&self) -> Option<ast::Name> {
|
|
|
|
match self {
|
|
|
|
Macro::MacroRules(mac) => mac.name(),
|
|
|
|
Macro::MacroDef(mac) => mac.name(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 05:54:24 -05:00
|
|
|
impl HasAttrs for Macro {}
|
2020-12-15 11:43:19 -06:00
|
|
|
|
2022-01-06 05:30:16 -06:00
|
|
|
impl From<ast::AssocItem> for ast::Item {
|
|
|
|
fn from(assoc: ast::AssocItem) -> Self {
|
|
|
|
match assoc {
|
|
|
|
ast::AssocItem::Const(it) => ast::Item::Const(it),
|
|
|
|
ast::AssocItem::Fn(it) => ast::Item::Fn(it),
|
|
|
|
ast::AssocItem::MacroCall(it) => ast::Item::MacroCall(it),
|
|
|
|
ast::AssocItem::TypeAlias(it) => ast::Item::TypeAlias(it),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 08:44:52 -06:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub enum AttrKind {
|
|
|
|
Inner,
|
|
|
|
Outer,
|
|
|
|
}
|
|
|
|
|
2021-04-19 09:11:49 -05:00
|
|
|
impl AttrKind {
|
2021-08-03 22:57:31 -05:00
|
|
|
/// Returns `true` if the attr_kind is [`Inner`](Self::Inner).
|
2021-04-19 09:11:49 -05:00
|
|
|
pub fn is_inner(&self) -> bool {
|
|
|
|
matches!(self, Self::Inner)
|
|
|
|
}
|
|
|
|
|
2021-08-03 22:57:31 -05:00
|
|
|
/// Returns `true` if the attr_kind is [`Outer`](Self::Outer).
|
2021-04-19 09:11:49 -05:00
|
|
|
pub fn is_outer(&self) -> bool {
|
|
|
|
matches!(self, Self::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> {
|
2021-06-11 11:12:51 -05:00
|
|
|
let meta = self.meta()?;
|
|
|
|
if meta.eq_token().is_some() || meta.token_tree().is_some() {
|
2020-07-30 13:16:04 -05:00
|
|
|
return None;
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
2020-07-30 13:16:04 -05:00
|
|
|
self.simple_name()
|
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)> {
|
2021-06-11 11:12:51 -05:00
|
|
|
let tt = self.meta()?.token_tree()?;
|
2020-07-30 13:16:04 -05:00
|
|
|
Some((self.simple_name()?, tt))
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
2019-09-29 16:15:03 -05:00
|
|
|
pub fn simple_name(&self) -> Option<SmolStr> {
|
2021-06-11 11:12:51 -05:00
|
|
|
let path = self.meta()?.path()?;
|
2019-09-29 16:15:03 -05:00
|
|
|
match (path.segment(), path.qualifier()) {
|
2021-01-19 16:56:11 -06:00
|
|
|
(Some(segment), None) => Some(segment.syntax().first_token()?.text().into()),
|
2019-09-29 16:15:03 -05:00
|
|
|
_ => 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) {
|
2021-01-10 09:40:52 -06:00
|
|
|
(Some(T![#]), Some(T![!])) => AttrKind::Inner,
|
2020-02-12 08:44:52 -06:00
|
|
|
_ => AttrKind::Outer,
|
|
|
|
}
|
2020-02-12 08:21:55 -06:00
|
|
|
}
|
2021-06-11 11:12:51 -05:00
|
|
|
|
|
|
|
pub fn path(&self) -> Option<ast::Path> {
|
|
|
|
self.meta()?.path()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expr(&self) -> Option<ast::Expr> {
|
|
|
|
self.meta()?.expr()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn token_tree(&self) -> Option<ast::TokenTree> {
|
|
|
|
self.meta()?.token_tree()
|
|
|
|
}
|
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),
|
2020-07-31 05:06:38 -05:00
|
|
|
Type { type_ref: Option<ast::Type>, 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")
|
|
|
|
}
|
|
|
|
|
2021-01-15 11:57:32 -06:00
|
|
|
pub fn crate_token(&self) -> Option<SyntaxToken> {
|
|
|
|
self.name_ref().and_then(|it| it.crate_token())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn self_token(&self) -> Option<SyntaxToken> {
|
|
|
|
self.name_ref().and_then(|it| it.self_token())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn super_token(&self) -> Option<SyntaxToken> {
|
|
|
|
self.name_ref().and_then(|it| it.super_token())
|
|
|
|
}
|
|
|
|
|
2019-04-02 04:47:39 -05:00
|
|
|
pub fn kind(&self) -> Option<PathSegmentKind> {
|
|
|
|
let res = if let Some(name_ref) = self.name_ref() {
|
2021-01-15 11:57:32 -06:00
|
|
|
match name_ref.syntax().first_token().map(|it| it.kind()) {
|
|
|
|
Some(T![self]) => PathSegmentKind::SelfKw,
|
|
|
|
Some(T![super]) => PathSegmentKind::SuperKw,
|
|
|
|
Some(T![crate]) => PathSegmentKind::CrateKw,
|
|
|
|
_ => PathSegmentKind::Name(name_ref),
|
|
|
|
}
|
2019-04-02 04:47:39 -05:00
|
|
|
} else {
|
|
|
|
match self.syntax().first_child_or_token()?.kind() {
|
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 =
|
2020-07-31 05:06:38 -05:00
|
|
|
self.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
|
|
|
|
let type_ref = type_refs.next().and_then(ast::Type::cast);
|
2019-08-05 15:42:38 -05:00
|
|
|
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)
|
|
|
|
}
|
2021-01-15 14:07:38 -06:00
|
|
|
|
|
|
|
pub fn as_single_segment(&self) -> Option<ast::PathSegment> {
|
|
|
|
match self.qualifier() {
|
|
|
|
Some(_) => None,
|
|
|
|
None => self.segment(),
|
|
|
|
}
|
|
|
|
}
|
2021-04-24 06:31:16 -05:00
|
|
|
|
2021-05-27 16:28:14 -05:00
|
|
|
pub fn as_single_name_ref(&self) -> Option<ast::NameRef> {
|
|
|
|
match self.qualifier() {
|
|
|
|
Some(_) => None,
|
|
|
|
None => self.segment()?.name_ref(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-24 06:31:16 -05:00
|
|
|
pub fn first_qualifier_or_self(&self) -> ast::Path {
|
|
|
|
successors(Some(self.clone()), ast::Path::qualifier).last().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn first_segment(&self) -> Option<ast::PathSegment> {
|
|
|
|
self.first_qualifier_or_self().segment()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
|
|
|
|
successors(self.first_segment(), |p| {
|
|
|
|
p.parent_path().parent_path().and_then(|p| p.segment())
|
|
|
|
})
|
|
|
|
}
|
2021-06-08 15:14:30 -05:00
|
|
|
|
|
|
|
pub fn qualifiers(&self) -> impl Iterator<Item = ast::Path> + Clone {
|
|
|
|
successors(self.qualifier(), |p| p.qualifier())
|
|
|
|
}
|
2021-06-30 14:29:40 -05:00
|
|
|
|
|
|
|
pub fn top_path(&self) -> ast::Path {
|
|
|
|
let mut this = self.clone();
|
|
|
|
while let Some(path) = this.parent_path() {
|
|
|
|
this = path;
|
|
|
|
}
|
|
|
|
this
|
|
|
|
}
|
2021-04-24 06:31:16 -05:00
|
|
|
}
|
2021-06-18 16:11:56 -05:00
|
|
|
|
|
|
|
impl ast::Use {
|
|
|
|
pub fn is_simple_glob(&self) -> bool {
|
2021-10-03 07:45:08 -05:00
|
|
|
self.use_tree().map_or(false, |use_tree| {
|
|
|
|
use_tree.use_tree_list().is_none() && use_tree.star_token().is_some()
|
|
|
|
})
|
2021-06-18 16:11:56 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-24 06:31:16 -05:00
|
|
|
impl ast::UseTree {
|
|
|
|
pub fn is_simple_path(&self) -> bool {
|
|
|
|
self.use_tree_list().is_none() && self.star_token().is_none()
|
|
|
|
}
|
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-12-29 23:46:34 -06:00
|
|
|
|
|
|
|
pub fn has_inner_comment(&self) -> bool {
|
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
2020-12-29 23:56:00 -06:00
|
|
|
.filter_map(|it| it.into_token())
|
|
|
|
.find_map(ast::Comment::cast)
|
|
|
|
.is_some()
|
2020-12-29 23:46:34 -06:00
|
|
|
}
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
2020-07-30 11:28:28 -05:00
|
|
|
impl ast::Impl {
|
2020-07-31 13:23:52 -05:00
|
|
|
pub fn self_ty(&self) -> Option<ast::Type> {
|
2019-04-02 04:47:39 -05:00
|
|
|
match self.target() {
|
|
|
|
(Some(t), None) | (_, Some(t)) => Some(t),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:52 -05:00
|
|
|
pub fn trait_(&self) -> Option<ast::Type> {
|
2019-04-02 04:47:39 -05:00
|
|
|
match self.target() {
|
|
|
|
(Some(t), Some(_)) => Some(t),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-31 05:06:38 -05:00
|
|
|
fn target(&self) -> (Option<ast::Type>, Option<ast::Type>) {
|
2020-04-09 15:22:58 -05:00
|
|
|
let mut types = support::children(self.syntax());
|
2019-04-02 04:47:39 -05:00
|
|
|
let first = types.next();
|
|
|
|
let second = types.next();
|
|
|
|
(first, second)
|
|
|
|
}
|
2021-06-15 14:44:07 -05:00
|
|
|
|
|
|
|
pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> {
|
|
|
|
let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?;
|
|
|
|
if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() {
|
|
|
|
Some(this)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2019-04-02 04:47:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2019-07-18 11:23:05 -05:00
|
|
|
pub enum StructKind {
|
2020-07-30 09:49:13 -05:00
|
|
|
Record(ast::RecordFieldList),
|
|
|
|
Tuple(ast::TupleFieldList),
|
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 {
|
2020-07-30 09:49:13 -05:00
|
|
|
if let Some(nfdl) = support::child::<ast::RecordFieldList>(node.syntax()) {
|
2019-11-22 12:52:06 -06:00
|
|
|
StructKind::Record(nfdl)
|
2020-07-30 09:49:13 -05:00
|
|
|
} else if let Some(pfl) = support::child::<ast::TupleFieldList>(node.syntax()) {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-30 10:50:40 -05:00
|
|
|
impl ast::Struct {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-30 09:21:30 -05:00
|
|
|
impl ast::RecordExprField {
|
|
|
|
pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
|
2021-02-07 11:38:12 -06:00
|
|
|
let candidate = Self::for_name_ref(field_name)?;
|
2020-04-11 09:42:24 -05:00
|
|
|
if candidate.field_name().as_ref() == Some(field_name) {
|
|
|
|
Some(candidate)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-07 11:38:12 -06:00
|
|
|
pub fn for_name_ref(name_ref: &ast::NameRef) -> Option<ast::RecordExprField> {
|
|
|
|
let syn = name_ref.syntax();
|
|
|
|
syn.parent()
|
|
|
|
.and_then(ast::RecordExprField::cast)
|
|
|
|
.or_else(|| syn.ancestors().nth(4).and_then(ast::RecordExprField::cast))
|
|
|
|
}
|
|
|
|
|
2020-04-11 09:42:24 -05:00
|
|
|
/// Deals with field init shorthand
|
|
|
|
pub fn field_name(&self) -> Option<ast::NameRef> {
|
|
|
|
if let Some(name_ref) = self.name_ref() {
|
|
|
|
return Some(name_ref);
|
|
|
|
}
|
2021-09-26 09:29:42 -05:00
|
|
|
if let ast::Expr::PathExpr(expr) = self.expr()? {
|
|
|
|
let path = expr.path()?;
|
|
|
|
let segment = path.segment()?;
|
|
|
|
let name_ref = segment.name_ref()?;
|
|
|
|
if path.qualifier().is_none() {
|
|
|
|
return Some(name_ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
2020-04-11 09:42:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-17 08:00:44 -06:00
|
|
|
#[derive(Debug, Clone)]
|
2021-02-16 12:27:08 -06:00
|
|
|
pub enum NameLike {
|
|
|
|
NameRef(ast::NameRef),
|
|
|
|
Name(ast::Name),
|
|
|
|
Lifetime(ast::Lifetime),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl NameLike {
|
|
|
|
pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
|
|
|
|
match self {
|
|
|
|
NameLike::NameRef(name_ref) => Some(name_ref),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::AstNode for NameLike {
|
|
|
|
fn can_cast(kind: SyntaxKind) -> bool {
|
|
|
|
matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME)
|
|
|
|
}
|
|
|
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
|
|
|
let res = match syntax.kind() {
|
|
|
|
SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }),
|
|
|
|
SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }),
|
|
|
|
SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }),
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
Some(res)
|
|
|
|
}
|
|
|
|
fn syntax(&self) -> &SyntaxNode {
|
|
|
|
match self {
|
|
|
|
NameLike::NameRef(it) => it.syntax(),
|
|
|
|
NameLike::Name(it) => it.syntax(),
|
|
|
|
NameLike::Lifetime(it) => it.syntax(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-06 05:55:33 -06:00
|
|
|
const _: () = {
|
|
|
|
use ast::{Lifetime, Name, NameRef};
|
2021-02-16 12:27:08 -06:00
|
|
|
stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
|
2022-01-06 05:55:33 -06:00
|
|
|
};
|
2021-02-16 12:27:08 -06:00
|
|
|
|
2021-02-17 08:00:44 -06:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub enum NameOrNameRef {
|
|
|
|
Name(ast::Name),
|
|
|
|
NameRef(ast::NameRef),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for NameOrNameRef {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
|
|
|
|
NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-20 17:22:09 -05:00
|
|
|
impl NameOrNameRef {
|
2021-05-06 00:07:06 -05:00
|
|
|
pub fn text(&self) -> TokenText<'_> {
|
2021-03-20 17:22:09 -05:00
|
|
|
match self {
|
|
|
|
NameOrNameRef::Name(name) => name.text(),
|
|
|
|
NameOrNameRef::NameRef(name_ref) => name_ref.text(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-31 12:54:16 -05:00
|
|
|
impl ast::RecordPatField {
|
2021-02-07 11:38:12 -06:00
|
|
|
pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
|
|
|
|
let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
|
|
|
|
match candidate.field_name()? {
|
2021-02-17 08:00:44 -06:00
|
|
|
NameOrNameRef::NameRef(name_ref) if name_ref == *field_name => Some(candidate),
|
2021-02-07 11:38:12 -06:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
|
|
|
|
let candidate =
|
2021-02-13 16:35:04 -06:00
|
|
|
field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
|
2021-02-07 11:38:12 -06:00
|
|
|
match candidate.field_name()? {
|
2021-02-17 08:00:44 -06:00
|
|
|
NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
|
2021-02-07 11:38:12 -06:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-11 16:33:17 -05:00
|
|
|
/// Deals with field init shorthand
|
2021-02-17 08:00:44 -06:00
|
|
|
pub fn field_name(&self) -> Option<NameOrNameRef> {
|
2020-04-11 16:33:17 -05:00
|
|
|
if let Some(name_ref) = self.name_ref() {
|
2021-02-17 08:00:44 -06:00
|
|
|
return Some(NameOrNameRef::NameRef(name_ref));
|
2020-04-11 16:33:17 -05:00
|
|
|
}
|
2021-02-20 04:36:17 -06:00
|
|
|
match self.pat() {
|
|
|
|
Some(ast::Pat::IdentPat(pat)) => {
|
|
|
|
let name = pat.name()?;
|
|
|
|
Some(NameOrNameRef::Name(name))
|
|
|
|
}
|
|
|
|
Some(ast::Pat::BoxPat(pat)) => match pat.pat() {
|
|
|
|
Some(ast::Pat::IdentPat(pat)) => {
|
|
|
|
let name = pat.name()?;
|
|
|
|
Some(NameOrNameRef::Name(name))
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
},
|
|
|
|
_ => None,
|
2020-04-11 16:33:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-30 10:56:53 -05:00
|
|
|
impl ast::Variant {
|
2020-07-30 10:52:53 -05:00
|
|
|
pub fn parent_enum(&self) -> ast::Enum {
|
2019-04-02 04:47:39 -05:00
|
|
|
self.syntax()
|
|
|
|
.parent()
|
|
|
|
.and_then(|it| it.parent())
|
2020-07-30 10:52:53 -05:00
|
|
|
.and_then(ast::Enum::cast)
|
2019-04-02 04:47:39 -05:00
|
|
|
.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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-04 19:54:06 -05:00
|
|
|
impl ast::Item {
|
|
|
|
pub fn generic_param_list(&self) -> Option<ast::GenericParamList> {
|
2021-09-27 05:54:24 -05:00
|
|
|
ast::AnyHasGenericParams::cast(self.syntax().clone())?.generic_param_list()
|
2021-08-04 19:54:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-07 15:16:15 -05:00
|
|
|
impl ast::Condition {
|
|
|
|
pub fn is_pattern_cond(&self) -> bool {
|
|
|
|
self.let_token().is_some()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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> {
|
2021-10-03 07:53:01 -05:00
|
|
|
match self.name_ref() {
|
|
|
|
Some(nr) => Some(FieldKind::Name(nr)),
|
|
|
|
None => self.index_token().map(FieldKind::Index),
|
2019-04-05 15:34:45 -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 {
|
2020-07-31 14:58:36 -05:00
|
|
|
let mut args = self.pats().peekable();
|
2020-02-11 15:33:11 -06:00
|
|
|
let prefix = args
|
|
|
|
.peeking_take_while(|p| match p {
|
2020-07-31 14:45:29 -05:00
|
|
|
ast::Pat::RestPat(_) => false,
|
2021-03-21 09:33:18 -05:00
|
|
|
ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
|
2020-02-11 15:33:11 -06:00
|
|
|
ast::Pat::RefPat(rp) => match rp.pat() {
|
2020-07-31 14:45:29 -05:00
|
|
|
Some(ast::Pat::RestPat(_)) => false,
|
2021-03-21 09:33:18 -05:00
|
|
|
Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
|
2020-02-11 15:33:11 -06:00
|
|
|
_ => true,
|
|
|
|
},
|
|
|
|
_ => true,
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let slice = args.next();
|
|
|
|
let suffix = args.collect();
|
|
|
|
|
|
|
|
SlicePatComponents { prefix, slice, suffix }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 13:05:00 -05:00
|
|
|
impl ast::IdentPat {
|
|
|
|
pub fn is_simple_ident(&self) -> bool {
|
|
|
|
self.at_token().is_none()
|
|
|
|
&& self.mut_token().is_none()
|
|
|
|
&& self.ref_token().is_none()
|
|
|
|
&& self.pat().is_none()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-10 10:47:49 -05:00
|
|
|
if self.mut_token().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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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-12-15 12:23:51 -06: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 {
|
2020-04-09 15:22:58 -05:00
|
|
|
if let Some(path_type) = support::children(self.syntax()).next() {
|
2019-08-22 10:43:09 -05:00
|
|
|
TypeBoundKind::PathType(path_type)
|
2020-04-09 15:22:58 -05:00
|
|
|
} else if let Some(for_type) = support::children(self.syntax()).next() {
|
2019-08-22 10:43:09 -05:00
|
|
|
TypeBoundKind::ForType(for_type)
|
2020-12-15 12:23:51 -06:00
|
|
|
} else if let Some(lifetime) = self.lifetime() {
|
2019-08-22 10:43:09 -05:00
|
|
|
TypeBoundKind::Lifetime(lifetime)
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
2019-08-22 07:28:08 -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 {
|
2021-01-15 14:07:38 -06:00
|
|
|
match self.path() {
|
|
|
|
Some(path) => {
|
|
|
|
if let Some(segment) =
|
|
|
|
path.as_single_segment().filter(|it| it.coloncolon_token().is_none())
|
|
|
|
{
|
|
|
|
if segment.crate_token().is_some() {
|
|
|
|
return VisibilityKind::PubCrate;
|
|
|
|
} else if segment.super_token().is_some() {
|
|
|
|
return VisibilityKind::PubSuper;
|
|
|
|
} else if segment.self_token().is_some() {
|
|
|
|
return VisibilityKind::PubSelf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VisibilityKind::In(path)
|
|
|
|
}
|
|
|
|
None => VisibilityKind::Pub,
|
2019-12-24 13:32:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-22 02:00:44 -05:00
|
|
|
|
2020-04-03 14:12:09 -05:00
|
|
|
impl ast::LifetimeParam {
|
2020-04-10 08:53:09 -05:00
|
|
|
pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
|
2020-04-03 14:12:09 -05:00
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
|
|
|
.filter_map(|it| it.into_token())
|
|
|
|
.skip_while(|x| x.kind() != T![:])
|
2020-12-15 12:23:51 -06:00
|
|
|
.filter(|it| it.kind() == T![lifetime_ident])
|
2020-04-03 14:12:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-17 05:09:28 -05:00
|
|
|
impl ast::Module {
|
|
|
|
/// Returns the parent ast::Module, this is different than the semantic parent in that this only
|
|
|
|
/// considers parent declarations in the AST
|
|
|
|
pub fn parent(&self) -> Option<ast::Module> {
|
|
|
|
self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 14:12:09 -05:00
|
|
|
impl ast::RangePat {
|
|
|
|
pub fn start(&self) -> Option<ast::Pat> {
|
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
2020-04-10 04:49:13 -05:00
|
|
|
.take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
|
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-10 04:49:13 -05:00
|
|
|
.skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
|
2020-04-03 14:12:09 -05:00
|
|
|
.filter_map(|it| it.into_node())
|
|
|
|
.find_map(ast::Pat::cast)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::TokenTree {
|
2020-04-10 03:27:23 -05:00
|
|
|
pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
|
2020-06-27 20:02:03 -05:00
|
|
|
self.syntax()
|
|
|
|
.first_child_or_token()?
|
|
|
|
.into_token()
|
|
|
|
.filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
|
2020-04-10 03:27:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
|
2020-06-27 20:02:03 -05:00
|
|
|
self.syntax()
|
|
|
|
.last_child_or_token()?
|
|
|
|
.into_token()
|
|
|
|
.filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
|
2020-04-03 14:12:09 -05:00
|
|
|
}
|
2021-09-23 08:37:52 -05:00
|
|
|
|
|
|
|
pub fn parent_meta(&self) -> Option<ast::Meta> {
|
|
|
|
self.syntax().parent().and_then(ast::Meta::cast)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::Meta {
|
|
|
|
pub fn parent_attr(&self) -> Option<ast::Attr> {
|
|
|
|
self.syntax().parent().and_then(ast::Attr::cast)
|
|
|
|
}
|
2020-04-03 14:12:09 -05:00
|
|
|
}
|
2020-07-29 08:45:23 -05:00
|
|
|
|
2020-07-30 11:52:02 -05:00
|
|
|
impl ast::GenericParamList {
|
|
|
|
pub fn lifetime_params(&self) -> impl Iterator<Item = ast::LifetimeParam> {
|
|
|
|
self.generic_params().filter_map(|param| match param {
|
|
|
|
ast::GenericParam::LifetimeParam(it) => Some(it),
|
|
|
|
ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
pub fn type_params(&self) -> impl Iterator<Item = ast::TypeParam> {
|
|
|
|
self.generic_params().filter_map(|param| match param {
|
|
|
|
ast::GenericParam::TypeParam(it) => Some(it),
|
|
|
|
ast::GenericParam::LifetimeParam(_) | ast::GenericParam::ConstParam(_) => None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
pub fn const_params(&self) -> impl Iterator<Item = ast::ConstParam> {
|
|
|
|
self.generic_params().filter_map(|param| match param {
|
|
|
|
ast::GenericParam::ConstParam(it) => Some(it),
|
|
|
|
ast::GenericParam::TypeParam(_) | ast::GenericParam::LifetimeParam(_) => None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-30 09:37:32 -05:00
|
|
|
impl ast::HasLoopBody for ast::ForExpr {
|
|
|
|
fn loop_body(&self) -> Option<ast::BlockExpr> {
|
|
|
|
let mut exprs = support::children(self.syntax());
|
|
|
|
let first = exprs.next();
|
|
|
|
let second = exprs.next();
|
|
|
|
second.or(first)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-07 05:37:58 -06:00
|
|
|
impl ast::HasAttrs for ast::AnyHasDocComments {}
|
2022-01-07 07:14:33 -06:00
|
|
|
|
|
|
|
impl From<ast::Adt> for ast::Item {
|
|
|
|
fn from(it: ast::Adt) -> Self {
|
|
|
|
match it {
|
|
|
|
ast::Adt::Enum(it) => ast::Item::Enum(it),
|
|
|
|
ast::Adt::Struct(it) => ast::Item::Struct(it),
|
|
|
|
ast::Adt::Union(it) => ast::Item::Union(it),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|