diff options
Diffstat (limited to 'crates/syntax')
-rw-r--r-- | crates/syntax/src/ast/edit.rs | 95 | ||||
-rw-r--r-- | crates/syntax/src/ast/make.rs | 50 | ||||
-rw-r--r-- | crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast (renamed from crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast) | 0 | ||||
-rw-r--r-- | crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs (renamed from crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs) | 0 | ||||
-rw-r--r-- | crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast (renamed from crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast) | 0 | ||||
-rw-r--r-- | crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs (renamed from crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs) | 0 |
6 files changed, 125 insertions, 20 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 060b20966..dda0a0319 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -13,7 +13,7 @@ use crate::{ | |||
13 | ast::{ | 13 | ast::{ |
14 | self, | 14 | self, |
15 | make::{self, tokens}, | 15 | make::{self, tokens}, |
16 | AstNode, TypeBoundsOwner, | 16 | AstNode, GenericParamsOwner, NameOwner, TypeBoundsOwner, |
17 | }, | 17 | }, |
18 | AstToken, Direction, InsertPosition, SmolStr, SyntaxElement, SyntaxKind, | 18 | AstToken, Direction, InsertPosition, SmolStr, SyntaxElement, SyntaxKind, |
19 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | 19 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, |
@@ -46,6 +46,19 @@ impl ast::Fn { | |||
46 | to_insert.push(body.syntax().clone().into()); | 46 | to_insert.push(body.syntax().clone().into()); |
47 | self.replace_children(single_node(old_body_or_semi), to_insert) | 47 | self.replace_children(single_node(old_body_or_semi), to_insert) |
48 | } | 48 | } |
49 | |||
50 | #[must_use] | ||
51 | pub fn with_generic_param_list(&self, generic_args: ast::GenericParamList) -> ast::Fn { | ||
52 | if let Some(old) = self.generic_param_list() { | ||
53 | return self.replace_descendant(old, generic_args); | ||
54 | } | ||
55 | |||
56 | let anchor = self.name().expect("The function must have a name").syntax().clone(); | ||
57 | |||
58 | let mut to_insert: ArrayVec<[SyntaxElement; 1]> = ArrayVec::new(); | ||
59 | to_insert.push(generic_args.syntax().clone().into()); | ||
60 | self.insert_children(InsertPosition::After(anchor.into()), to_insert) | ||
61 | } | ||
49 | } | 62 | } |
50 | 63 | ||
51 | fn make_multiline<N>(node: N) -> N | 64 | fn make_multiline<N>(node: N) -> N |
@@ -80,6 +93,22 @@ where | |||
80 | } | 93 | } |
81 | } | 94 | } |
82 | 95 | ||
96 | impl ast::Impl { | ||
97 | #[must_use] | ||
98 | pub fn with_assoc_item_list(&self, items: ast::AssocItemList) -> ast::Impl { | ||
99 | let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); | ||
100 | if let Some(old_items) = self.assoc_item_list() { | ||
101 | let to_replace: SyntaxElement = old_items.syntax().clone().into(); | ||
102 | to_insert.push(items.syntax().clone().into()); | ||
103 | self.replace_children(single_node(to_replace), to_insert) | ||
104 | } else { | ||
105 | to_insert.push(make::tokens::single_space().into()); | ||
106 | to_insert.push(items.syntax().clone().into()); | ||
107 | self.insert_children(InsertPosition::Last, to_insert) | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
83 | impl ast::AssocItemList { | 112 | impl ast::AssocItemList { |
84 | #[must_use] | 113 | #[must_use] |
85 | pub fn append_items( | 114 | pub fn append_items( |
@@ -260,16 +289,16 @@ impl ast::Path { | |||
260 | 289 | ||
261 | impl ast::PathSegment { | 290 | impl ast::PathSegment { |
262 | #[must_use] | 291 | #[must_use] |
263 | pub fn with_type_args(&self, type_args: ast::GenericArgList) -> ast::PathSegment { | 292 | pub fn with_generic_args(&self, type_args: ast::GenericArgList) -> ast::PathSegment { |
264 | self._with_type_args(type_args, false) | 293 | self._with_generic_args(type_args, false) |
265 | } | 294 | } |
266 | 295 | ||
267 | #[must_use] | 296 | #[must_use] |
268 | pub fn with_turbo_fish(&self, type_args: ast::GenericArgList) -> ast::PathSegment { | 297 | pub fn with_turbo_fish(&self, type_args: ast::GenericArgList) -> ast::PathSegment { |
269 | self._with_type_args(type_args, true) | 298 | self._with_generic_args(type_args, true) |
270 | } | 299 | } |
271 | 300 | ||
272 | fn _with_type_args(&self, type_args: ast::GenericArgList, turbo: bool) -> ast::PathSegment { | 301 | fn _with_generic_args(&self, type_args: ast::GenericArgList, turbo: bool) -> ast::PathSegment { |
273 | if let Some(old) = self.generic_arg_list() { | 302 | if let Some(old) = self.generic_arg_list() { |
274 | return self.replace_children( | 303 | return self.replace_children( |
275 | single_node(old.syntax().clone()), | 304 | single_node(old.syntax().clone()), |
@@ -334,6 +363,7 @@ impl ast::UseTree { | |||
334 | self.clone() | 363 | self.clone() |
335 | } | 364 | } |
336 | 365 | ||
366 | /// Splits off the given prefix, making it the path component of the use tree, appending the rest of the path to all UseTreeList items. | ||
337 | #[must_use] | 367 | #[must_use] |
338 | pub fn split_prefix(&self, prefix: &ast::Path) -> ast::UseTree { | 368 | pub fn split_prefix(&self, prefix: &ast::Path) -> ast::UseTree { |
339 | let suffix = if self.path().as_ref() == Some(prefix) && self.use_tree_list().is_none() { | 369 | let suffix = if self.path().as_ref() == Some(prefix) && self.use_tree_list().is_none() { |
@@ -459,6 +489,61 @@ impl ast::MatchArmList { | |||
459 | } | 489 | } |
460 | } | 490 | } |
461 | 491 | ||
492 | impl ast::GenericParamList { | ||
493 | #[must_use] | ||
494 | pub fn append_params( | ||
495 | &self, | ||
496 | params: impl IntoIterator<Item = ast::GenericParam>, | ||
497 | ) -> ast::GenericParamList { | ||
498 | let mut res = self.clone(); | ||
499 | params.into_iter().for_each(|it| res = res.append_param(it)); | ||
500 | res | ||
501 | } | ||
502 | |||
503 | #[must_use] | ||
504 | pub fn append_param(&self, item: ast::GenericParam) -> ast::GenericParamList { | ||
505 | let space = tokens::single_space(); | ||
506 | |||
507 | let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new(); | ||
508 | if self.generic_params().next().is_some() { | ||
509 | to_insert.push(space.into()); | ||
510 | } | ||
511 | to_insert.push(item.syntax().clone().into()); | ||
512 | |||
513 | macro_rules! after_l_angle { | ||
514 | () => {{ | ||
515 | let anchor = match self.l_angle_token() { | ||
516 | Some(it) => it.into(), | ||
517 | None => return self.clone(), | ||
518 | }; | ||
519 | InsertPosition::After(anchor) | ||
520 | }}; | ||
521 | } | ||
522 | |||
523 | macro_rules! after_field { | ||
524 | ($anchor:expr) => { | ||
525 | if let Some(comma) = $anchor | ||
526 | .syntax() | ||
527 | .siblings_with_tokens(Direction::Next) | ||
528 | .find(|it| it.kind() == T![,]) | ||
529 | { | ||
530 | InsertPosition::After(comma) | ||
531 | } else { | ||
532 | to_insert.insert(0, make::token(T![,]).into()); | ||
533 | InsertPosition::After($anchor.syntax().clone().into()) | ||
534 | } | ||
535 | }; | ||
536 | }; | ||
537 | |||
538 | let position = match self.generic_params().last() { | ||
539 | Some(it) => after_field!(it), | ||
540 | None => after_l_angle!(), | ||
541 | }; | ||
542 | |||
543 | self.insert_children(position, to_insert) | ||
544 | } | ||
545 | } | ||
546 | |||
462 | #[must_use] | 547 | #[must_use] |
463 | pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N { | 548 | pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N { |
464 | N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap() | 549 | N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap() |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 7ba625990..4a0ffcbb0 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -21,6 +21,10 @@ pub fn ty(text: &str) -> ast::Type { | |||
21 | ast_from_text(&format!("impl {} for D {{}};", text)) | 21 | ast_from_text(&format!("impl {} for D {{}};", text)) |
22 | } | 22 | } |
23 | 23 | ||
24 | pub fn assoc_item_list() -> ast::AssocItemList { | ||
25 | ast_from_text("impl C for D {};") | ||
26 | } | ||
27 | |||
24 | pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { | 28 | pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { |
25 | ast_from_text(&format!("use {};", name_ref)) | 29 | ast_from_text(&format!("use {};", name_ref)) |
26 | } | 30 | } |
@@ -33,10 +37,15 @@ pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { | |||
33 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { | 37 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { |
34 | path_from_text(&format!("{}::{}", qual, segment)) | 38 | path_from_text(&format!("{}::{}", qual, segment)) |
35 | } | 39 | } |
40 | // FIXME: make this private | ||
36 | pub fn path_from_text(text: &str) -> ast::Path { | 41 | pub fn path_from_text(text: &str) -> ast::Path { |
37 | ast_from_text(text) | 42 | ast_from_text(text) |
38 | } | 43 | } |
39 | 44 | ||
45 | pub fn glob_use_tree() -> ast::UseTree { | ||
46 | ast_from_text("use *;") | ||
47 | } | ||
48 | |||
40 | pub fn use_tree( | 49 | pub fn use_tree( |
41 | path: ast::Path, | 50 | path: ast::Path, |
42 | use_tree_list: Option<ast::UseTreeList>, | 51 | use_tree_list: Option<ast::UseTreeList>, |
@@ -144,10 +153,6 @@ fn expr_from_text(text: &str) -> ast::Expr { | |||
144 | ast_from_text(&format!("const C: () = {};", text)) | 153 | ast_from_text(&format!("const C: () = {};", text)) |
145 | } | 154 | } |
146 | 155 | ||
147 | pub fn try_expr_from_text(text: &str) -> Option<ast::Expr> { | ||
148 | try_ast_from_text(&format!("const C: () = {};", text)) | ||
149 | } | ||
150 | |||
151 | pub fn condition(expr: ast::Expr, pattern: Option<ast::Pat>) -> ast::Condition { | 156 | pub fn condition(expr: ast::Expr, pattern: Option<ast::Pat>) -> ast::Condition { |
152 | match pattern { | 157 | match pattern { |
153 | None => ast_from_text(&format!("const _: () = while {} {{}};", expr)), | 158 | None => ast_from_text(&format!("const _: () = while {} {{}};", expr)), |
@@ -297,6 +302,21 @@ pub fn param_list(pats: impl IntoIterator<Item = ast::Param>) -> ast::ParamList | |||
297 | ast_from_text(&format!("fn f({}) {{ }}", args)) | 302 | ast_from_text(&format!("fn f({}) {{ }}", args)) |
298 | } | 303 | } |
299 | 304 | ||
305 | pub fn generic_param(name: String, ty: Option<ast::TypeBoundList>) -> ast::GenericParam { | ||
306 | let bound = match ty { | ||
307 | Some(it) => format!(": {}", it), | ||
308 | None => String::new(), | ||
309 | }; | ||
310 | ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound)) | ||
311 | } | ||
312 | |||
313 | pub fn generic_param_list( | ||
314 | pats: impl IntoIterator<Item = ast::GenericParam>, | ||
315 | ) -> ast::GenericParamList { | ||
316 | let args = pats.into_iter().join(", "); | ||
317 | ast_from_text(&format!("fn f<{}>() {{ }}", args)) | ||
318 | } | ||
319 | |||
300 | pub fn visibility_pub_crate() -> ast::Visibility { | 320 | pub fn visibility_pub_crate() -> ast::Visibility { |
301 | ast_from_text("pub(crate) struct S") | 321 | ast_from_text("pub(crate) struct S") |
302 | } | 322 | } |
@@ -332,16 +352,6 @@ fn ast_from_text<N: AstNode>(text: &str) -> N { | |||
332 | node | 352 | node |
333 | } | 353 | } |
334 | 354 | ||
335 | fn try_ast_from_text<N: AstNode>(text: &str) -> Option<N> { | ||
336 | let parse = SourceFile::parse(text); | ||
337 | let node = parse.tree().syntax().descendants().find_map(N::cast)?; | ||
338 | let node = node.syntax().clone(); | ||
339 | let node = unroot(node); | ||
340 | let node = N::cast(node).unwrap(); | ||
341 | assert_eq!(node.syntax().text_range().start(), 0.into()); | ||
342 | Some(node) | ||
343 | } | ||
344 | |||
345 | fn unroot(n: SyntaxNode) -> SyntaxNode { | 355 | fn unroot(n: SyntaxNode) -> SyntaxNode { |
346 | SyntaxNode::new_root(n.green().clone()) | 356 | SyntaxNode::new_root(n.green().clone()) |
347 | } | 357 | } |
@@ -352,7 +362,7 @@ pub mod tokens { | |||
352 | use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken}; | 362 | use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken}; |
353 | 363 | ||
354 | pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = | 364 | pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = |
355 | Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;")); | 365 | Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;\n\n")); |
356 | 366 | ||
357 | pub fn single_space() -> SyntaxToken { | 367 | pub fn single_space() -> SyntaxToken { |
358 | SOURCE_FILE | 368 | SOURCE_FILE |
@@ -392,6 +402,16 @@ pub mod tokens { | |||
392 | .unwrap() | 402 | .unwrap() |
393 | } | 403 | } |
394 | 404 | ||
405 | pub fn blank_line() -> SyntaxToken { | ||
406 | SOURCE_FILE | ||
407 | .tree() | ||
408 | .syntax() | ||
409 | .descendants_with_tokens() | ||
410 | .filter_map(|it| it.into_token()) | ||
411 | .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n\n") | ||
412 | .unwrap() | ||
413 | } | ||
414 | |||
395 | pub struct WsBuilder(SourceFile); | 415 | pub struct WsBuilder(SourceFile); |
396 | 416 | ||
397 | impl WsBuilder { | 417 | impl WsBuilder { |
diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast index 866e60ed8..866e60ed8 100644 --- a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast +++ b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs index da3412fa8..da3412fa8 100644 --- a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs +++ b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast index 925409bdf..925409bdf 100644 --- a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast +++ b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs index 26b1d5f89..26b1d5f89 100644 --- a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs +++ b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs | |||