@@ -2,9 +2,10 @@ use crate::{Assist, AssistId, AssistCtx, ast_editor::{AstEditor, AstBuilder}};
2
2
3
3
use hir:: { HasSource , db:: HirDatabase } ;
4
4
use ra_syntax:: { SmolStr , TreeArc } ;
5
- use ra_syntax:: ast:: { self , AstNode , FnDef , ImplItem , ImplItemKind , NameOwner } ;
5
+ use ra_syntax:: ast:: { self , AstNode , ImplItem , ImplItemKind , NameOwner } ;
6
6
use ra_db:: FilePosition ;
7
7
8
+ #[ derive( PartialEq ) ]
8
9
enum AddMissingImplMembersMode {
9
10
DefaultMethodsOnly ,
10
11
NoDefaultMethods ,
@@ -45,39 +46,50 @@ fn add_missing_impl_members_inner(
45
46
resolve_target_trait_def ( ctx. db , & analyzer, impl_node) ?
46
47
} ;
47
48
48
- let missing_fns: Vec < _ > = {
49
- let fn_def_opt = |kind| if let ImplItemKind :: FnDef ( def) = kind { Some ( def) } else { None } ;
50
- let def_name = |def| -> Option < & SmolStr > { FnDef :: name ( def) . map ( ast:: Name :: text) } ;
51
-
52
- let trait_items =
53
- trait_def. syntax ( ) . descendants ( ) . find_map ( ast:: ItemList :: cast) ?. impl_items ( ) ;
54
- let impl_items = impl_item_list. impl_items ( ) ;
55
-
56
- let trait_fns = trait_items. map ( ImplItem :: kind) . filter_map ( fn_def_opt) ;
57
- let impl_fns = impl_items. map ( ImplItem :: kind) . filter_map ( fn_def_opt) . collect :: < Vec < _ > > ( ) ;
58
-
59
- trait_fns
60
- . filter ( |t| def_name ( t) . is_some ( ) )
61
- . filter ( |t| match mode {
62
- AddMissingImplMembersMode :: DefaultMethodsOnly => t. body ( ) . is_some ( ) ,
63
- AddMissingImplMembersMode :: NoDefaultMethods => t. body ( ) . is_none ( ) ,
64
- } )
65
- . filter ( |t| impl_fns. iter ( ) . all ( |i| def_name ( i) != def_name ( t) ) )
66
- . collect ( )
49
+ let def_name = |kind| -> Option < & SmolStr > {
50
+ match kind {
51
+ ImplItemKind :: FnDef ( def) => def. name ( ) ,
52
+ ImplItemKind :: TypeAliasDef ( def) => def. name ( ) ,
53
+ ImplItemKind :: ConstDef ( def) => def. name ( ) ,
54
+ }
55
+ . map ( ast:: Name :: text)
67
56
} ;
68
- if missing_fns. is_empty ( ) {
57
+
58
+ let trait_items = trait_def. item_list ( ) ?. impl_items ( ) ;
59
+ let impl_items = impl_item_list. impl_items ( ) . collect :: < Vec < _ > > ( ) ;
60
+
61
+ let missing_items: Vec < _ > = trait_items
62
+ . filter ( |t| def_name ( t. kind ( ) ) . is_some ( ) )
63
+ . filter ( |t| match t. kind ( ) {
64
+ ImplItemKind :: FnDef ( def) => match mode {
65
+ AddMissingImplMembersMode :: DefaultMethodsOnly => def. body ( ) . is_some ( ) ,
66
+ AddMissingImplMembersMode :: NoDefaultMethods => def. body ( ) . is_none ( ) ,
67
+ } ,
68
+ _ => mode == AddMissingImplMembersMode :: NoDefaultMethods ,
69
+ } )
70
+ . filter ( |t| impl_items. iter ( ) . all ( |i| def_name ( i. kind ( ) ) != def_name ( t. kind ( ) ) ) )
71
+ . collect ( ) ;
72
+ if missing_items. is_empty ( ) {
69
73
return None ;
70
74
}
71
75
72
76
ctx. add_action ( AssistId ( assist_id) , label, |edit| {
73
77
let n_existing_items = impl_item_list. impl_items ( ) . count ( ) ;
74
- let fns = missing_fns. into_iter ( ) . map ( add_body_and_strip_docstring) . collect :: < Vec < _ > > ( ) ;
75
-
76
78
let mut ast_editor = AstEditor :: new ( impl_item_list) ;
77
79
if n_existing_items == 0 {
78
80
ast_editor. make_multiline ( ) ;
79
81
}
80
- ast_editor. append_functions ( fns. iter ( ) . map ( |it| & * * it) ) ;
82
+
83
+ for item in missing_items {
84
+ let it = match item. kind ( ) {
85
+ ImplItemKind :: FnDef ( def) => {
86
+ strip_docstring ( ImplItem :: cast ( add_body ( def) . syntax ( ) ) . unwrap ( ) )
87
+ }
88
+ _ => strip_docstring ( item) ,
89
+ } ;
90
+ ast_editor. append_item ( & it)
91
+ }
92
+
81
93
let first_new_item = ast_editor. ast ( ) . impl_items ( ) . nth ( n_existing_items) . unwrap ( ) ;
82
94
let cursor_poisition = first_new_item. syntax ( ) . range ( ) . start ( ) ;
83
95
ast_editor. into_text_edit ( edit. text_edit_builder ( ) ) ;
@@ -88,14 +100,19 @@ fn add_missing_impl_members_inner(
88
100
ctx. build ( )
89
101
}
90
102
91
- fn add_body_and_strip_docstring ( fn_def : & ast:: FnDef ) -> TreeArc < ast:: FnDef > {
103
+ fn strip_docstring ( item : & ast:: ImplItem ) -> TreeArc < ast:: ImplItem > {
104
+ let mut ast_editor = AstEditor :: new ( item) ;
105
+ ast_editor. strip_attrs_and_docs ( ) ;
106
+ ast_editor. ast ( ) . to_owned ( )
107
+ }
108
+
109
+ fn add_body ( fn_def : & ast:: FnDef ) -> TreeArc < ast:: FnDef > {
92
110
let mut ast_editor = AstEditor :: new ( fn_def) ;
93
111
if fn_def. body ( ) . is_none ( ) {
94
112
ast_editor. set_body ( & AstBuilder :: < ast:: Block > :: single_expr (
95
113
& AstBuilder :: < ast:: Expr > :: unimplemented ( ) ,
96
114
) ) ;
97
115
}
98
- ast_editor. strip_attrs_and_docs ( ) ;
99
116
ast_editor. ast ( ) . to_owned ( )
100
117
}
101
118
@@ -126,6 +143,10 @@ mod tests {
126
143
add_missing_impl_members,
127
144
"
128
145
trait Foo {
146
+ type Output;
147
+
148
+ const CONST: usize = 42;
149
+
129
150
fn foo(&self);
130
151
fn bar(&self);
131
152
fn baz(&self);
@@ -139,6 +160,10 @@ impl Foo for S {
139
160
}" ,
140
161
"
141
162
trait Foo {
163
+ type Output;
164
+
165
+ const CONST: usize = 42;
166
+
142
167
fn foo(&self);
143
168
fn bar(&self);
144
169
fn baz(&self);
@@ -148,7 +173,9 @@ struct S;
148
173
149
174
impl Foo for S {
150
175
fn bar(&self) {}
151
- <|>fn foo(&self) { unimplemented!() }
176
+ <|>type Output;
177
+ const CONST: usize = 42;
178
+ fn foo(&self) { unimplemented!() }
152
179
fn baz(&self) { unimplemented!() }
153
180
154
181
}" ,
@@ -256,6 +283,8 @@ impl Foo for S { <|> }",
256
283
#[doc(alias = "test alias")]
257
284
trait Foo {
258
285
/// doc string
286
+ type Output;
287
+
259
288
#[must_use]
260
289
fn foo(&self);
261
290
}
@@ -265,12 +294,15 @@ impl Foo for S {}<|>"#,
265
294
#[doc(alias = "test alias")]
266
295
trait Foo {
267
296
/// doc string
297
+ type Output;
298
+
268
299
#[must_use]
269
300
fn foo(&self);
270
301
}
271
302
struct S;
272
303
impl Foo for S {
273
- <|>fn foo(&self) { unimplemented!() }
304
+ <|>type Output;
305
+ fn foo(&self) { unimplemented!() }
274
306
}"# ,
275
307
)
276
308
}
@@ -281,13 +313,21 @@ impl Foo for S {
281
313
add_missing_default_members,
282
314
"
283
315
trait Foo {
316
+ type Output;
317
+
318
+ const CONST: usize = 42;
319
+
284
320
fn valid(some: u32) -> bool { false }
285
321
fn foo(some: u32) -> bool;
286
322
}
287
323
struct S;
288
324
impl Foo for S { <|> }" ,
289
325
"
290
326
trait Foo {
327
+ type Output;
328
+
329
+ const CONST: usize = 42;
330
+
291
331
fn valid(some: u32) -> bool { false }
292
332
fn foo(some: u32) -> bool;
293
333
}
0 commit comments