Skip to content

Commit a32589f

Browse files
bors[bot]matklad
andauthored
Merge #8837
8837: internal: rewrite assoc item manipulaion to use mutable trees r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 73123a7 + 6c21d04 commit a32589f

File tree

7 files changed

+187
-221
lines changed

7 files changed

+187
-221
lines changed

crates/ide_assists/src/handlers/add_missing_impl_members.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -
6464
// impl Trait for () {
6565
// type X = ();
6666
// fn foo(&self) {}$0
67-
//
6867
// }
6968
// ```
7069
// ->
@@ -195,6 +194,7 @@ impl Foo for S {
195194
fn baz(&self) {
196195
todo!()
197196
}
197+
198198
}"#,
199199
);
200200
}
@@ -231,6 +231,7 @@ impl Foo for S {
231231
fn foo(&self) {
232232
${0:todo!()}
233233
}
234+
234235
}"#,
235236
);
236237
}

crates/ide_assists/src/handlers/generate_new.rs

Lines changed: 99 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use ast::Adt;
21
use itertools::Itertools;
32
use stdx::format_to;
43
use syntax::ast::{self, AstNode, NameOwner, StructKind, VisibilityOwner};
@@ -37,7 +36,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
3736
};
3837

3938
// Return early if we've found an existing new fn
40-
let impl_def = find_struct_impl(&ctx, &Adt::Struct(strukt.clone()), "new")?;
39+
let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), "new")?;
4140

4241
let target = strukt.syntax().text_range();
4342
acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| {
@@ -60,7 +59,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
6059
let start_offset = impl_def
6160
.and_then(|impl_def| find_impl_block_start(impl_def, &mut buf))
6261
.unwrap_or_else(|| {
63-
buf = generate_impl_text(&Adt::Struct(strukt.clone()), &buf);
62+
buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
6463
strukt.syntax().text_range().end()
6564
});
6665

@@ -81,110 +80,142 @@ mod tests {
8180
use super::*;
8281

8382
#[test]
84-
#[rustfmt::skip]
8583
fn test_generate_new() {
86-
// Check output of generation
8784
check_assist(
8885
generate_new,
89-
"struct Foo {$0}",
90-
"struct Foo {}
86+
r#"
87+
struct Foo {$0}
88+
"#,
89+
r#"
90+
struct Foo {}
9191
9292
impl Foo {
9393
fn $0new() -> Self { Self { } }
94-
}",
94+
}
95+
"#,
9596
);
9697
check_assist(
9798
generate_new,
98-
"struct Foo<T: Clone> {$0}",
99-
"struct Foo<T: Clone> {}
99+
r#"
100+
struct Foo<T: Clone> {$0}
101+
"#,
102+
r#"
103+
struct Foo<T: Clone> {}
100104
101105
impl<T: Clone> Foo<T> {
102106
fn $0new() -> Self { Self { } }
103-
}",
107+
}
108+
"#,
104109
);
105110
check_assist(
106111
generate_new,
107-
"struct Foo<'a, T: Foo<'a>> {$0}",
108-
"struct Foo<'a, T: Foo<'a>> {}
112+
r#"
113+
struct Foo<'a, T: Foo<'a>> {$0}
114+
"#,
115+
r#"
116+
struct Foo<'a, T: Foo<'a>> {}
109117
110118
impl<'a, T: Foo<'a>> Foo<'a, T> {
111119
fn $0new() -> Self { Self { } }
112-
}",
120+
}
121+
"#,
113122
);
114123
check_assist(
115124
generate_new,
116-
"struct Foo { baz: String $0}",
117-
"struct Foo { baz: String }
125+
r#"
126+
struct Foo { baz: String $0}
127+
"#,
128+
r#"
129+
struct Foo { baz: String }
118130
119131
impl Foo {
120132
fn $0new(baz: String) -> Self { Self { baz } }
121-
}",
133+
}
134+
"#,
122135
);
123136
check_assist(
124137
generate_new,
125-
"struct Foo { baz: String, qux: Vec<i32> $0}",
126-
"struct Foo { baz: String, qux: Vec<i32> }
138+
r#"
139+
struct Foo { baz: String, qux: Vec<i32> $0}
140+
"#,
141+
r#"
142+
struct Foo { baz: String, qux: Vec<i32> }
127143
128144
impl Foo {
129145
fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
130-
}",
146+
}
147+
"#,
131148
);
149+
}
132150

