Skip to content

Commit c9882c8

Browse files
committed
Get a make version working!
1 parent efb4d45 commit c9882c8

File tree

1 file changed

+89
-14
lines changed

1 file changed

+89
-14
lines changed

crates/ide_assists/src/handlers/generate_delegate.rs

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use hir::{self, HasCrate, HirDisplay};
1+
use hir::{self, HasCrate, HasSource, HirDisplay};
22
use syntax::ast::{self, make, AstNode, HasName, HasVisibility};
33

44
use crate::{
55
utils::{find_struct_impl, render_snippet, Cursor},
66
AssistContext, AssistId, AssistKind, Assists, GroupLabel,
77
};
8+
use syntax::ast::edit::AstNodeEdit;
89

910
// Assist: generate_setter
1011
//
@@ -33,6 +34,7 @@ pub(crate) fn generate_delegate(acc: &mut Assists, ctx: &AssistContext) -> Optio
3334
let strukt_name = strukt.name()?;
3435

3536
let field = ctx.find_node_at_offset::<ast::RecordField>()?;
37+
let field_name = field.name()?;
3638
let field_ty = field.ty()?;
3739

3840
let sema_field_ty = ctx.sema.resolve_type(&field_ty)?;
@@ -61,36 +63,62 @@ pub(crate) fn generate_delegate(acc: &mut Assists, ctx: &AssistContext) -> Optio
6163
target,
6264
|builder| {
6365
// make function
64-
let vis = strukt.visibility();
66+
let method_source = match method.source(ctx.db()) {
67+
Some(source) => source.value,
68+
None => return,
69+
};
70+
let method_name = method.name(ctx.db());
71+
let vis = method_source.visibility();
6572
let name = make::name(&method.name(ctx.db()).to_string());
6673
let type_params = None;
67-
let params = make::param_list(None, []);
68-
let body = make::block_expr([], None);
74+
let self_ty = method
75+
.self_param(ctx.db())
76+
.map(|s| s.source(ctx.db()).map(|s| s.value))
77+
.flatten();
78+
let params = make::param_list(self_ty, []);
79+
let tail_expr = make::expr_method_call(
80+
field_from_idents(["self", &field_name.to_string()]).unwrap(),
81+
make::name_ref(&method_name.to_string()),
82+
make::arg_list([]),
83+
);
84+
let body = make::block_expr([], Some(tail_expr));
6985
let ret_type = &method.ret_type(ctx.db()).display(ctx.db()).to_string();
7086
let ret_type = Some(make::ret_type(make::ty(ret_type)));
7187
let is_async = false;
72-
let f = make::fn_(vis, name, type_params, params, body, ret_type, is_async);
88+
let f = make::fn_(vis, name, type_params, params, body, ret_type, is_async)
89+
.indent(ast::edit::IndentLevel(1))
90+
.clone_for_update();
7391

7492
let cursor = Cursor::Before(f.syntax());
7593
let cap = ctx.config.snippet_cap.unwrap(); // FIXME.
7694

95+
// Create or update an impl block, and attach the function to it.
7796
match impl_def {
7897
Some(impl_def) => {
98+
// Remember where in our source our `impl` block lives.
7999
let impl_def = impl_def.clone_for_update();
80100
let old_range = impl_def.syntax().text_range();
101+
102+
// Attach the function to the impl block
81103
let assoc_items = impl_def.get_or_create_assoc_item_list();
82104
assoc_items.add_item(f.clone().into());
105+
106+
// Update the impl block.
83107
let snippet = render_snippet(cap, impl_def.syntax(), cursor);
84108
builder.replace_snippet(cap, old_range, snippet);
85109
}
86110
None => {
111+
// Attach the function to the impl block
87112
let name = &strukt_name.to_string();
88-
let impl_def = make::impl_(make::ext::ident_path(name));
113+
let impl_def = make::impl_(make::ext::ident_path(name)).clone_for_update();
89114
let assoc_items = impl_def.get_or_create_assoc_item_list();
90115
assoc_items.add_item(f.clone().into());
91-
let start_offset = strukt.syntax().text_range().end();
116+
117+
// Insert the impl block.
118+
let offset = strukt.syntax().text_range().end();
92119
let snippet = render_snippet(cap, impl_def.syntax(), cursor);
93-
builder.insert_snippet(cap, start_offset, snippet);
120+
let snippet = format!("\n\n{}", snippet);
121+
builder.insert_snippet(cap, offset, snippet);
94122
}
95123
}
96124
},
@@ -99,35 +127,77 @@ pub(crate) fn generate_delegate(acc: &mut Assists, ctx: &AssistContext) -> Optio
99127
Some(())
100128
}
101129

130+
pub fn field_from_idents<'a>(
131+
parts: impl std::iter::IntoIterator<Item = &'a str>,
132+
) -> Option<ast::Expr> {
133+
let mut iter = parts.into_iter();
134+
let base = make::expr_path(make::ext::ident_path(iter.next()?));
135+
let expr = iter.fold(base, |base, s| make::expr_field(base, s));
136+
Some(expr)
137+
}
138+
102139
#[cfg(test)]
103140
mod tests {
104141
use crate::tests::check_assist;
105142

106143
use super::*;
107144

108145
#[test]
109-
fn test_generate_setter_from_field() {
146+
fn test_generate_delegate_create_impl_block() {
147+
check_assist(
148+
generate_delegate,
149+
r#"
150+
struct Age(u8);
151+
impl Age {
152+
fn age(&self) -> u8 {
153+
self.0
154+
}
155+
}
156+
157+
struct Person {
158+
ag$0e: Age,
159+
}"#,
160+
r#"
161+
struct Age(u8);
162+
impl Age {
163+
fn age(&self) -> u8 {
164+
self.0
165+
}
166+
}
167+
168+
struct Person {
169+
age: Age,
170+
}
171+
172+
impl Person {
173+
$0fn age(&self) -> u8 {
174+
self.age.age()
175+
}
176+
}"#,
177+
);
178+
}
179+
180+
#[test]
181+
fn test_generate_delegate_update_impl_block() {
110182
check_assist(
111183
generate_delegate,
112184
r#"
113185
struct Age(u8);
114186
impl Age {
115187
fn age(&self) -> u8 {
116188
self.0
117-
118189
}
119190
}
120191
121192
struct Person {
122193
ag$0e: Age,
123194
}
124195
125-
impl Person {}
126-
"#,
196+
impl Person {}"#,
127197
r#"
128198
struct Age(u8);
129199
impl Age {
130-
$0fn age(&self) -> u8 {
200+
fn age(&self) -> u8 {
131201
self.0
132202
}
133203
}
@@ -137,7 +207,12 @@ struct Person {
137207
}
138208
139209
impl Person {
140-
fn age(&self) -> u8 {
210+
$0fn age(&self) -> u8 {
211+
self.age.age()
212+
}
213+
}"#,
214+
);
215+
}
141216
self.age.age()
142217
}
143218
}"#,

0 commit comments

Comments
 (0)