Skip to content

Commit 0e510d9

Browse files
committed
add GetOrCreateWhereClause subtrait in edit to provide get_or_create_where_clause
1 parent 3faa0e1 commit 0e510d9

3 files changed

Lines changed: 112 additions & 54 deletions

File tree

crates/ide-assists/src/handlers/move_bounds.rs

Lines changed: 10 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use either::Either;
22
use syntax::{
3-
ast::{self, AstNode, HasGenericParams, HasName, HasTypeBounds, syntax_factory::SyntaxFactory},
3+
ast::{self, AstNode, HasName, HasTypeBounds, syntax_factory::SyntaxFactory},
44
match_ast,
5-
syntax_editor::{Position, Removable},
5+
syntax_editor::{GetOrCreateWhereClause, Removable},
66
};
77

88
use crate::{AssistContext, AssistId, Assists};
@@ -53,61 +53,18 @@ pub(crate) fn move_bounds_to_where_clause(
5353
.filter_map(|param| build_predicate(param, &make))
5454
.collect();
5555

56-
let existing_where: Option<ast::WhereClause> = match_ast! {
56+
match_ast! {
5757
match (&parent) {
58-
ast::Fn(it) => it.where_clause(),
59-
ast::Trait(it) => it.where_clause(),
60-
ast::Impl(it) => it.where_clause(),
61-
ast::Enum(it) => it.where_clause(),
62-
ast::Struct(it) => it.where_clause(),
63-
ast::TypeAlias(it) => it.where_clause(),
64-
_ => None,
58+
ast::Fn(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
59+
ast::Trait(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
60+
ast::Impl(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
61+
ast::Enum(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
62+
ast::Struct(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
63+
ast::TypeAlias(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
64+
_ => return,
6565
}
6666
};
6767

68-
let all_preds = existing_where.iter().flat_map(|wc| wc.predicates()).chain(new_preds);
69-
let new_where = make.where_clause(all_preds);
70-
71-
if let Some(existing) = &existing_where {
72-
edit.replace(existing.syntax(), new_where.syntax());
73-
} else {
74-
let pos: Option<Position> = match_ast! {
75-
match (&parent) {
76-
ast::Fn(it) => it.ret_type()
77-
.map(|t| Position::after(t.syntax()))
78-
.or_else(|| it.param_list().map(|t| Position::after(t.syntax()))),
79-
ast::Trait(it) => it.generic_param_list()
80-
.map(|t| Position::after(t.syntax()))
81-
.or_else(|| it.name().map(|t| Position::after(t.syntax()))),
82-
ast::Impl(it) => it.self_ty()
83-
.map(|t| Position::after(t.syntax())),
84-
ast::Enum(it) => it.generic_param_list()
85-
.map(|t| Position::after(t.syntax()))
86-
.or_else(|| it.name().map(|t| Position::after(t.syntax()))),
87-
ast::Struct(it) => it.field_list()
88-
.and_then(|fl| match fl {
89-
ast::FieldList::TupleFieldList(it) => {
90-
Some(Position::after(it.syntax()))
91-
}
92-
ast::FieldList::RecordFieldList(_) => None,
93-
})
94-
.or_else(|| it.generic_param_list()
95-
.map(|t| Position::after(t.syntax())))
96-
.or_else(|| it.name().map(|t| Position::after(t.syntax()))),
97-
ast::TypeAlias(it) => it.generic_param_list()
98-
.map(|t| Position::after(t.syntax()))
99-
.or_else(|| it.name().map(|t| Position::after(t.syntax()))),
100-
_ => None,
101-
}
102-
};
103-
if let Some(pos) = pos {
104-
edit.insert_all(
105-
pos,
106-
vec![make.whitespace(" ").into(), new_where.syntax().clone().into()],
107-
);
108-
}
109-
}
110-
11168
for generic_param in type_param_list.generic_params() {
11269
let param: &dyn HasTypeBounds = match &generic_param {
11370
ast::GenericParam::TypeParam(t) => t,

crates/syntax/src/syntax_editor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ mod edit_algo;
2020
mod edits;
2121
mod mapping;
2222

23-
pub use edits::Removable;
23+
pub use edits::{GetOrCreateWhereClause, Removable};
2424
pub use mapping::{SyntaxMapping, SyntaxMappingBuilder};
2525

2626
#[derive(Debug)]

crates/syntax/src/syntax_editor/edits.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,107 @@ use crate::{
1010
syntax_editor::{Position, SyntaxEditor},
1111
};
1212

13+
pub trait GetOrCreateWhereClause: ast::HasGenericParams {
14+
fn where_clause_position(&self) -> Option<Position>;
15+
16+
fn get_or_create_where_clause(
17+
&self,
18+
editor: &mut SyntaxEditor,
19+
make: &SyntaxFactory,
20+
new_preds: impl Iterator<Item = ast::WherePred>,
21+
) {
22+
let existing = self.where_clause();
23+
let all_preds: Vec<_> =
24+
existing.iter().flat_map(|wc| wc.predicates()).chain(new_preds).collect();
25+
let new_where = make.where_clause(all_preds);
26+
27+
if let Some(existing) = &existing {
28+
editor.replace(existing.syntax(), new_where.syntax());
29+
} else if let Some(pos) = self.where_clause_position() {
30+
editor.insert_all(
31+
pos,
32+
vec![make.whitespace(" ").into(), new_where.syntax().clone().into()],
33+
);
34+
}
35+
}
36+
}
37+
38+
impl GetOrCreateWhereClause for ast::Fn {
39+
fn where_clause_position(&self) -> Option<Position> {
40+
if let Some(ty) = self.ret_type() {
41+
Some(Position::after(ty.syntax()))
42+
} else if let Some(param_list) = self.param_list() {
43+
Some(Position::after(param_list.syntax()))
44+
} else {
45+
Some(Position::last_child_of(self.syntax()))
46+
}
47+
}
48+
}
49+
50+
impl GetOrCreateWhereClause for ast::Impl {
51+
fn where_clause_position(&self) -> Option<Position> {
52+
if let Some(ty) = self.self_ty() {
53+
Some(Position::after(ty.syntax()))
54+
} else {
55+
Some(Position::last_child_of(self.syntax()))
56+
}
57+
}
58+
}
59+
60+
impl GetOrCreateWhereClause for ast::Trait {
61+
fn where_clause_position(&self) -> Option<Position> {
62+
if let Some(gpl) = self.generic_param_list() {
63+
Some(Position::after(gpl.syntax()))
64+
} else if let Some(name) = self.name() {
65+
Some(Position::after(name.syntax()))
66+
} else {
67+
Some(Position::last_child_of(self.syntax()))
68+
}
69+
}
70+
}
71+
72+
impl GetOrCreateWhereClause for ast::TypeAlias {
73+
fn where_clause_position(&self) -> Option<Position> {
74+
if let Some(gpl) = self.generic_param_list() {
75+
Some(Position::after(gpl.syntax()))
76+
} else if let Some(name) = self.name() {
77+
Some(Position::after(name.syntax()))
78+
} else {
79+
Some(Position::last_child_of(self.syntax()))
80+
}
81+
}
82+
}
83+
84+
impl GetOrCreateWhereClause for ast::Struct {
85+
fn where_clause_position(&self) -> Option<Position> {
86+
let tfl = self.field_list().and_then(|fl| match fl {
87+
ast::FieldList::RecordFieldList(_) => None,
88+
ast::FieldList::TupleFieldList(it) => Some(it),
89+
});
90+
if let Some(tfl) = tfl {
91+
Some(Position::after(tfl.syntax()))
92+
} else if let Some(gpl) = self.generic_param_list() {
93+
Some(Position::after(gpl.syntax()))
94+
} else if let Some(name) = self.name() {
95+
Some(Position::after(name.syntax()))
96+
} else {
97+
Some(Position::last_child_of(self.syntax()))
98+
}
99+
}
100+
}
101+
102+
impl GetOrCreateWhereClause for ast::Enum {
103+
fn where_clause_position(&self) -> Option<Position> {
104+
if let Some(gpl) = self.generic_param_list() {
105+
Some(Position::after(gpl.syntax()))
106+
} else if let Some(name) = self.name() {
107+
Some(Position::after(name.syntax()))
108+
} else {
109+
Some(Position::last_child_of(self.syntax()))
110+
}
111+
}
112+
}
113+
13114
impl SyntaxEditor {
14115
/// Adds a new generic param to the function using `SyntaxEditor`
15116
pub fn add_generic_param(&mut self, function: &Fn, new_param: GenericParam) {

0 commit comments

Comments
 (0)