133-
// Check that visibility modifiers don't get brought in for fields
151+
#[test]
152+
fn check_that_visibility_modifiers_dont_get_brought_in() {
134153
check_assist(
135154
generate_new,
136-
"struct Foo { pub baz: String, pub qux: Vec<i32> $0}",
137-
"struct Foo { pub baz: String, pub qux: Vec<i32> }
155+
r#"
156+
struct Foo { pub baz: String, pub qux: Vec<i32> $0}
157+
"#,
158+
r#"
159+
struct Foo { pub baz: String, pub qux: Vec<i32> }
138160
139161
impl Foo {
140162
fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
141-
}",
163+
}
164+
"#,
142165
);
166+
}
143167

144-
// Check that it reuses existing impls
168+
#[test]
169+
fn check_it_reuses_existing_impls() {
145170
check_assist(
146171
generate_new,
147-
"struct Foo {$0}
172+
r#"
173+
struct Foo {$0}
148174
149175
impl Foo {}
150-
",
151-
"struct Foo {}
176+
"#,
177+
r#"
178+
struct Foo {}
152179
153180
impl Foo {
154181
fn $0new() -> Self { Self { } }
155182
}
156-
",
183+
"#,
157184
);
158185
check_assist(
159186
generate_new,
160-
"struct Foo {$0}
187+
r#"
188+
struct Foo {$0}
161189
162190
impl Foo {
163191
fn qux(&self) {}
164192
}
165-
",
166-
"struct Foo {}
193+
"#,
194+
r#"
195+
struct Foo {}
167196
168197
impl Foo {
169198
fn $0new() -> Self { Self { } }
170199
171200
fn qux(&self) {}
172201
}
173-
",
202+
"#,
174203
);
175204

176205
check_assist(
177206
generate_new,
178-
"struct Foo {$0}
207+
r#"
208+
struct Foo {$0}
179209
180210
impl Foo {
181211
fn qux(&self) {}
182212
fn baz() -> i32 {
183213
5
184214
}
185215
}
186-
",
187-
"struct Foo {}
216+
"#,
217+
r#"
218+
struct Foo {}
188219
189220
impl Foo {
190221
fn $0new() -> Self { Self { } }
@@ -194,67 +225,79 @@ impl Foo {
194225
5
195226
}
196227
}
197-
",
228+
"#,
198229
);
230+
}
199231

200-
// Check visibility of new fn based on struct
232+
#[test]
233+
fn check_visibility_of_new_fn_based_on_struct() {
201234
check_assist(
202235
generate_new,
203-
"pub struct Foo {$0}",
204-
"pub struct Foo {}
236+
r#"
237+
pub struct Foo {$0}
238+
"#,
239+
r#"
240+
pub struct Foo {}
205241
206242
impl Foo {
207243
pub fn $0new() -> Self { Self { } }
208-
}",
244+
}
245+
"#,
209246
);
210247
check_assist(
211248
generate_new,
212-
"pub(crate) struct Foo {$0}",
213-
"pub(crate) struct Foo {}
249+
r#"
250+
pub(crate) struct Foo {$0}
251+
"#,
252+
r#"
253+
pub(crate) struct Foo {}
214254
215255
impl Foo {
216256
pub(crate) fn $0new() -> Self { Self { } }
217-
}",
257+
}
258+
"#,
218259
);
219260
}
220261

221262
#[test]
222263
fn generate_new_not_applicable_if_fn_exists() {
223264
check_assist_not_applicable(
224265
generate_new,
225-
"
266+
r#"
226267
struct Foo {$0}
227268
228269
impl Foo {
229270
fn new() -> Self {
230271
Self
231272
}
232-
}",
273+
}
274+
"#,
233275
);
234276

