Skip to content

Commit 4e50efc

Browse files
committed
Strongly-typed generic methods for editing nodes
1 parent 12c952f commit 4e50efc

File tree

1 file changed

+49
-47
lines changed

1 file changed

+49
-47
lines changed

crates/ra_syntax/src/ast/edit.rs

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl ast::BinExpr {
2323
pub fn replace_op(&self, op: SyntaxKind) -> Option<ast::BinExpr> {
2424
let op_node: SyntaxElement = self.op_details()?.0.into();
2525
let to_insert: Option<SyntaxElement> = Some(make::token(op).into());
26-
Some(replace_children(self, single_node(op_node), to_insert))
26+
Some(self.replace_children(single_node(op_node), to_insert))
2727
}
2828
}
2929

@@ -39,10 +39,10 @@ impl ast::FnDef {
3939
} else {
4040
to_insert.push(make::tokens::single_space().into());
4141
to_insert.push(body.syntax().clone().into());
42-
return insert_children(self, InsertPosition::Last, to_insert);
42+
return self.insert_children(InsertPosition::Last, to_insert);
4343
};
4444
to_insert.push(body.syntax().clone().into());
45-
replace_children(self, single_node(old_body_or_semi), to_insert)
45+
self.replace_children(single_node(old_body_or_semi), to_insert)
4646
}
4747
}
4848

@@ -75,7 +75,7 @@ impl ast::ItemList {
7575
let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
7676
let to_insert: ArrayVec<[SyntaxElement; 2]> =
7777
[ws.ws().into(), item.syntax().clone().into()].into();
78-
insert_children(self, position, to_insert)
78+
self.insert_children(position, to_insert)
7979
}
8080

8181
fn l_curly(&self) -> Option<SyntaxElement> {
@@ -106,8 +106,8 @@ impl ast::ItemList {
106106
let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
107107
let to_insert = iter::once(ws.ws().into());
108108
match existing_ws {
109-
None => insert_children(self, InsertPosition::After(l_curly), to_insert),
110-
Some(ws) => replace_children(self, single_node(ws), to_insert),
109+
None => self.insert_children(InsertPosition::After(l_curly), to_insert),
110+
Some(ws) => self.replace_children(single_node(ws), to_insert),
111111
}
112112
}
113113
}
@@ -184,7 +184,7 @@ impl ast::RecordFieldList {
184184
InsertPosition::After(anchor) => after_field!(anchor),
185185
};
186186

187-
insert_children(self, position, to_insert)
187+
self.insert_children(position, to_insert)
188188
}
189189

190190
fn l_curly(&self) -> Option<SyntaxElement> {
@@ -203,16 +203,15 @@ impl ast::TypeParam {
203203
Some(it) => it.syntax().clone().into(),
204204
None => colon.clone().into(),
205205
};
206-
replace_children(self, colon.into()..=end, iter::empty())
206+
self.replace_children(colon.into()..=end, iter::empty())
207207
}
208208
}
209209

