aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax/src')
-rw-r--r--crates/syntax/src/ast/edit.rs78
-rw-r--r--crates/syntax/src/ast/make.rs27
2 files changed, 99 insertions, 6 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 060b20966..8b1c65dd6 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
51fn make_multiline<N>(node: N) -> N 64fn make_multiline<N>(node: N) -> N
@@ -260,16 +273,16 @@ impl ast::Path {
260 273
261impl ast::PathSegment { 274impl ast::PathSegment {
262 #[must_use] 275 #[must_use]
263 pub fn with_type_args(&self, type_args: ast::GenericArgList) -> ast::PathSegment { 276 pub fn with_generic_args(&self, type_args: ast::GenericArgList) -> ast::PathSegment {
264 self._with_type_args(type_args, false) 277 self._with_generic_args(type_args, false)
265 } 278 }
266 279
267 #[must_use] 280 #[must_use]
268 pub fn with_turbo_fish(&self, type_args: ast::GenericArgList) -> ast::PathSegment { 281 pub fn with_turbo_fish(&self, type_args: ast::GenericArgList) -> ast::PathSegment {
269 self._with_type_args(type_args, true) 282 self._with_generic_args(type_args, true)
270 } 283 }
271 284
272 fn _with_type_args(&self, type_args: ast::GenericArgList, turbo: bool) -> ast::PathSegment { 285 fn _with_generic_args(&self, type_args: ast::GenericArgList, turbo: bool) -> ast::PathSegment {
273 if let Some(old) = self.generic_arg_list() { 286 if let Some(old) = self.generic_arg_list() {
274 return self.replace_children( 287 return self.replace_children(
275 single_node(old.syntax().clone()), 288 single_node(old.syntax().clone()),
@@ -459,6 +472,61 @@ impl ast::MatchArmList {
459 } 472 }
460} 473}
461 474
475impl ast::GenericParamList {
476 #[must_use]
477 pub fn append_params(
478 &self,
479 params: impl IntoIterator<Item = ast::GenericParam>,
480 ) -> ast::GenericParamList {
481 let mut res = self.clone();
482 params.into_iter().for_each(|it| res = res.append_param(it));
483 res
484 }
485
486 #[must_use]
487 pub fn append_param(&self, item: ast::GenericParam) -> ast::GenericParamList {
488 let space = tokens::single_space();
489
490 let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new();
491 if self.generic_params().next().is_some() {
492 to_insert.push(space.into());
493 }
494 to_insert.push(item.syntax().clone().into());
495
496 macro_rules! after_l_angle {
497 () => {{
498 let anchor = match self.l_angle_token() {
499 Some(it) => it.into(),
500 None => return self.clone(),
501 };
502 InsertPosition::After(anchor)
503 }};
504 }
505
506 macro_rules! after_field {
507 ($anchor:expr) => {
508 if let Some(comma) = $anchor
509 .syntax()
510 .siblings_with_tokens(Direction::Next)
511 .find(|it| it.kind() == T![,])
512 {
513 InsertPosition::After(comma)
514 } else {
515 to_insert.insert(0, make::token(T![,]).into());
516 InsertPosition::After($anchor.syntax().clone().into())
517 }
518 };
519 };
520
521 let position = match self.generic_params().last() {
522 Some(it) => after_field!(it),
523 None => after_l_angle!(),
524 };
525
526 self.insert_children(position, to_insert)
527 }
528}
529
462#[must_use] 530#[must_use]
463pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N { 531pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N {
464 N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap() 532 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 c2c938ad1..25e8a359d 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -294,6 +294,21 @@ pub fn param_list(pats: impl IntoIterator<Item = ast::Param>) -> ast::ParamList
294 ast_from_text(&format!("fn f({}) {{ }}", args)) 294 ast_from_text(&format!("fn f({}) {{ }}", args))
295} 295}
296 296
297pub fn generic_param(name: String, ty: Option<ast::TypeBoundList>) -> ast::GenericParam {
298 let bound = match ty {
299 Some(it) => format!(": {}", it),
300 None => String::new(),
301 };
302 ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound))
303}
304
305pub fn generic_param_list(
306 pats: impl IntoIterator<Item = ast::GenericParam>,
307) -> ast::GenericParamList {
308 let args = pats.into_iter().join(", ");
309 ast_from_text(&format!("fn f<{}>() {{ }}", args))
310}
311
297pub fn visibility_pub_crate() -> ast::Visibility { 312pub fn visibility_pub_crate() -> ast::Visibility {
298 ast_from_text("pub(crate) struct S") 313 ast_from_text("pub(crate) struct S")
299} 314}
@@ -339,7 +354,7 @@ pub mod tokens {
339 use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken}; 354 use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken};
340 355
341 pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = 356 pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
342 Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;")); 357 Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;\n\n"));
343 358
344 pub fn single_space() -> SyntaxToken { 359 pub fn single_space() -> SyntaxToken {
345 SOURCE_FILE 360 SOURCE_FILE
@@ -379,6 +394,16 @@ pub mod tokens {
379 .unwrap() 394 .unwrap()
380 } 395 }
381 396
397 pub fn blank_line() -> SyntaxToken {
398 SOURCE_FILE
399 .tree()
400 .syntax()
401 .descendants_with_tokens()
402 .filter_map(|it| it.into_token())
403 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n\n")
404 .unwrap()
405 }
406
382 pub struct WsBuilder(SourceFile); 407 pub struct WsBuilder(SourceFile);
383 408
384 impl WsBuilder { 409 impl WsBuilder {