235277
check_assist_not_applicable(
236278
generate_new,
237-
"
279+
r#"
238280
struct Foo {$0}
239281
240282
impl Foo {
241283
fn New() -> Self {
242284
Self
243285
}
244-
}",
286+
}
287+
"#,
245288
);
246289
}
247290

248291
#[test]
249292
fn generate_new_target() {
250293
check_assist_target(
251294
generate_new,
252-
"
295+
r#"
253296
struct SomeThingIrrelevant;
254297
/// Has a lifetime parameter
255298
struct Foo<'a, T: Foo<'a>> {$0}
256299
struct EvenMoreIrrelevant;
257-
",
300+
"#,
258301
"/// Has a lifetime parameter
259302
struct Foo<'a, T: Foo<'a>> {}",
260303
);
@@ -264,7 +307,7 @@ struct Foo<'a, T: Foo<'a>> {}",
264307
fn test_unrelated_new() {
265308
check_assist(
266309
generate_new,
267-
r##"
310+
r#"
268311
pub struct AstId<N: AstNode> {
269312
file_id: HirFileId,
270313
file_ast_id: FileAstId<N>,
@@ -285,8 +328,9 @@ impl<T> Source<T> {
285328
pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
286329
Source { file_id: self.file_id, ast: f(self.ast) }
287330
}
288-
}"##,
289-
r##"
331+
}
332+
"#,
333+
r#"
290334
pub struct AstId<N: AstNode> {
291335
file_id: HirFileId,
292336
file_ast_id: FileAstId<N>,
@@ -309,7 +353,8 @@ impl<T> Source<T> {
309353
pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
310354
Source { file_id: self.file_id, ast: f(self.ast) }
311355
}
312-
}"##,
356+
}
357+
"#,
313358
);
314359
}
315360
}

crates/ide_assists/src/tests/generated.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ trait Trait {
5050
impl Trait for () {
5151
type X = ();
5252
fn foo(&self) {}$0
53-
5453
}
5554
"#####,
5655
r#####"

crates/ide_assists/src/utils.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,12 @@ pub fn add_trait_assoc_items_to_impl(
128128
sema: &hir::Semantics<ide_db::RootDatabase>,
129129
items: Vec<ast::AssocItem>,
130130
trait_: hir::Trait,
131-
impl_def: ast::Impl,
131+
impl_: ast::Impl,
132132
target_scope: hir::SemanticsScope,
133133
) -> (ast::Impl, ast::AssocItem) {
134-
let impl_item_list = impl_def.assoc_item_list().unwrap_or_else(make::assoc_item_list);
135-
136-
let n_existing_items = impl_item_list.assoc_items().count();
137134
let source_scope = sema.scope_for_def(trait_);
138135
let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
139-
.or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def.clone()));
136+
.or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_.clone()));
140137

141138
let items = items
142139
.into_iter()
@@ -147,13 +144,18 @@ pub fn add_trait_assoc_items_to_impl(
147144
ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()),
148145
_ => it,
149146
})
150-
.map(|it| edit::remove_attrs_and_docs(&it));
151-
152-
let new_impl_item_list = impl_item_list.append_items(items);
153-
let new_impl_def = impl_def.with_assoc_item_list(new_impl_item_list);
154-
let first_new_item =
155-
new_impl_def.assoc_item_list().unwrap().assoc_items().nth(n_existing_items).unwrap();
156-
return (new_impl_def, first_new_item);
147+
.map(|it| edit::remove_attrs_and_docs(&it).clone_subtree().clone_for_update());
148+
149+
let res = impl_.clone_for_update();
150+
let assoc_item_list = res.get_or_create_assoc_item_list();
151+
let mut first_item = None;
152+
for item in items {
153+
if first_item.is_none() {
154+
first_item = Some(item.clone())
155+
}
156+
assoc_item_list.add_item(item)
157+
}
158+
return (res, first_item.unwrap());
157159

158160
fn add_body(fn_def: ast::Fn) -> ast::Fn {
159161
match fn_def.body() {

0 commit comments

Comments
 (0)