mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-22 12:43:36 +00:00
Merge #1088
1088: add minimal comments r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
b0d2447193
@ -11,8 +11,8 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) ->
|
||||
let expr = cond.expr()?;
|
||||
let then_block = if_expr.then_branch()?;
|
||||
let else_block = match if_expr.else_branch()? {
|
||||
ast::ElseBranchFlavor::Block(it) => it,
|
||||
ast::ElseBranchFlavor::IfExpr(_) => return None,
|
||||
ast::ElseBranch::Block(it) => it,
|
||||
ast::ElseBranch::IfExpr(_) => return None,
|
||||
};
|
||||
|
||||
ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| {
|
||||
|
@ -6,7 +6,7 @@ use std::sync::Arc;
|
||||
use ra_arena::{RawId, Arena, impl_arena_id};
|
||||
use ra_syntax::{
|
||||
TreeArc,
|
||||
ast::{self, NameOwner, StructFlavor, TypeAscriptionOwner}
|
||||
ast::{self, NameOwner, StructKind, TypeAscriptionOwner}
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -47,7 +47,7 @@ pub struct StructData {
|
||||
impl StructData {
|
||||
fn new(struct_def: &ast::StructDef) -> StructData {
|
||||
let name = struct_def.name().map(|n| n.as_name());
|
||||
let variant_data = VariantData::new(struct_def.flavor());
|
||||
let variant_data = VariantData::new(struct_def.kind());
|
||||
let variant_data = Arc::new(variant_data);
|
||||
StructData { name, variant_data }
|
||||
}
|
||||
@ -94,7 +94,7 @@ impl EnumData {
|
||||
let variants = variants(&*enum_def)
|
||||
.map(|var| EnumVariantData {
|
||||
name: var.name().map(|it| it.as_name()),
|
||||
variant_data: Arc::new(VariantData::new(var.flavor())),
|
||||
variant_data: Arc::new(VariantData::new(var.kind())),
|
||||
})
|
||||
.collect();
|
||||
Arc::new(EnumData { name, variants })
|
||||
@ -143,9 +143,9 @@ impl VariantData {
|
||||
}
|
||||
|
||||
impl VariantData {
|
||||
fn new(flavor: StructFlavor) -> Self {
|
||||
fn new(flavor: StructKind) -> Self {
|
||||
let inner = match flavor {
|
||||
ast::StructFlavor::Tuple(fl) => {
|
||||
ast::StructKind::Tuple(fl) => {
|
||||
let fields = fl
|
||||
.fields()
|
||||
.enumerate()
|
||||
@ -156,7 +156,7 @@ impl VariantData {
|
||||
.collect();
|
||||
VariantDataInner::Tuple(fields)
|
||||
}
|
||||
ast::StructFlavor::Named(fl) => {
|
||||
ast::StructKind::Named(fl) => {
|
||||
let fields = fl
|
||||
.fields()
|
||||
.map(|fd| StructFieldData {
|
||||
@ -166,7 +166,7 @@ impl VariantData {
|
||||
.collect();
|
||||
VariantDataInner::Struct(fields)
|
||||
}
|
||||
ast::StructFlavor::Unit => VariantDataInner::Unit,
|
||||
ast::StructKind::Unit => VariantDataInner::Unit,
|
||||
};
|
||||
VariantData(inner)
|
||||
}
|
||||
@ -200,27 +200,27 @@ impl StructField {
|
||||
let fields = var_data.fields().unwrap();
|
||||
let ss;
|
||||
let es;
|
||||
let (file_id, struct_flavor) = match self.parent {
|
||||
let (file_id, struct_kind) = match self.parent {
|
||||
VariantDef::Struct(s) => {
|
||||
let (file_id, source) = s.source(db);
|
||||
ss = source;
|
||||
(file_id, ss.flavor())
|
||||
(file_id, ss.kind())
|
||||
}
|
||||
VariantDef::EnumVariant(e) => {
|
||||
let (file_id, source) = e.source(db);
|
||||
es = source;
|
||||
(file_id, es.flavor())
|
||||
(file_id, es.kind())
|
||||
}
|
||||
};
|
||||
|
||||
let field_sources = match struct_flavor {
|
||||
ast::StructFlavor::Tuple(fl) => {
|
||||
let field_sources = match struct_kind {
|
||||
ast::StructKind::Tuple(fl) => {
|
||||
fl.fields().map(|it| FieldSource::Pos(it.to_owned())).collect()
|
||||
}
|
||||
ast::StructFlavor::Named(fl) => {
|
||||
ast::StructKind::Named(fl) => {
|
||||
fl.fields().map(|it| FieldSource::Named(it.to_owned())).collect()
|
||||
}
|
||||
ast::StructFlavor::Unit => Vec::new(),
|
||||
ast::StructKind::Unit => Vec::new(),
|
||||
};
|
||||
let field = field_sources
|
||||
.into_iter()
|
||||
|
@ -20,12 +20,12 @@ impl FnSignature {
|
||||
TypeRef::from_ast(type_ref)
|
||||
} else {
|
||||
let self_type = TypeRef::Path(Name::self_type().into());
|
||||
match self_param.flavor() {
|
||||
ast::SelfParamFlavor::Owned => self_type,
|
||||
ast::SelfParamFlavor::Ref => {
|
||||
match self_param.kind() {
|
||||
ast::SelfParamKind::Owned => self_type,
|
||||
ast::SelfParamKind::Ref => {
|
||||
TypeRef::Reference(Box::new(self_type), Mutability::Shared)
|
||||
}
|
||||
ast::SelfParamFlavor::MutRef => {
|
||||
ast::SelfParamKind::MutRef => {
|
||||
TypeRef::Reference(Box::new(self_type), Mutability::Mut)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
|
||||
use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
|
||||
use ra_syntax::{
|
||||
SyntaxNodePtr, AstPtr, AstNode,
|
||||
ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor, TypeAscriptionOwner}
|
||||
ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind, TypeAscriptionOwner}
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -516,8 +516,8 @@ impl ExprCollector {
|
||||
let else_branch = e
|
||||
.else_branch()
|
||||
.map(|b| match b {
|
||||
ast::ElseBranchFlavor::Block(it) => self.collect_block(it),
|
||||
ast::ElseBranchFlavor::IfExpr(elif) => {
|
||||
ast::ElseBranch::Block(it) => self.collect_block(it),
|
||||
ast::ElseBranch::IfExpr(elif) => {
|
||||
let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap();
|
||||
self.collect_expr(expr)
|
||||
}
|
||||
@ -533,8 +533,8 @@ impl ExprCollector {
|
||||
let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
|
||||
let then_branch = self.collect_block_opt(e.then_branch());
|
||||
let else_branch = e.else_branch().map(|b| match b {
|
||||
ast::ElseBranchFlavor::Block(it) => self.collect_block(it),
|
||||
ast::ElseBranchFlavor::IfExpr(elif) => {
|
||||
ast::ElseBranch::Block(it) => self.collect_block(it),
|
||||
ast::ElseBranch::IfExpr(elif) => {
|
||||
let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap();
|
||||
self.collect_expr(expr)
|
||||
}
|
||||
@ -726,8 +726,8 @@ impl ExprCollector {
|
||||
self.alloc_expr(Expr::Array { exprs }, syntax_ptr)
|
||||
}
|
||||
ast::ExprKind::Literal(e) => {
|
||||
let lit = match e.flavor() {
|
||||
LiteralFlavor::IntNumber { suffix } => {
|
||||
let lit = match e.kind() {
|
||||
LiteralKind::IntNumber { suffix } => {
|
||||
let known_name = suffix
|
||||
.and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
|
||||
|
||||
@ -736,7 +736,7 @@ impl ExprCollector {
|
||||
known_name.unwrap_or(UncertainIntTy::Unknown),
|
||||
)
|
||||
}
|
||||
LiteralFlavor::FloatNumber { suffix } => {
|
||||
LiteralKind::FloatNumber { suffix } => {
|
||||
let known_name = suffix
|
||||
.and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known));
|
||||
|
||||
@ -745,13 +745,13 @@ impl ExprCollector {
|
||||
known_name.unwrap_or(UncertainFloatTy::Unknown),
|
||||
)
|
||||
}
|
||||
LiteralFlavor::ByteString => Literal::ByteString(Default::default()),
|
||||
LiteralFlavor::String => Literal::String(Default::default()),
|
||||
LiteralFlavor::Byte => {
|
||||
LiteralKind::ByteString => Literal::ByteString(Default::default()),
|
||||
LiteralKind::String => Literal::String(Default::default()),
|
||||
LiteralKind::Byte => {
|
||||
Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8()))
|
||||
}
|
||||
LiteralFlavor::Bool => Literal::Bool(Default::default()),
|
||||
LiteralFlavor::Char => Literal::Char(Default::default()),
|
||||
LiteralKind::Bool => Literal::Bool(Default::default()),
|
||||
LiteralKind::Char => Literal::Char(Default::default()),
|
||||
};
|
||||
self.alloc_expr(Expr::Literal(lit), syntax_ptr)
|
||||
}
|
||||
|
@ -1,22 +1,24 @@
|
||||
//! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s
|
||||
|
||||
mod generated;
|
||||
mod traits;
|
||||
mod tokens;
|
||||
mod extensions;
|
||||
mod expr_extensions;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement},
|
||||
syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken},
|
||||
SmolStr,
|
||||
SyntaxKind::*,
|
||||
};
|
||||
|
||||
pub use self::{
|
||||
generated::*,
|
||||
traits::*,
|
||||
tokens::*,
|
||||
extensions::{PathSegmentKind, StructKind, SelfParamKind},
|
||||
expr_extensions::{ElseBranch, PrefixOp, BinOp, LiteralKind},
|
||||
};
|
||||
|
||||
/// The main trait to go from untyped `SyntaxNode` to a typed ast. The
|
||||
@ -32,6 +34,18 @@ pub trait AstNode:
|
||||
fn syntax(&self) -> &SyntaxNode;
|
||||
}
|
||||
|
||||
/// Like `AstNode`, but wraps tokens rather than interior nodes.
|
||||
pub trait AstToken<'a> {
|
||||
fn cast(token: SyntaxToken<'a>) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
fn syntax(&self) -> SyntaxToken<'a>;
|
||||
fn text(&self) -> &'a SmolStr {
|
||||
self.syntax().text()
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over `SyntaxNode` children of a particular AST type.
|
||||
#[derive(Debug)]
|
||||
pub struct AstChildren<'a, N> {
|
||||
inner: SyntaxNodeChildren<'a>,
|
||||
@ -51,215 +65,6 @@ impl<'a, N: AstNode + 'a> Iterator for AstChildren<'a, N> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AstToken<'a> {
|
||||
fn cast(token: SyntaxToken<'a>) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
fn syntax(&self) -> SyntaxToken<'a>;
|
||||
fn text(&self) -> &'a SmolStr {
|
||||
self.syntax().text()
|
||||
}
|
||||
}
|
||||
|
||||
impl 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,
|
||||
};
|
||||
|
||||
prev.kind() == EXCL
|
||||
}
|
||||
|
||||
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, &TokenTree)> {
|
||||
let tt = self.value()?;
|
||||
let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
|
||||
let args = 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Name {
|
||||
pub fn text(&self) -> &SmolStr {
|
||||
let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
|
||||
ident.text()
|
||||
}
|
||||
}
|
||||
|
||||
impl NameRef {
|
||||
pub fn text(&self) -> &SmolStr {
|
||||
let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
|
||||
ident.text()
|
||||
}
|
||||
}
|
||||
|
||||
impl ImplBlock {
|
||||
pub fn target_type(&self) -> Option<&TypeRef> {
|
||||
match self.target() {
|
||||
(Some(t), None) | (_, Some(t)) => Some(t),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn target_trait(&self) -> Option<&TypeRef> {
|
||||
match self.target() {
|
||||
(Some(t), Some(_)) => Some(t),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn target(&self) -> (Option<&TypeRef>, Option<&TypeRef>) {
|
||||
let mut types = children(self);
|
||||
let first = types.next();
|
||||
let second = types.next();
|
||||
(first, second)
|
||||
}
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn has_semi(&self) -> bool {
|
||||
match self.syntax().last_child_or_token() {
|
||||
None => false,
|
||||
Some(node) => node.kind() == SEMI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LetStmt {
|
||||
pub fn has_semi(&self) -> bool {
|
||||
match self.syntax().last_child_or_token() {
|
||||
None => false,
|
||||
Some(node) => node.kind() == SEMI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ElseBranchFlavor<'a> {
|
||||
Block(&'a Block),
|
||||
IfExpr(&'a IfExpr),
|
||||
}
|
||||
|
||||
impl IfExpr {
|
||||
pub fn then_branch(&self) -> Option<&Block> {
|
||||
self.blocks().nth(0)
|
||||
}
|
||||
pub fn else_branch(&self) -> Option<ElseBranchFlavor> {
|
||||
let res = match self.blocks().nth(1) {
|
||||
Some(block) => ElseBranchFlavor::Block(block),
|
||||
None => {
|
||||
let elif: &IfExpr = child_opt(self)?;
|
||||
ElseBranchFlavor::IfExpr(elif)
|
||||
}
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
fn blocks(&self) -> AstChildren<Block> {
|
||||
children(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExprStmt {
|
||||
pub fn has_semi(&self) -> bool {
|
||||
match self.syntax().last_child_or_token() {
|
||||
None => false,
|
||||
Some(node) => node.kind() == SEMI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PathSegmentKind<'a> {
|
||||
Name(&'a NameRef),
|
||||
SelfKw,
|
||||
SuperKw,
|
||||
CrateKw,
|
||||
}
|
||||
|
||||
impl PathSegment {
|
||||
pub fn parent_path(&self) -> &Path {
|
||||
self.syntax().parent().and_then(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() {
|
||||
SELF_KW => PathSegmentKind::SelfKw,
|
||||
SUPER_KW => PathSegmentKind::SuperKw,
|
||||
CRATE_KW => PathSegmentKind::CrateKw,
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn has_colon_colon(&self) -> bool {
|
||||
match self.syntax.first_child_or_token().map(|s| s.kind()) {
|
||||
Some(COLONCOLON) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn parent_path(&self) -> Option<&Path> {
|
||||
self.syntax().parent().and_then(Path::cast)
|
||||
}
|
||||
}
|
||||
|
||||
impl UseTree {
|
||||
pub fn has_star(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|it| it.kind() == STAR)
|
||||
}
|
||||
}
|
||||
|
||||
impl UseTreeList {
|
||||
pub fn parent_use_tree(&self) -> &UseTree {
|
||||
self.syntax()
|
||||
.parent()
|
||||
.and_then(UseTree::cast)
|
||||
.expect("UseTreeLists are always nested in UseTrees")
|
||||
}
|
||||
}
|
||||
|
||||
impl RefPat {
|
||||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
}
|
||||
|
||||
fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> {
|
||||
children(parent).next()
|
||||
}
|
||||
@ -268,342 +73,6 @@ fn children<P: AstNode, C: AstNode>(parent: &P) -> AstChildren<C> {
|
||||
AstChildren::new(parent.syntax())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum StructFlavor<'a> {
|
||||
Tuple(&'a PosFieldDefList),
|
||||
Named(&'a NamedFieldDefList),
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl StructFlavor<'_> {
|
||||
fn from_node<N: AstNode>(node: &N) -> StructFlavor {
|
||||
if let Some(nfdl) = child_opt::<_, NamedFieldDefList>(node) {
|
||||
StructFlavor::Named(nfdl)
|
||||
} else if let Some(pfl) = child_opt::<_, PosFieldDefList>(node) {
|
||||
StructFlavor::Tuple(pfl)
|
||||
} else {
|
||||
StructFlavor::Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StructDef {
|
||||
pub fn flavor(&self) -> StructFlavor {
|
||||
StructFlavor::from_node(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl EnumVariant {
|
||||
pub fn parent_enum(&self) -> &EnumDef {
|
||||
self.syntax()
|
||||
.parent()
|
||||
.and_then(|it| it.parent())
|
||||
.and_then(EnumDef::cast)
|
||||
.expect("EnumVariants are always nested in Enums")
|
||||
}
|
||||
pub fn flavor(&self) -> StructFlavor {
|
||||
StructFlavor::from_node(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PointerType {
|
||||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
}
|
||||
|
||||
impl ReferenceType {
|
||||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
}
|
||||
|
||||
impl RefExpr {
|
||||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum PrefixOp {
|
||||
/// The `*` operator for dereferencing
|
||||
Deref,
|
||||
/// The `!` operator for logical inversion
|
||||
Not,
|
||||
/// The `-` operator for negation
|
||||
Neg,
|
||||
}
|
||||
|
||||
impl PrefixExpr {
|
||||
pub fn op_kind(&self) -> Option<PrefixOp> {
|
||||
match self.op_token()?.kind() {
|
||||
STAR => Some(PrefixOp::Deref),
|
||||
EXCL => Some(PrefixOp::Not),
|
||||
MINUS => Some(PrefixOp::Neg),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn op_token(&self) -> Option<SyntaxToken> {
|
||||
self.syntax().first_child_or_token()?.as_token()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum BinOp {
|
||||
/// The `||` operator for boolean OR
|
||||
BooleanOr,
|
||||
/// The `&&` operator for boolean AND
|
||||
BooleanAnd,
|
||||
/// The `==` operator for equality testing
|
||||
EqualityTest,
|
||||
/// The `!=` operator for equality testing
|
||||
NegatedEqualityTest,
|
||||
/// The `<=` operator for lesser-equal testing
|
||||
LesserEqualTest,
|
||||
/// The `>=` operator for greater-equal testing
|
||||
GreaterEqualTest,
|
||||
/// The `<` operator for comparison
|
||||
LesserTest,
|
||||
/// The `>` operator for comparison
|
||||
GreaterTest,
|
||||
/// The `+` operator for addition
|
||||
Addition,
|
||||
/// The `*` operator for multiplication
|
||||
Multiplication,
|
||||
/// The `-` operator for subtraction
|
||||
Subtraction,
|
||||
/// The `/` operator for division
|
||||
Division,
|
||||
/// The `%` operator for remainder after division
|
||||
Remainder,
|
||||
/// The `<<` operator for left shift
|
||||
LeftShift,
|
||||
/// The `>>` operator for right shift
|
||||
RightShift,
|
||||
/// The `^` operator for bitwise XOR
|
||||
BitwiseXor,
|
||||
/// The `|` operator for bitwise OR
|
||||
BitwiseOr,
|
||||
/// The `&` operator for bitwise AND
|
||||
BitwiseAnd,
|
||||
/// The `..` operator for right-open ranges
|
||||
RangeRightOpen,
|
||||
/// The `..=` operator for right-closed ranges
|
||||
RangeRightClosed,
|
||||
/// The `=` operator for assignment
|
||||
Assignment,
|
||||
/// The `+=` operator for assignment after addition
|
||||
AddAssign,
|
||||
/// The `/=` operator for assignment after division
|
||||
DivAssign,
|
||||
/// The `*=` operator for assignment after multiplication
|
||||
MulAssign,
|
||||
/// The `%=` operator for assignment after remainders
|
||||
RemAssign,
|
||||
/// The `>>=` operator for assignment after shifting right
|
||||
ShrAssign,
|
||||
/// The `<<=` operator for assignment after shifting left
|
||||
ShlAssign,
|
||||
/// The `-=` operator for assignment after subtraction
|
||||
SubAssign,
|
||||
/// The `|=` operator for assignment after bitwise OR
|
||||
BitOrAssign,
|
||||
/// The `&=` operator for assignment after bitwise AND
|
||||
BitAndAssign,
|
||||
/// The `^=` operator for assignment after bitwise XOR
|
||||
BitXorAssign,
|
||||
}
|
||||
|
||||
impl BinExpr {
|
||||
fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
|
||||
self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| {
|
||||
match c.kind() {
|
||||
PIPEPIPE => Some((c, BinOp::BooleanOr)),
|
||||
AMPAMP => Some((c, BinOp::BooleanAnd)),
|
||||
EQEQ => Some((c, BinOp::EqualityTest)),
|
||||
NEQ => Some((c, BinOp::NegatedEqualityTest)),
|
||||
LTEQ => Some((c, BinOp::LesserEqualTest)),
|
||||
GTEQ => Some((c, BinOp::GreaterEqualTest)),
|
||||
L_ANGLE => Some((c, BinOp::LesserTest)),
|
||||
R_ANGLE => Some((c, BinOp::GreaterTest)),
|
||||
PLUS => Some((c, BinOp::Addition)),
|
||||
STAR => Some((c, BinOp::Multiplication)),
|
||||
MINUS => Some((c, BinOp::Subtraction)),
|
||||
SLASH => Some((c, BinOp::Division)),
|
||||
PERCENT => Some((c, BinOp::Remainder)),
|
||||
SHL => Some((c, BinOp::LeftShift)),
|
||||
SHR => Some((c, BinOp::RightShift)),
|
||||
CARET => Some((c, BinOp::BitwiseXor)),
|
||||
PIPE => Some((c, BinOp::BitwiseOr)),
|
||||
AMP => Some((c, BinOp::BitwiseAnd)),
|
||||
DOTDOT => Some((c, BinOp::RangeRightOpen)),
|
||||
DOTDOTEQ => Some((c, BinOp::RangeRightClosed)),
|
||||
EQ => Some((c, BinOp::Assignment)),
|
||||
PLUSEQ => Some((c, BinOp::AddAssign)),
|
||||
SLASHEQ => Some((c, BinOp::DivAssign)),
|
||||
STAREQ => Some((c, BinOp::MulAssign)),
|
||||
PERCENTEQ => Some((c, BinOp::RemAssign)),
|
||||
SHREQ => Some((c, BinOp::ShrAssign)),
|
||||
SHLEQ => Some((c, BinOp::ShlAssign)),
|
||||
MINUSEQ => Some((c, BinOp::SubAssign)),
|
||||
PIPEEQ => Some((c, BinOp::BitOrAssign)),
|
||||
AMPEQ => Some((c, BinOp::BitAndAssign)),
|
||||
CARETEQ => Some((c, BinOp::BitXorAssign)),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn op_kind(&self) -> Option<BinOp> {
|
||||
self.op_details().map(|t| t.1)
|
||||
}
|
||||
|
||||
pub fn op_token(&self) -> Option<SyntaxToken> {
|
||||
self.op_details().map(|t| t.0)
|
||||
}
|
||||
|
||||
pub fn lhs(&self) -> Option<&Expr> {
|
||||
children(self).nth(0)
|
||||
}
|
||||
|
||||
pub fn rhs(&self) -> Option<&Expr> {
|
||||
children(self).nth(1)
|
||||
}
|
||||
|
||||
pub fn sub_exprs(&self) -> (Option<&Expr>, Option<&Expr>) {
|
||||
let mut children = children(self);
|
||||
let first = children.next();
|
||||
let second = children.next();
|
||||
(first, second)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum SelfParamFlavor {
|
||||
/// self
|
||||
Owned,
|
||||
/// &self
|
||||
Ref,
|
||||
/// &mut self
|
||||
MutRef,
|
||||
}
|
||||
|
||||
impl SelfParam {
|
||||
pub fn self_kw_token(&self) -> SyntaxToken {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.as_token())
|
||||
.find(|it| it.kind() == SELF_KW)
|
||||
.expect("invalid tree: self param must have self")
|
||||
}
|
||||
|
||||
pub fn flavor(&self) -> SelfParamFlavor {
|
||||
let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP);
|
||||
if borrowed {
|
||||
// check for a `mut` coming after the & -- `mut &self` != `&mut self`
|
||||
if self
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.skip_while(|n| n.kind() != AMP)
|
||||
.any(|n| n.kind() == MUT_KW)
|
||||
{
|
||||
SelfParamFlavor::MutRef
|
||||
} else {
|
||||
SelfParamFlavor::Ref
|
||||
}
|
||||
} else {
|
||||
SelfParamFlavor::Owned
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum LiteralFlavor {
|
||||
String,
|
||||
ByteString,
|
||||
Char,
|
||||
Byte,
|
||||
IntNumber { suffix: Option<SmolStr> },
|
||||
FloatNumber { suffix: Option<SmolStr> },
|
||||
Bool,
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
pub fn token(&self) -> SyntaxToken {
|
||||
match self.syntax().first_child_or_token().unwrap() {
|
||||
SyntaxElement::Token(token) => token,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flavor(&self) -> LiteralFlavor {
|
||||
match self.token().kind() {
|
||||
INT_NUMBER => {
|
||||
let allowed_suffix_list = [
|
||||
"isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32",
|
||||
"u16", "u8",
|
||||
];
|
||||
let text = self.token().text().to_string();
|
||||
let suffix = allowed_suffix_list
|
||||
.iter()
|
||||
.find(|&s| text.ends_with(s))
|
||||
.map(|&suf| SmolStr::new(suf));
|
||||
LiteralFlavor::IntNumber { suffix }
|
||||
}
|
||||
FLOAT_NUMBER => {
|
||||
let allowed_suffix_list = ["f64", "f32"];
|
||||
let text = self.token().text().to_string();
|
||||
let suffix = allowed_suffix_list
|
||||
.iter()
|
||||
.find(|&s| text.ends_with(s))
|
||||
.map(|&suf| SmolStr::new(suf));
|
||||
LiteralFlavor::FloatNumber { suffix: suffix }
|
||||
}
|
||||
STRING | RAW_STRING => LiteralFlavor::String,
|
||||
TRUE_KW | FALSE_KW => LiteralFlavor::Bool,
|
||||
BYTE_STRING | RAW_BYTE_STRING => LiteralFlavor::ByteString,
|
||||
CHAR => LiteralFlavor::Char,
|
||||
BYTE => LiteralFlavor::Byte,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedField {
|
||||
pub fn parent_struct_lit(&self) -> &StructLit {
|
||||
self.syntax().ancestors().find_map(StructLit::cast).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl BindPat {
|
||||
pub fn is_mutable(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
|
||||
pub fn is_ref(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW)
|
||||
}
|
||||
}
|
||||
|
||||
impl 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 WherePred {
|
||||
pub fn lifetime_token(&self) -> Option<SyntaxToken> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.as_token())
|
||||
.find(|it| it.kind() == LIFETIME)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_doc_comment_none() {
|
||||
let file = SourceFile::parse(
|
||||
|
252
crates/ra_syntax/src/ast/expr_extensions.rs
Normal file
252
crates/ra_syntax/src/ast/expr_extensions.rs
Normal file
@ -0,0 +1,252 @@
|
||||
//! Various extension methods to ast Expr Nodes, which are hard to code-generate.
|
||||
|
||||
use crate::{
|
||||
SyntaxToken, SyntaxElement, SmolStr,
|
||||
ast::{self, AstNode, AstChildren, children, child_opt},
|
||||
SyntaxKind::*
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ElseBranch<'a> {
|
||||
Block(&'a ast::Block),
|
||||
IfExpr(&'a ast::IfExpr),
|
||||
}
|
||||
|
||||
impl ast::IfExpr {
|
||||
pub fn then_branch(&self) -> Option<&ast::Block> {
|
||||
self.blocks().nth(0)
|
||||
}
|
||||
pub fn else_branch(&self) -> Option<ElseBranch> {
|
||||
let res = match self.blocks().nth(1) {
|
||||
Some(block) => ElseBranch::Block(block),
|
||||
None => {
|
||||
let elif: &ast::IfExpr = child_opt(self)?;
|
||||
ElseBranch::IfExpr(elif)
|
||||
}
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
fn blocks(&self) -> AstChildren<ast::Block> {
|
||||
children(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::RefExpr {
|
||||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum PrefixOp {
|
||||
/// The `*` operator for dereferencing
|
||||
Deref,
|
||||
/// The `!` operator for logical inversion
|
||||
Not,
|
||||
/// The `-` operator for negation
|
||||
Neg,
|
||||
}
|
||||
|
||||
impl ast::PrefixExpr {
|
||||
pub fn op_kind(&self) -> Option<PrefixOp> {
|
||||
match self.op_token()?.kind() {
|
||||
STAR => Some(PrefixOp::Deref),
|
||||
EXCL => Some(PrefixOp::Not),
|
||||
MINUS => Some(PrefixOp::Neg),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn op_token(&self) -> Option<SyntaxToken> {
|
||||
self.syntax().first_child_or_token()?.as_token()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum BinOp {
|
||||
/// The `||` operator for boolean OR
|
||||
BooleanOr,
|
||||
/// The `&&` operator for boolean AND
|
||||
BooleanAnd,
|
||||
/// The `==` operator for equality testing
|
||||
EqualityTest,
|
||||
/// The `!=` operator for equality testing
|
||||
NegatedEqualityTest,
|
||||
/// The `<=` operator for lesser-equal testing
|
||||
LesserEqualTest,
|
||||
/// The `>=` operator for greater-equal testing
|
||||
GreaterEqualTest,
|
||||
/// The `<` operator for comparison
|
||||
LesserTest,
|
||||
/// The `>` operator for comparison
|
||||
GreaterTest,
|
||||
/// The `+` operator for addition
|
||||
Addition,
|
||||
/// The `*` operator for multiplication
|
||||
Multiplication,
|
||||
/// The `-` operator for subtraction
|
||||
Subtraction,
|
||||
/// The `/` operator for division
|
||||
Division,
|
||||
/// The `%` operator for remainder after division
|
||||
Remainder,
|
||||
/// The `<<` operator for left shift
|
||||
LeftShift,
|
||||
/// The `>>` operator for right shift
|
||||
RightShift,
|
||||
/// The `^` operator for bitwise XOR
|
||||
BitwiseXor,
|
||||
/// The `|` operator for bitwise OR
|
||||
BitwiseOr,
|
||||
/// The `&` operator for bitwise AND
|
||||
BitwiseAnd,
|
||||
/// The `..` operator for right-open ranges
|
||||
RangeRightOpen,
|
||||
/// The `..=` operator for right-closed ranges
|
||||
RangeRightClosed,
|
||||
/// The `=` operator for assignment
|
||||
Assignment,
|
||||
/// The `+=` operator for assignment after addition
|
||||
AddAssign,
|
||||
/// The `/=` operator for assignment after division
|
||||
DivAssign,
|
||||
/// The `*=` operator for assignment after multiplication
|
||||
MulAssign,
|
||||
/// The `%=` operator for assignment after remainders
|
||||
RemAssign,
|
||||
/// The `>>=` operator for assignment after shifting right
|
||||
ShrAssign,
|
||||
/// The `<<=` operator for assignment after shifting left
|
||||
ShlAssign,
|
||||
/// The `-=` operator for assignment after subtraction
|
||||
SubAssign,
|
||||
/// The `|=` operator for assignment after bitwise OR
|
||||
BitOrAssign,
|
||||
/// The `&=` operator for assignment after bitwise AND
|
||||
BitAndAssign,
|
||||
/// The `^=` operator for assignment after bitwise XOR
|
||||
BitXorAssign,
|
||||
}
|
||||
|
||||
impl ast::BinExpr {
|
||||
fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
|
||||
self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| {
|
||||
match c.kind() {
|
||||
PIPEPIPE => Some((c, BinOp::BooleanOr)),
|
||||
AMPAMP => Some((c, BinOp::BooleanAnd)),
|
||||
EQEQ => Some((c, BinOp::EqualityTest)),
|
||||
NEQ => Some((c, BinOp::NegatedEqualityTest)),
|
||||
LTEQ => Some((c, BinOp::LesserEqualTest)),
|
||||
GTEQ => Some((c, BinOp::GreaterEqualTest)),
|
||||
L_ANGLE => Some((c, BinOp::LesserTest)),
|
||||
R_ANGLE => Some((c, BinOp::GreaterTest)),
|
||||
PLUS => Some((c, BinOp::Addition)),
|
||||
STAR => Some((c, BinOp::Multiplication)),
|
||||
MINUS => Some((c, BinOp::Subtraction)),
|
||||
SLASH => Some((c, BinOp::Division)),
|
||||
PERCENT => Some((c, BinOp::Remainder)),
|
||||
SHL => Some((c, BinOp::LeftShift)),
|
||||
SHR => Some((c, BinOp::RightShift)),
|
||||
CARET => Some((c, BinOp::BitwiseXor)),
|
||||
PIPE => Some((c, BinOp::BitwiseOr)),
|
||||
AMP => Some((c, BinOp::BitwiseAnd)),
|
||||
DOTDOT => Some((c, BinOp::RangeRightOpen)),
|
||||
DOTDOTEQ => Some((c, BinOp::RangeRightClosed)),
|
||||
EQ => Some((c, BinOp::Assignment)),
|
||||
PLUSEQ => Some((c, BinOp::AddAssign)),
|
||||
SLASHEQ => Some((c, BinOp::DivAssign)),
|
||||
STAREQ => Some((c, BinOp::MulAssign)),
|
||||
PERCENTEQ => Some((c, BinOp::RemAssign)),
|
||||
SHREQ => Some((c, BinOp::ShrAssign)),
|
||||
SHLEQ => Some((c, BinOp::ShlAssign)),
|
||||
MINUSEQ => Some((c, BinOp::SubAssign)),
|
||||
PIPEEQ => Some((c, BinOp::BitOrAssign)),
|
||||
AMPEQ => Some((c, BinOp::BitAndAssign)),
|
||||
CARETEQ => Some((c, BinOp::BitXorAssign)),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn op_kind(&self) -> Option<BinOp> {
|
||||
self.op_details().map(|t| t.1)
|
||||
}
|
||||
|
||||
pub fn op_token(&self) -> Option<SyntaxToken> {
|
||||
self.op_details().map(|t| t.0)
|
||||
}
|
||||
|
||||
pub fn lhs(&self) -> Option<&ast::Expr> {
|
||||
children(self).nth(0)
|
||||
}
|
||||
|
||||
pub fn rhs(&self) -> Option<&ast::Expr> {
|
||||
children(self).nth(1)
|
||||
}
|
||||
|
||||
pub fn sub_exprs(&self) -> (Option<&ast::Expr>, Option<&ast::Expr>) {
|
||||
let mut children = children(self);
|
||||
let first = children.next();
|
||||
let second = children.next();
|
||||
(first, second)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum LiteralKind {
|
||||
String,
|
||||
ByteString,
|
||||
Char,
|
||||
Byte,
|
||||
IntNumber { suffix: Option<SmolStr> },
|
||||
FloatNumber { suffix: Option<SmolStr> },
|
||||
Bool,
|
||||
}
|
||||
|
||||
impl ast::Literal {
|
||||
pub fn token(&self) -> SyntaxToken {
|
||||
match self.syntax().first_child_or_token().unwrap() {
|
||||
SyntaxElement::Token(token) => token,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> LiteralKind {
|
||||
match self.token().kind() {
|
||||
INT_NUMBER => {
|
||||
let allowed_suffix_list = [
|
||||
"isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32",
|
||||
"u16", "u8",
|
||||
];
|
||||
let text = self.token().text().to_string();
|
||||
let suffix = allowed_suffix_list
|
||||
.iter()
|
||||
.find(|&s| text.ends_with(s))
|
||||
.map(|&suf| SmolStr::new(suf));
|
||||
LiteralKind::IntNumber { suffix }
|
||||
}
|
||||
FLOAT_NUMBER => {
|
||||
let allowed_suffix_list = ["f64", "f32"];
|
||||
let text = self.token().text().to_string();
|
||||
let suffix = allowed_suffix_list
|
||||
.iter()
|
||||
.find(|&s| text.ends_with(s))
|
||||
.map(|&suf| SmolStr::new(suf));
|
||||
LiteralKind::FloatNumber { suffix: suffix }
|
||||
}
|
||||
STRING | RAW_STRING => LiteralKind::String,
|
||||
TRUE_KW | FALSE_KW => LiteralKind::Bool,
|
||||
BYTE_STRING | RAW_BYTE_STRING => LiteralKind::ByteString,
|
||||
CHAR => LiteralKind::Char,
|
||||
BYTE => LiteralKind::Byte,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::NamedField {
|
||||
pub fn parent_struct_lit(&self) -> &ast::StructLit {
|
||||
self.syntax().ancestors().find_map(ast::StructLit::cast).unwrap()
|
||||
}
|
||||
}
|
303
crates/ra_syntax/src/ast/extensions.rs
Normal file
303
crates/ra_syntax/src/ast/extensions.rs
Normal file
@ -0,0 +1,303 @@
|
||||
//! Various extension methods to ast Nodes, which are hard to code-generate.
|
||||
//! Extensions for various expressions live in a sibling `expr_extensions` module.
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
SmolStr, SyntaxToken,
|
||||
ast::{self, AstNode, children, child_opt},
|
||||
SyntaxKind::*,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
prev.kind() == EXCL
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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() {
|
||||
SELF_KW => PathSegmentKind::SelfKw,
|
||||
SUPER_KW => PathSegmentKind::SuperKw,
|
||||
CRATE_KW => PathSegmentKind::CrateKw,
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn has_colon_colon(&self) -> bool {
|
||||
match self.syntax.first_child_or_token().map(|s| s.kind()) {
|
||||
Some(COLONCOLON) => true,
|
||||
_ => 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,
|
||||
Some(node) => node.kind() == SEMI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::UseTree {
|
||||
pub fn has_star(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|it| it.kind() == STAR)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum StructKind<'a> {
|
||||
Tuple(&'a ast::PosFieldDefList),
|
||||
Named(&'a ast::NamedFieldDefList),
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl StructKind<'_> {
|
||||
fn from_node<N: AstNode>(node: &N) -> StructKind {
|
||||
if let Some(nfdl) = child_opt::<_, ast::NamedFieldDefList>(node) {
|
||||
StructKind::Named(nfdl)
|
||||
} else if let Some(pfl) = child_opt::<_, ast::PosFieldDefList>(node) {
|
||||
StructKind::Tuple(pfl)
|
||||
} else {
|
||||
StructKind::Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::StructDef {
|
||||
pub fn kind(&self) -> StructKind {
|
||||
StructKind::from_node(self)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
pub fn kind(&self) -> StructKind {
|
||||
StructKind::from_node(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::LetStmt {
|
||||
pub fn has_semi(&self) -> bool {
|
||||
match self.syntax().last_child_or_token() {
|
||||
None => false,
|
||||
Some(node) => node.kind() == SEMI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::ExprStmt {
|
||||
pub fn has_semi(&self) -> bool {
|
||||
match self.syntax().last_child_or_token() {
|
||||
None => false,
|
||||
Some(node) => node.kind() == SEMI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::RefPat {
|
||||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::BindPat {
|
||||
pub fn is_mutable(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
|
||||
pub fn is_ref(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::PointerType {
|
||||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::ReferenceType {
|
||||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum SelfParamKind {
|
||||
/// 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())
|
||||
.find(|it| it.kind() == SELF_KW)
|
||||
.expect("invalid tree: self param must have self")
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> SelfParamKind {
|
||||
let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP);
|
||||
if borrowed {
|
||||
// check for a `mut` coming after the & -- `mut &self` != `&mut self`
|
||||
if self
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.skip_while(|n| n.kind() != AMP)
|
||||
.any(|n| n.kind() == MUT_KW)
|
||||
{
|
||||
SelfParamKind::MutRef
|
||||
} else {
|
||||
SelfParamKind::Ref
|
||||
}
|
||||
} else {
|
||||
SelfParamKind::Owned
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
//! There are many AstNodes, but only a few tokens, so we hand-write them here.
|
||||
|
||||
use crate::{
|
||||
SyntaxToken,
|
||||
SyntaxKind::{COMMENT, WHITESPACE},
|
||||
|
@ -1,3 +1,7 @@
|
||||
//! Various traits that are implemented by ast nodes.
|
||||
//!
|
||||
//! The implementations are usually trivial, and live in generated.rs
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
|
Loading…
Reference in New Issue
Block a user