210210
impl ast::Path {
211211
#[must_use]
212212
pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path {
213213
if let Some(old) = self.segment() {
214-
return replace_children(
215-
self,
214+
return self.replace_children(
216215
single_node(old.syntax().clone()),
217216
iter::once(segment.syntax().clone().into()),
218217
);
@@ -234,8 +233,7 @@ impl ast::PathSegment {
234233

235234
fn _with_type_args(&self, type_args: ast::TypeArgList, turbo: bool) -> ast::PathSegment {
236235
if let Some(old) = self.type_arg_list() {
237-
return replace_children(
238-
self,
236+
return self.replace_children(
239237
single_node(old.syntax().clone()),
240238
iter::once(type_args.syntax().clone().into()),
241239
);
@@ -245,15 +243,15 @@ impl ast::PathSegment {
245243
to_insert.push(make::token(T![::]).into());
246244
}
247245
to_insert.push(type_args.syntax().clone().into());
248-
insert_children(self, InsertPosition::Last, to_insert)
246+
self.insert_children(InsertPosition::Last, to_insert)
249247
}
250248
}
251249

252250
impl ast::UseItem {
253251
#[must_use]
254252
pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::UseItem {
255253
if let Some(old) = self.use_tree() {
256-
return replace_descendants(self, iter::once((old, use_tree)));
254+
return self.replace_descendants(iter::once((old, use_tree)));
257255
}
258256
self.clone()
259257
}
@@ -263,15 +261,15 @@ impl ast::UseTree {
263261
#[must_use]
264262
pub fn with_path(&self, path: ast::Path) -> ast::UseTree {
265263
if let Some(old) = self.path() {
266-
return replace_descendants(self, iter::once((old, path)));
264+
return self.replace_descendants(iter::once((old, path)));
267265
}
268266
self.clone()
269267
}
270268

271269
#[must_use]
272270
pub fn with_use_tree_list(&self, use_tree_list: ast::UseTreeList) -> ast::UseTree {
273271
if let Some(old) = self.use_tree_list() {
274-
return replace_descendants(self, iter::once((old, use_tree_list)));
272+
return self.replace_descendants(iter::once((old, use_tree_list)));
275273
}
276274
self.clone()
277275
}
@@ -295,19 +293,6 @@ fn strip_attrs_and_docs_inner(mut node: SyntaxNode) -> SyntaxNode {
295293
node
296294
}
297295

298-
#[must_use]
299-
pub fn replace_descendants<N: AstNode, D: AstNode>(
300-
parent: &N,
301-
replacement_map: impl IntoIterator<Item = (D, D)>,
302-
) -> N {
303-
let map = replacement_map
304-
.into_iter()
305-
.map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into()))
306-
.collect::<FxHashMap<SyntaxElement, _>>();
307-
let new_syntax = algo::replace_descendants(parent.syntax(), |n| map.get(n).cloned());
308-
N::cast(new_syntax).unwrap()
309-
}
310-
311296
#[derive(Debug, Clone, Copy)]
312297
pub struct IndentLevel(pub u8);
313298

@@ -411,31 +396,48 @@ fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
411396
iter::successors(Some(token), |token| token.prev_token())
412397
}
413398

414-
#[must_use]
415-
fn insert_children<N: AstNode>(
416-
parent: &N,
417-
position: InsertPosition<SyntaxElement>,
418-
to_insert: impl IntoIterator<Item = SyntaxElement>,
419-
) -> N {
420-
let new_syntax = algo::insert_children(parent.syntax(), position, to_insert);
421-
N::cast(new_syntax).unwrap()
399+
pub trait AstNodeEdit: AstNode + Sized {
400+
#[must_use]
401+
fn insert_children(
402+
&self,
403+
position: InsertPosition<SyntaxElement>,
404+
to_insert: impl IntoIterator<Item = SyntaxElement>,
405+
) -> Self {
406+
let new_syntax = algo::insert_children(self.syntax(), position, to_insert);
407+
Self::cast(new_syntax).unwrap()
408+
}
409+
410+
#[must_use]
411+
fn replace_children(
412+
&self,
413+
to_replace: RangeInclusive<SyntaxElement>,
414+
to_insert: impl IntoIterator<Item = SyntaxElement>,
415+
) -> Self {
416+
let new_syntax = algo::replace_children(self.syntax(), to_replace, to_insert);
417+
Self::cast(new_syntax).unwrap()
418+
}
419+
420+
#[must_use]
421+
fn replace_descendants<D: AstNode>(
422+
&self,
423+
replacement_map: impl IntoIterator<Item = (D, D)>,
424+
) -> Self {
425+
let map = replacement_map
426+
.into_iter()
427+
.map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into()))
428+
.collect::<FxHashMap<SyntaxElement, _>>();
429+
let new_syntax = algo::replace_descendants(self.syntax(), |n| map.get(n).cloned());
430+
Self::cast(new_syntax).unwrap()
431+
}
422432
}
423433

434+
impl<N: AstNode> AstNodeEdit for N {}
435+
424436
fn single_node(element: impl Into<SyntaxElement>) -> RangeInclusive<SyntaxElement> {
425437
let element = element.into();
426438
element.clone()..=element
427439
}
428440

429-
#[must_use]
430-
fn replace_children<N: AstNode>(
431-
parent: &N,
432-
to_replace: RangeInclusive<SyntaxElement>,
433-
to_insert: impl IntoIterator<Item = SyntaxElement>,
434-
) -> N {
435-
let new_syntax = algo::replace_children(parent.syntax(), to_replace, to_insert);
436-
N::cast(new_syntax).unwrap()
437-
}
438-
439441
#[test]
440442
fn test_increase_indent() {
441443
let arm_list = {

0 commit comments

Comments
 (0)