@@ -2,9 +2,10 @@ use crate::{Assist, AssistId, AssistCtx, ast_editor::{AstEditor, AstBuilder}};
22
33use hir:: { HasSource , db:: HirDatabase } ;
44use 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 } ;
66use ra_db:: FilePosition ;
77
8+ #[ derive( PartialEq ) ]
89enum AddMissingImplMembersMode {
910 DefaultMethodsOnly ,
1011 NoDefaultMethods ,
@@ -45,39 +46,50 @@ fn add_missing_impl_members_inner(
4546 resolve_target_trait_def ( ctx. db , & analyzer, impl_node) ?
4647 } ;
4748
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)
6756 } ;
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 ( ) {
6973 return None ;
7074 }
7175
7276 ctx. add_action ( AssistId ( assist_id) , label, |edit| {
7377 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-
7678 let mut ast_editor = AstEditor :: new ( impl_item_list) ;
7779 if n_existing_items == 0 {
7880 ast_editor. make_multiline ( ) ;
7981 }
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+
8193 let first_new_item = ast_editor. ast ( ) . impl_items ( ) . nth ( n_existing_items) . unwrap ( ) ;
8294 let cursor_poisition = first_new_item. syntax ( ) . range ( ) . start ( ) ;
8395 ast_editor. into_text_edit ( edit. text_edit_builder ( ) ) ;
@@ -88,14 +100,19 @@ fn add_missing_impl_members_inner(
88100 ctx. build ( )
89101}
90102
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 > {
92110 let mut ast_editor = AstEditor :: new ( fn_def) ;
93111 if fn_def. body ( ) . is_none ( ) {
94112 ast_editor. set_body ( & AstBuilder :: < ast:: Block > :: single_expr (
95113 & AstBuilder :: < ast:: Expr > :: unimplemented ( ) ,
96114 ) ) ;
97115 }
98- ast_editor. strip_attrs_and_docs ( ) ;
99116 ast_editor. ast ( ) . to_owned ( )
100117}
101118
@@ -126,6 +143,10 @@ mod tests {
126143 add_missing_impl_members,
127144 "
128145trait Foo {
146+ type Output;
147+
148+ const CONST: usize = 42;
149+
129150 fn foo(&self);
130151 fn bar(&self);
131152 fn baz(&self);
@@ -139,6 +160,10 @@ impl Foo for S {
139160}" ,
140161 "
141162trait Foo {
163+ type Output;
164+
165+ const CONST: usize = 42;
166+
142167 fn foo(&self);
143168 fn bar(&self);
144169 fn baz(&self);
@@ -148,7 +173,9 @@ struct S;
148173
149174impl Foo for S {
150175 fn bar(&self) {}
151- <|>fn foo(&self) { unimplemented!() }
176+ <|>type Output;
177+ const CONST: usize = 42;
178+ fn foo(&self) { unimplemented!() }
152179 fn baz(&self) { unimplemented!() }
153180
154181}" ,
@@ -256,6 +283,8 @@ impl Foo for S { <|> }",
256283#[doc(alias = "test alias")]
257284trait Foo {
258285 /// doc string
286+ type Output;
287+
259288 #[must_use]
260289 fn foo(&self);
261290}
@@ -265,12 +294,15 @@ impl Foo for S {}<|>"#,
265294#[doc(alias = "test alias")]
266295trait Foo {
267296 /// doc string
297+ type Output;
298+
268299 #[must_use]
269300 fn foo(&self);
270301}
271302struct S;
272303impl Foo for S {
273- <|>fn foo(&self) { unimplemented!() }
304+ <|>type Output;
305+ fn foo(&self) { unimplemented!() }
274306}"# ,
275307 )
276308 }
@@ -281,13 +313,21 @@ impl Foo for S {
281313 add_missing_default_members,
282314 "
283315trait Foo {
316+ type Output;
317+
318+ const CONST: usize = 42;
319+
284320 fn valid(some: u32) -> bool { false }
285321 fn foo(some: u32) -> bool;
286322}
287323struct S;
288324impl Foo for S { <|> }" ,
289325 "
290326trait Foo {
327+ type Output;
328+
329+ const CONST: usize = 42;
330+
291331 fn valid(some: u32) -> bool { false }
292332 fn foo(some: u32) -> bool;
293333}
0 commit comments