1 //! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s
12 use std::marker::PhantomData;
15 syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken},
20 expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp},
21 generated::{nodes::*, tokens::*},
23 AttrKind, AttrsOwnerNode, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind,
24 SelfParamKind, SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind,
30 /// The main trait to go from untyped `SyntaxNode` to a typed ast. The
31 /// conversion itself has zero runtime cost: ast and syntax nodes have exactly
32 /// the same representation: a pointer to the tree root and a pointer to the
35 fn can_cast(kind: SyntaxKind) -> bool
39 fn cast(syntax: SyntaxNode) -> Option<Self>
43 fn syntax(&self) -> &SyntaxNode;
44 fn clone_for_update(&self) -> Self
48 Self::cast(self.syntax().clone_for_update()).unwrap()
50 fn clone_subtree(&self) -> Self
54 Self::cast(self.syntax().clone_subtree()).unwrap()
58 /// Like `AstNode`, but wraps tokens rather than interior nodes.
60 fn can_cast(token: SyntaxKind) -> bool
64 fn cast(syntax: SyntaxToken) -> Option<Self>
68 fn syntax(&self) -> &SyntaxToken;
70 fn text(&self) -> &str {
75 /// An iterator over `SyntaxNode` children of a particular AST type.
76 #[derive(Debug, Clone)]
77 pub struct AstChildren<N> {
78 inner: SyntaxNodeChildren,
82 impl<N> AstChildren<N> {
83 fn new(parent: &SyntaxNode) -> Self {
84 AstChildren { inner: parent.children(), ph: PhantomData }
88 impl<N: AstNode> Iterator for AstChildren<N> {
90 fn next(&mut self) -> Option<N> {
91 self.inner.find_map(N::cast)
96 use super::{AstChildren, AstNode, SyntaxKind, SyntaxNode, SyntaxToken};
98 pub(super) fn child<N: AstNode>(parent: &SyntaxNode) -> Option<N> {
99 parent.children().find_map(N::cast)
102 pub(super) fn children<N: AstNode>(parent: &SyntaxNode) -> AstChildren<N> {
103 AstChildren::new(parent)
106 pub(super) fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<SyntaxToken> {
107 parent.children_with_tokens().filter_map(|it| it.into_token()).find(|it| it.kind() == kind)
112 fn assert_ast_is_object_safe() {
113 fn _f(_: &dyn AstNode, _: &dyn NameOwner) {}
117 fn test_doc_comment_none() {
118 let file = SourceFile::parse(
126 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
127 assert!(module.doc_comments().doc_comment_text().is_none());
131 fn test_outer_doc_comment_of_items() {
132 let file = SourceFile::parse(
141 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
142 assert_eq!(" doc", module.doc_comments().doc_comment_text().unwrap());
146 fn test_inner_doc_comment_of_items() {
147 let file = SourceFile::parse(
156 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
157 assert!(module.doc_comments().doc_comment_text().is_none());
161 fn test_doc_comment_of_statics() {
162 let file = SourceFile::parse(
165 static LEVELS: i32 = 0;
170 let st = file.syntax().descendants().find_map(Static::cast).unwrap();
171 assert_eq!(" Number of levels", st.doc_comments().doc_comment_text().unwrap());
175 fn test_doc_comment_preserves_indents() {
176 let file = SourceFile::parse(
189 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
191 " doc1\n ```\n fn foo() {\n // ...\n }\n ```",
192 module.doc_comments().doc_comment_text().unwrap()
197 fn test_doc_comment_preserves_newlines() {
198 let file = SourceFile::parse(
209 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
210 assert_eq!(" this\n is\n mod\n foo", module.doc_comments().doc_comment_text().unwrap());
214 fn test_doc_comment_single_line_block_strips_suffix() {
215 let file = SourceFile::parse(
217 /** this is mod foo*/
223 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
224 assert_eq!(" this is mod foo", module.doc_comments().doc_comment_text().unwrap());
228 fn test_doc_comment_single_line_block_strips_suffix_whitespace() {
229 let file = SourceFile::parse(
231 /** this is mod foo */
237 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
238 assert_eq!(" this is mod foo ", module.doc_comments().doc_comment_text().unwrap());
242 fn test_doc_comment_multi_line_block_strips_suffix() {
243 let file = SourceFile::parse(
255 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
257 "\n this\n is\n mod foo\n ",
258 module.doc_comments().doc_comment_text().unwrap()
263 fn test_comments_preserve_trailing_whitespace() {
264 let file = SourceFile::parse(
265 "\n/// Representation of a Realm. \n/// In the specification these are called Realm Records.\nstruct Realm {}",
269 let def = file.syntax().descendants().find_map(Struct::cast).unwrap();
271 " Representation of a Realm. \n In the specification these are called Realm Records.",
272 def.doc_comments().doc_comment_text().unwrap()
277 fn test_four_slash_line_comment() {
278 let file = SourceFile::parse(
280 //// too many slashes to be a doc comment
287 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
288 assert_eq!(" doc comment", module.doc_comments().doc_comment_text().unwrap());
292 fn test_where_predicates() {
293 fn assert_bound(text: &str, bound: Option<TypeBound>) {
294 assert_eq!(text, bound.unwrap().syntax().text().to_string());
297 let file = SourceFile::parse(
301 T: Clone + Copy + Debug + 'static,
303 Iterator::Item: 'a + Debug,
304 Iterator::Item: Debug + 'a,
305 <T as Iterator>::Item: Debug + 'a,
306 for<'a> F: Fn(&'a str)
312 let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap();
314 let mut predicates = where_clause.predicates();
316 let pred = predicates.next().unwrap();
317 let mut bounds = pred.type_bound_list().unwrap().bounds();
319 assert!(pred.for_token().is_none());
320 assert!(pred.generic_param_list().is_none());
321 assert_eq!("T", pred.ty().unwrap().syntax().text().to_string());
322 assert_bound("Clone", bounds.next());
323 assert_bound("Copy", bounds.next());
324 assert_bound("Debug", bounds.next());
325 assert_bound("'static", bounds.next());
327 let pred = predicates.next().unwrap();
328 let mut bounds = pred.type_bound_list().unwrap().bounds();
330 assert_eq!("'a", pred.lifetime().unwrap().lifetime_ident_token().unwrap().text());
332 assert_bound("'b", bounds.next());
333 assert_bound("'c", bounds.next());
335 let pred = predicates.next().unwrap();
336 let mut bounds = pred.type_bound_list().unwrap().bounds();
338 assert_eq!("Iterator::Item", pred.ty().unwrap().syntax().text().to_string());
339 assert_bound("'a", bounds.next());
341 let pred = predicates.next().unwrap();
342 let mut bounds = pred.type_bound_list().unwrap().bounds();
344 assert_eq!("Iterator::Item", pred.ty().unwrap().syntax().text().to_string());
345 assert_bound("Debug", bounds.next());
346 assert_bound("'a", bounds.next());
348 let pred = predicates.next().unwrap();
349 let mut bounds = pred.type_bound_list().unwrap().bounds();
351 assert_eq!("<T as Iterator>::Item", pred.ty().unwrap().syntax().text().to_string());
352 assert_bound("Debug", bounds.next());
353 assert_bound("'a", bounds.next());
355 let pred = predicates.next().unwrap();
356 let mut bounds = pred.type_bound_list().unwrap().bounds();
358 assert!(pred.for_token().is_some());
359 assert_eq!("<'a>", pred.generic_param_list().unwrap().syntax().text().to_string());
360 assert_eq!("F", pred.ty().unwrap().syntax().text().to_string());
361 assert_bound("Fn(&'a str)", bounds.next());