From 60f4d7bd8c0ecb9f23557464e824140a2be8f41a Mon Sep 17 00:00:00 2001
From: Luca Barbieri <luca@luca-barbieri.com>
Date: Fri, 3 Apr 2020 21:12:09 +0200
Subject: Provide more complete AST accessors to support usage in rustc

---
 crates/ra_syntax/src/ast.rs                 |   2 +-
 crates/ra_syntax/src/ast/edit.rs            |  26 +++--
 crates/ra_syntax/src/ast/expr_extensions.rs |   4 +
 crates/ra_syntax/src/ast/extensions.rs      | 148 ++++++++++++++--------------
 crates/ra_syntax/src/ast/traits.rs          |  32 +++---
 5 files changed, 108 insertions(+), 104 deletions(-)

(limited to 'crates/ra_syntax/src')

diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index ab0f44dd2..c81b68d3e 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -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());
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index b69cae234..d79310995 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -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);
 
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index 8bbd946c0..40c8fca3b 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -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)]
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index bf7d137be..400eba210 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -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)
+    }
+}
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs
index 576378306..e6f3a4ebb 100644
--- a/crates/ra_syntax/src/ast/traits.rs
+++ b/crates/ra_syntax/src/ast/traits.rs
@@ -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))
-    }
-}
-- 
cgit v1.2.3