1 //! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s
11 use std::marker::PhantomData;
14 syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken},
19 expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp},
21 AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents,
22 StructKind, TypeBoundKind, VisibilityKind,
24 generated::{nodes::*, tokens::*},
29 /// The main trait to go from untyped `SyntaxNode` to a typed ast. The
30 /// conversion itself has zero runtime cost: ast and syntax nodes have exactly
31 /// the same representation: a pointer to the tree root and a pointer to the
34 fn can_cast(kind: SyntaxKind) -> bool
38 fn cast(syntax: SyntaxNode) -> Option<Self>
42 fn syntax(&self) -> &SyntaxNode;
45 /// Like `AstNode`, but wraps tokens rather than interior nodes.
47 fn can_cast(token: SyntaxKind) -> bool
51 fn cast(syntax: SyntaxToken) -> Option<Self>
55 fn syntax(&self) -> &SyntaxToken;
57 fn text(&self) -> &SmolStr {
62 /// An iterator over `SyntaxNode` children of a particular AST type.
63 #[derive(Debug, Clone)]
64 pub struct AstChildren<N> {
65 inner: SyntaxNodeChildren,
69 impl<N> AstChildren<N> {
70 fn new(parent: &SyntaxNode) -> Self {
71 AstChildren { inner: parent.children(), ph: PhantomData }
75 impl<N: AstNode> Iterator for AstChildren<N> {
77 fn next(&mut self) -> Option<N> {
78 self.inner.by_ref().find_map(N::cast)
83 use super::{AstChildren, AstNode, SyntaxKind, SyntaxNode, SyntaxToken};
85 pub(super) fn child<N: AstNode>(parent: &SyntaxNode) -> Option<N> {
86 parent.children().find_map(N::cast)
89 pub(super) fn children<N: AstNode>(parent: &SyntaxNode) -> AstChildren<N> {
90 AstChildren::new(parent)
93 pub(super) fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<SyntaxToken> {
94 parent.children_with_tokens().filter_map(|it| it.into_token()).find(|it| it.kind() == kind)
99 fn assert_ast_is_object_safe() {
100 fn _f(_: &dyn AstNode, _: &dyn NameOwner) {}
104 fn test_doc_comment_none() {
105 let file = SourceFile::parse(
113 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
114 assert!(module.doc_comment_text().is_none());
118 fn test_doc_comment_of_items() {
119 let file = SourceFile::parse(
128 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
129 assert_eq!("doc", module.doc_comment_text().unwrap());
133 fn test_doc_comment_of_statics() {
134 let file = SourceFile::parse(
137 static LEVELS: i32 = 0;
142 let st = file.syntax().descendants().find_map(StaticDef::cast).unwrap();
143 assert_eq!("Number of levels", st.doc_comment_text().unwrap());
147 fn test_doc_comment_preserves_indents() {
148 let file = SourceFile::parse(
161 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
162 assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap());
166 fn test_doc_comment_preserves_newlines() {
167 let file = SourceFile::parse(
178 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
179 assert_eq!("this\nis\nmod\nfoo", module.doc_comment_text().unwrap());
183 fn test_doc_comment_single_line_block_strips_suffix() {
184 let file = SourceFile::parse(
186 /** this is mod foo*/
192 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
193 assert_eq!("this is mod foo", module.doc_comment_text().unwrap());
197 fn test_doc_comment_single_line_block_strips_suffix_whitespace() {
198 let file = SourceFile::parse(
200 /** this is mod foo */
206 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
207 assert_eq!("this is mod foo ", module.doc_comment_text().unwrap());
211 fn test_doc_comment_multi_line_block_strips_suffix() {
212 let file = SourceFile::parse(
224 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
226 " this\n is\n mod foo\n ",
227 module.doc_comment_text().unwrap()
232 fn test_comments_preserve_trailing_whitespace() {
233 let file = SourceFile::parse(
234 "\n/// Representation of a Realm. \n/// In the specification these are called Realm Records.\nstruct Realm {}",
238 let def = file.syntax().descendants().find_map(StructDef::cast).unwrap();
240 "Representation of a Realm. \nIn the specification these are called Realm Records.",
241 def.doc_comment_text().unwrap()
246 fn test_where_predicates() {
247 fn assert_bound(text: &str, bound: Option<TypeBound>) {
248 assert_eq!(text, bound.unwrap().syntax().text().to_string());
251 let file = SourceFile::parse(
255 T: Clone + Copy + Debug + 'static,
257 Iterator::Item: 'a + Debug,
258 Iterator::Item: Debug + 'a,
259 <T as Iterator>::Item: Debug + 'a,
260 for<'a> F: Fn(&'a str)
266 let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap();
268 let mut predicates = where_clause.predicates();
270 let pred = predicates.next().unwrap();
271 let mut bounds = pred.type_bound_list().unwrap().bounds();
273 assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string());
274 assert_bound("Clone", bounds.next());
275 assert_bound("Copy", bounds.next());
276 assert_bound("Debug", bounds.next());
277 assert_bound("'static", bounds.next());
279 let pred = predicates.next().unwrap();
280 let mut bounds = pred.type_bound_list().unwrap().bounds();
282 assert_eq!("'a", pred.lifetime_token().unwrap().text());
284 assert_bound("'b", bounds.next());
285 assert_bound("'c", bounds.next());
287 let pred = predicates.next().unwrap();
288 let mut bounds = pred.type_bound_list().unwrap().bounds();
290 assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string());
291 assert_bound("'a", bounds.next());
293 let pred = predicates.next().unwrap();
294 let mut bounds = pred.type_bound_list().unwrap().bounds();
296 assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string());
297 assert_bound("Debug", bounds.next());
298 assert_bound("'a", bounds.next());
300 let pred = predicates.next().unwrap();
301 let mut bounds = pred.type_bound_list().unwrap().bounds();
303 assert_eq!("<T as Iterator>::Item", pred.type_ref().unwrap().syntax().text().to_string());
304 assert_bound("Debug", bounds.next());
305 assert_bound("'a", bounds.next());
307 let pred = predicates.next().unwrap();
308 let mut bounds = pred.type_bound_list().unwrap().bounds();
310 assert_eq!("for<'a> F", pred.type_ref().unwrap().syntax().text().to_string());
311 assert_bound("Fn(&'a str)", bounds.next());