mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Provide more complete AST accessors to support usage in rustc
This commit is contained in:
parent
8595693287
commit
60f4d7bd8c
18 changed files with 433 additions and 211 deletions
|
@ -271,7 +271,7 @@ where
|
|||
let pred = predicates.next().unwrap();
|
||||
let mut bounds = pred.type_bound_list().unwrap().bounds();
|
||||
|
||||
assert_eq!("'a", pred.lifetime_token().unwrap().text());
|
||||
assert_eq!("'a", pred.lifetime().unwrap().text());
|
||||
|
||||
assert_bound("'b", bounds.next());
|
||||
assert_bound("'c", bounds.next());
|
||||
|
|
|
@ -99,7 +99,7 @@ impl ast::ItemList {
|
|||
None => match self.l_curly() {
|
||||
Some(it) => (
|
||||
" ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(),
|
||||
InsertPosition::After(it),
|
||||
InsertPosition::After(it.syntax().clone().into()),
|
||||
),
|
||||
None => return self.clone(),
|
||||
},
|
||||
|
@ -109,10 +109,6 @@ impl ast::ItemList {
|
|||
[ws.ws().into(), item.syntax().clone().into()].into();
|
||||
self.insert_children(position, to_insert)
|
||||
}
|
||||
|
||||
fn l_curly(&self) -> Option<SyntaxElement> {
|
||||
self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::RecordFieldList {
|
||||
|
@ -147,7 +143,7 @@ impl ast::RecordFieldList {
|
|||
macro_rules! after_l_curly {
|
||||
() => {{
|
||||
let anchor = match self.l_curly() {
|
||||
Some(it) => it,
|
||||
Some(it) => it.syntax().clone().into(),
|
||||
None => return self.clone(),
|
||||
};
|
||||
InsertPosition::After(anchor)
|
||||
|
@ -189,24 +185,20 @@ impl ast::RecordFieldList {
|
|||
|
||||
self.insert_children(position, to_insert)
|
||||
}
|
||||
|
||||
fn l_curly(&self) -> Option<SyntaxElement> {
|
||||
self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::TypeParam {
|
||||
#[must_use]
|
||||
pub fn remove_bounds(&self) -> ast::TypeParam {
|
||||
let colon = match self.colon_token() {
|
||||
let colon = match self.colon() {
|
||||
Some(it) => it,
|
||||
None => return self.clone(),
|
||||
};
|
||||
let end = match self.type_bound_list() {
|
||||
Some(it) => it.syntax().clone().into(),
|
||||
None => colon.clone().into(),
|
||||
None => colon.syntax().clone().into(),
|
||||
};
|
||||
self.replace_children(colon.into()..=end, iter::empty())
|
||||
self.replace_children(colon.syntax().clone().into()..=end, iter::empty())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,8 +297,12 @@ impl ast::UseTree {
|
|||
Some(it) => it,
|
||||
None => return self.clone(),
|
||||
};
|
||||
let use_tree =
|
||||
make::use_tree(suffix.clone(), self.use_tree_list(), self.alias(), self.has_star());
|
||||
let use_tree = make::use_tree(
|
||||
suffix.clone(),
|
||||
self.use_tree_list(),
|
||||
self.alias(),
|
||||
self.star().is_some(),
|
||||
);
|
||||
let nested = make::use_tree_list(iter::once(use_tree));
|
||||
return make::use_tree(prefix.clone(), Some(nested), None, false);
|
||||
|
||||
|
|
|
@ -52,6 +52,10 @@ impl ast::RefExpr {
|
|||
pub fn is_mut(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
|
||||
}
|
||||
|
||||
pub fn raw_token(&self) -> Option<SyntaxToken> {
|
||||
None // FIXME: implement &raw
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
ast::{self, child_opt, children, AstNode, AttrInput, NameOwner, SyntaxNode},
|
||||
ast::{
|
||||
self, child_opt, child_token_opt, children, AstElement, AstNode, AstToken, AttrInput,
|
||||
NameOwner, SyntaxNode,
|
||||
},
|
||||
SmolStr, SyntaxElement,
|
||||
SyntaxKind::*,
|
||||
SyntaxToken, T,
|
||||
|
@ -130,13 +133,6 @@ impl ast::PathSegment {
|
|||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn has_colon_colon(&self) -> bool {
|
||||
match self.syntax.first_child_or_token().map(|s| s.kind()) {
|
||||
Some(T![::]) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::Path {
|
||||
|
@ -154,12 +150,6 @@ impl ast::Module {
|
|||
}
|
||||
}
|
||||
|
||||
impl ast::UseTree {
|
||||
pub fn has_star(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|it| it.kind() == T![*])
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::UseTreeList {
|
||||
pub fn parent_use_tree(&self) -> ast::UseTree {
|
||||
self.syntax()
|
||||
|
@ -167,20 +157,6 @@ impl ast::UseTreeList {
|
|||
.and_then(ast::UseTree::cast)
|
||||
.expect("UseTreeLists are always nested in UseTrees")
|
||||
}
|
||||
pub fn l_curly(&self) -> Option<SyntaxToken> {
|
||||
self.token(T!['{'])
|
||||
}
|
||||
|
||||
pub fn r_curly(&self) -> Option<SyntaxToken> {
|
||||
self.token(T!['}'])
|
||||
}
|
||||
|
||||
fn token(&self, kind: SyntaxKind) -> Option<SyntaxToken> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.into_token())
|
||||
.find(|it| it.kind() == kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::ImplDef {
|
||||
|
@ -387,24 +363,9 @@ pub enum SelfParamKind {
|
|||
}
|
||||
|
||||
impl ast::SelfParam {
|
||||
pub fn self_kw_token(&self) -> SyntaxToken {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.into_token())
|
||||
.find(|it| it.kind() == T![self])
|
||||
.expect("invalid tree: self param must have self")
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> SelfParamKind {
|
||||
let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == T![&]);
|
||||
if borrowed {
|
||||
// check for a `mut` coming after the & -- `mut &self` != `&mut self`
|
||||
if self
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.skip_while(|n| n.kind() != T![&])
|
||||
.any(|n| n.kind() == T![mut])
|
||||
{
|
||||
if self.amp().is_some() {
|
||||
if self.amp_mut_kw().is_some() {
|
||||
SelfParamKind::MutRef
|
||||
} else {
|
||||
SelfParamKind::Ref
|
||||
|
@ -413,32 +374,23 @@ impl ast::SelfParam {
|
|||
SelfParamKind::Owned
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::LifetimeParam {
|
||||
pub fn lifetime_token(&self) -> Option<SyntaxToken> {
|
||||
/// the "mut" in "mut self", not the one in "&mut self"
|
||||
pub fn mut_kw(&self) -> Option<ast::MutKw> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.into_token())
|
||||
.find(|it| it.kind() == LIFETIME)
|
||||
.take_while(|it| it.kind() != T![&])
|
||||
.find_map(ast::MutKw::cast)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::TypeParam {
|
||||
pub fn colon_token(&self) -> Option<SyntaxToken> {
|
||||
/// the "mut" in "&mut self", not the one in "mut self"
|
||||
pub fn amp_mut_kw(&self) -> Option<ast::MutKw> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.into_token())
|
||||
.find(|it| it.kind() == T![:])
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::WherePred {
|
||||
pub fn lifetime_token(&self) -> Option<SyntaxToken> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.into_token())
|
||||
.find(|it| it.kind() == LIFETIME)
|
||||
.skip_while(|it| it.kind() != T![&])
|
||||
.find_map(ast::MutKw::cast)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -449,7 +401,7 @@ pub enum TypeBoundKind {
|
|||
/// for<'a> ...
|
||||
ForType(ast::ForType),
|
||||
/// 'a
|
||||
Lifetime(ast::SyntaxToken),
|
||||
Lifetime(ast::Lifetime),
|
||||
}
|
||||
|
||||
impl ast::TypeBound {
|
||||
|
@ -465,21 +417,28 @@ impl ast::TypeBound {
|
|||
}
|
||||
}
|
||||
|
||||
fn lifetime(&self) -> Option<SyntaxToken> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.into_token())
|
||||
.find(|it| it.kind() == LIFETIME)
|
||||
pub fn has_question_mark(&self) -> bool {
|
||||
self.question().is_some()
|
||||
}
|
||||
|
||||
pub fn question_mark_token(&self) -> Option<SyntaxToken> {
|
||||
pub fn const_question(&self) -> Option<ast::Question> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.into_token())
|
||||
.find(|it| it.kind() == T![?])
|
||||
.take_while(|it| it.kind() != T![const])
|
||||
.find_map(ast::Question::cast)
|
||||
}
|
||||
pub fn has_question_mark(&self) -> bool {
|
||||
self.question_mark_token().is_some()
|
||||
|
||||
pub fn question(&self) -> Option<ast::Question> {
|
||||
if self.const_kw().is_some() {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|it| it.into_token())
|
||||
.skip_while(|it| it.kind() != T![const])
|
||||
.find_map(ast::Question::cast)
|
||||
} else {
|
||||
child_token_opt(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,6 +452,7 @@ pub enum VisibilityKind {
|
|||
In(ast::Path),
|
||||
PubCrate,
|
||||
PubSuper,
|
||||
PubSelf,
|
||||
Pub,
|
||||
}
|
||||
|
||||
|
@ -504,6 +464,8 @@ impl ast::Visibility {
|
|||
VisibilityKind::PubCrate
|
||||
} else if self.is_pub_super() {
|
||||
VisibilityKind::PubSuper
|
||||
} else if self.is_pub_self() {
|
||||
VisibilityKind::PubSuper
|
||||
} else {
|
||||
VisibilityKind::Pub
|
||||
}
|
||||
|
@ -516,6 +478,10 @@ impl ast::Visibility {
|
|||
fn is_pub_super(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|it| it.kind() == T![super])
|
||||
}
|
||||
|
||||
fn is_pub_self(&self) -> bool {
|
||||
self.syntax().children_with_tokens().any(|it| it.kind() == T![self])
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::MacroCall {
|
||||
|
@ -528,3 +494,41 @@ impl ast::MacroCall {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
.take_while(|it| !ast::RangeSeparator::can_cast_element(it.kind()))
|
||||
.filter_map(|it| it.into_node())
|
||||
.find_map(ast::Pat::cast)
|
||||
}
|
||||
|
||||
pub fn end(&self) -> Option<ast::Pat> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.skip_while(|it| !ast::RangeSeparator::can_cast_element(it.kind()))
|
||||
.filter_map(|it| it.into_node())
|
||||
.find_map(ast::Pat::cast)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::TokenTree {
|
||||
pub fn left_delimiter(&self) -> Option<ast::LeftDelimiter> {
|
||||
self.syntax().first_child_or_token().and_then(ast::LeftDelimiter::cast_element)
|
||||
}
|
||||
|
||||
pub fn right_delimiter(&self) -> Option<ast::RightDelimiter> {
|
||||
self.syntax().last_child_or_token().and_then(ast::RightDelimiter::cast_element)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
ast::{self, child_opt, children, AstChildren, AstNode, AstToken},
|
||||
syntax_node::SyntaxElementChildren,
|
||||
use crate::ast::{
|
||||
self, child_elements, child_opt, child_token_opt, child_tokens, children, AstChildElements,
|
||||
AstChildTokens, AstChildren, AstNode, AstToken,
|
||||
};
|
||||
|
||||
pub trait TypeAscriptionOwner: AstNode {
|
||||
|
@ -31,6 +31,10 @@ pub trait LoopBodyOwner: AstNode {
|
|||
fn loop_body(&self) -> Option<ast::BlockExpr> {
|
||||
child_opt(self)
|
||||
}
|
||||
|
||||
fn label(&self) -> Option<ast::Label> {
|
||||
child_opt(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArgListOwner: AstNode {
|
||||
|
@ -65,6 +69,10 @@ pub trait TypeBoundsOwner: AstNode {
|
|||
fn type_bound_list(&self) -> Option<ast::TypeBoundList> {
|
||||
child_opt(self)
|
||||
}
|
||||
|
||||
fn colon(&self) -> Option<ast::Colon> {
|
||||
child_token_opt(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AttrsOwner: AstNode {
|
||||
|
@ -74,11 +82,14 @@ pub trait AttrsOwner: AstNode {
|
|||
fn has_atom_attr(&self, atom: &str) -> bool {
|
||||
self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom)
|
||||
}
|
||||
fn attr_or_comments(&self) -> AstChildElements<ast::AttrOrComment> {
|
||||
child_elements(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DocCommentsOwner: AstNode {
|
||||
fn doc_comments(&self) -> CommentIter {
|
||||
CommentIter { iter: self.syntax().children_with_tokens() }
|
||||
fn doc_comments(&self) -> AstChildTokens<ast::Comment> {
|
||||
child_tokens(self)
|
||||
}
|
||||
|
||||
/// Returns the textual content of a doc comment block as a single string.
|
||||
|
@ -123,14 +134,3 @@ pub trait DocCommentsOwner: AstNode {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommentIter {
|
||||
iter: SyntaxElementChildren,
|
||||
}
|
||||
|
||||
impl Iterator for CommentIter {
|
||||
type Item = ast::Comment;
|
||||
fn next(&mut self) -> Option<ast::Comment> {
|
||||
self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue