32
32
//! ```
33
33
34
34
use hir:: { self , HasAttrs , HasSource } ;
35
- use ide_db:: { traits:: get_missing_assoc_items, SymbolKind } ;
35
+ use ide_db:: { path_transform :: PathTransform , traits:: get_missing_assoc_items, SymbolKind } ;
36
36
use syntax:: {
37
37
ast:: { self , edit} ,
38
38
display:: function_declaration,
@@ -52,24 +52,26 @@ enum ImplCompletionKind {
52
52
53
53
pub ( crate ) fn complete_trait_impl ( acc : & mut Completions , ctx : & CompletionContext ) {
54
54
if let Some ( ( kind, trigger, impl_def) ) = completion_match ( ctx. token . clone ( ) ) {
55
- get_missing_assoc_items ( & ctx. sema , & impl_def) . into_iter ( ) . for_each ( |item| match item {
56
- hir:: AssocItem :: Function ( fn_item)
57
- if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: Fn =>
58
- {
59
- add_function_impl ( & trigger, acc, ctx, fn_item)
60
- }
61
- hir:: AssocItem :: TypeAlias ( type_item)
62
- if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: TypeAlias =>
63
- {
64
- add_type_alias_impl ( & trigger, acc, ctx, type_item)
65
- }
66
- hir:: AssocItem :: Const ( const_item)
67
- if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: Const =>
68
- {
69
- add_const_impl ( & trigger, acc, ctx, const_item)
70
- }
71
- _ => { }
72
- } ) ;
55
+ if let Some ( hir_impl) = ctx. sema . to_def ( & impl_def) {
56
+ get_missing_assoc_items ( & ctx. sema , & impl_def) . into_iter ( ) . for_each ( |item| match item {
57
+ hir:: AssocItem :: Function ( fn_item)
58
+ if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: Fn =>
59
+ {
60
+ add_function_impl ( & trigger, acc, ctx, fn_item, hir_impl)
61
+ }
62
+ hir:: AssocItem :: TypeAlias ( type_item)
63
+ if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: TypeAlias =>
64
+ {
65
+ add_type_alias_impl ( & trigger, acc, ctx, type_item)
66
+ }
67
+ hir:: AssocItem :: Const ( const_item)
68
+ if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: Const =>
69
+ {
70
+ add_const_impl ( & trigger, acc, ctx, const_item, hir_impl)
71
+ }
72
+ _ => { }
73
+ } ) ;
74
+ }
73
75
}
74
76
}
75
77
@@ -129,6 +131,7 @@ fn add_function_impl(
129
131
acc : & mut Completions ,
130
132
ctx : & CompletionContext ,
131
133
func : hir:: Function ,
134
+ impl_def : hir:: Impl ,
132
135
) {
133
136
let fn_name = func. name ( ctx. db ) . to_string ( ) ;
134
137
@@ -147,23 +150,55 @@ fn add_function_impl(
147
150
CompletionItemKind :: SymbolKind ( SymbolKind :: Function )
148
151
} ;
149
152
let range = replacement_range ( ctx, fn_def_node) ;
150
- if let Some ( src) = func. source ( ctx. db ) {
151
- let function_decl = function_declaration ( & src. value ) ;
152
- match ctx. config . snippet_cap {
153
- Some ( cap) => {
154
- let snippet = format ! ( "{} {{\n $0\n }}" , function_decl) ;
155
- item. snippet_edit ( cap, TextEdit :: replace ( range, snippet) ) ;
156
- }
157
- None => {
158
- let header = format ! ( "{} {{" , function_decl) ;
159
- item. text_edit ( TextEdit :: replace ( range, header) ) ;
160
- }
161
- } ;
162
- item. kind ( completion_kind) ;
163
- item. add_to ( acc) ;
153
+
154
+ if let Some ( source) = func. source ( ctx. db ) {
155
+ let assoc_item = ast:: AssocItem :: Fn ( source. value ) ;
156
+ if let Some ( transformed_item) = get_transformed_assoc_item ( ctx, assoc_item, impl_def) {
157
+ let transformed_fn = match transformed_item {
158
+ ast:: AssocItem :: Fn ( func) => func,
159
+ _ => unreachable ! ( ) ,
160
+ } ;
161
+
162
+ let function_decl = function_declaration ( & transformed_fn) ;
163
+ match ctx. config . snippet_cap {
164
+ Some ( cap) => {
165
+ let snippet = format ! ( "{} {{\n $0\n }}" , function_decl) ;
166
+ item. snippet_edit ( cap, TextEdit :: replace ( range, snippet) ) ;
167
+ }
168
+ None => {
169
+ let header = format ! ( "{} {{" , function_decl) ;
170
+ item. text_edit ( TextEdit :: replace ( range, header) ) ;
171
+ }
172
+ } ;
173
+ item. kind ( completion_kind) ;
174
+ item. add_to ( acc) ;
175
+ }
164
176
}
165
177
}
166
178
179
+ /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
180
+ fn get_transformed_assoc_item (
181
+ ctx : & CompletionContext ,
182
+ assoc_item : ast:: AssocItem ,
183
+ impl_def : hir:: Impl ,
184
+ ) -> Option < ast:: AssocItem > {
185
+ let assoc_item = assoc_item. clone_for_update ( ) ;
186
+ let trait_ = impl_def. trait_ ( ctx. db ) ?;
187
+ let source_scope = & ctx. sema . scope_for_def ( trait_) ;
188
+ let target_scope = & ctx. sema . scope ( impl_def. source ( ctx. db ) ?. syntax ( ) . value ) ;
189
+ let transform = PathTransform {
190
+ subst : ( trait_, impl_def. source ( ctx. db ) ?. value ) ,
191
+ source_scope,
192
+ target_scope,
193
+ } ;
194
+
195
+ transform. apply ( assoc_item. clone ( ) ) ;
196
+ Some ( match assoc_item {
197
+ ast:: AssocItem :: Fn ( func) => ast:: AssocItem :: Fn ( edit:: remove_attrs_and_docs ( & func) ) ,
198
+ _ => assoc_item,
199
+ } )
200
+ }
201
+
167
202
fn add_type_alias_impl (
168
203
type_def_node : & SyntaxNode ,
169
204
acc : & mut Completions ,
@@ -188,21 +223,30 @@ fn add_const_impl(
188
223
acc : & mut Completions ,
189
224
ctx : & CompletionContext ,
190
225
const_ : hir:: Const ,
226
+ impl_def : hir:: Impl ,
191
227
) {
192
228
let const_name = const_. name ( ctx. db ) . map ( |n| n. to_string ( ) ) ;
193
229
194
230
if let Some ( const_name) = const_name {
195
231
if let Some ( source) = const_. source ( ctx. db ) {
196
- let snippet = make_const_compl_syntax ( & source. value ) ;
197
-
198
- let range = replacement_range ( ctx, const_def_node) ;
199
- let mut item =
200
- CompletionItem :: new ( CompletionKind :: Magic , ctx. source_range ( ) , snippet. clone ( ) ) ;
201
- item. text_edit ( TextEdit :: replace ( range, snippet) )
202
- . lookup_by ( const_name)
203
- . kind ( SymbolKind :: Const )
204
- . set_documentation ( const_. docs ( ctx. db ) ) ;
205
- item. add_to ( acc) ;
232
+ let assoc_item = ast:: AssocItem :: Const ( source. value ) ;
233
+ if let Some ( transformed_item) = get_transformed_assoc_item ( ctx, assoc_item, impl_def) {
234
+ let transformed_const = match transformed_item {
235
+ ast:: AssocItem :: Const ( const_) => const_,
236
+ _ => unreachable ! ( ) ,
237
+ } ;
238
+
239
+ let snippet = make_const_compl_syntax ( & transformed_const) ;
240
+
241
+ let range = replacement_range ( ctx, const_def_node) ;
242
+ let mut item =
243
+ CompletionItem :: new ( CompletionKind :: Magic , ctx. source_range ( ) , snippet. clone ( ) ) ;
244
+ item. text_edit ( TextEdit :: replace ( range, snippet) )
245
+ . lookup_by ( const_name)
246
+ . kind ( SymbolKind :: Const )
247
+ . set_documentation ( const_. docs ( ctx. db ) ) ;
248
+ item. add_to ( acc) ;
249
+ }
206
250
}
207
251
}
208
252
}
@@ -779,4 +823,183 @@ impl Foo for T {{
779
823
test ( "Type" , "type T$0" , "type Type = " ) ;
780
824
test ( "CONST" , "const C$0" , "const CONST: i32 = " ) ;
781
825
}
826
+
827
+ #[ test]
828
+ fn generics_are_inlined_in_return_type ( ) {
829
+ check_edit (
830
+ "function" ,
831
+ r#"
832
+ trait Foo<T> {
833
+ fn function() -> T;
834
+ }
835
+ struct Bar;
836
+
837
+ impl Foo<u32> for Bar {
838
+ fn f$0
839
+ }
840
+ "# ,
841
+ r#"
842
+ trait Foo<T> {
843
+ fn function() -> T;
844
+ }
845
+ struct Bar;
846
+
847
+ impl Foo<u32> for Bar {
848
+ fn function() -> u32 {
849
+ $0
850
+ }
851
+ }
852
+ "# ,
853
+ )
854
+ }
855
+
856
+ #[ test]
857
+ fn generics_are_inlined_in_parameter ( ) {
858
+ check_edit (
859
+ "function" ,
860
+ r#"
861
+ trait Foo<T> {
862
+ fn function(bar: T);
863
+ }
864
+ struct Bar;
865
+
866
+ impl Foo<u32> for Bar {
867
+ fn f$0
868
+ }
869
+ "# ,
870
+ r#"
871
+ trait Foo<T> {
872
+ fn function(bar: T);
873
+ }
874
+ struct Bar;
875
+
876
+ impl Foo<u32> for Bar {
877
+ fn function(bar: u32) {
878
+ $0
879
+ }
880
+ }
881
+ "# ,
882
+ )
883
+ }
884
+
885
+ #[ test]
886
+ fn generics_are_inlined_when_part_of_other_types ( ) {
887
+ check_edit (
888
+ "function" ,
889
+ r#"
890
+ trait Foo<T> {
891
+ fn function(bar: Vec<T>);
892
+ }
893
+ struct Bar;
894
+
895
+ impl Foo<u32> for Bar {
896
+ fn f$0
897
+ }
898
+ "# ,
899
+ r#"
900
+ trait Foo<T> {
901
+ fn function(bar: Vec<T>);
902
+ }
903
+ struct Bar;
904
+
905
+ impl Foo<u32> for Bar {
906
+ fn function(bar: Vec<u32>) {
907
+ $0
908
+ }
909
+ }
910
+ "# ,
911
+ )
912
+ }
913
+
914
+ #[ test]
915
+ fn generics_are_inlined_complex ( ) {
916
+ check_edit (
917
+ "function" ,
918
+ r#"
919
+ trait Foo<T, U, V> {
920
+ fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
921
+ }
922
+ struct Bar;
923
+
924
+ impl Foo<u32, Vec<usize>, u8> for Bar {
925
+ fn f$0
926
+ }
927
+ "# ,
928
+ r#"
929
+ trait Foo<T, U, V> {
930
+ fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
931
+ }
932
+ struct Bar;
933
+
934
+ impl Foo<u32, Vec<usize>, u8> for Bar {
935
+ fn function(bar: Vec<u32>, baz: Vec<usize>) -> Arc<Vec<u8>> {
936
+ $0
937
+ }
938
+ }
939
+ "# ,
940
+ )
941
+ }
942
+
943
+ #[ test]
944
+ fn generics_are_inlined_in_associated_const ( ) {
945
+ check_edit (
946
+ "BAR" ,
947
+ r#"
948
+ trait Foo<T> {
949
+ const BAR: T;
950
+ }
951
+ struct Bar;
952
+
953
+ impl Foo<u32> for Bar {
954
+ const B$0;
955
+ }
956
+ "# ,
957
+ r#"
958
+ trait Foo<T> {
959
+ const BAR: T;
960
+ }
961
+ struct Bar;
962
+
963
+ impl Foo<u32> for Bar {
964
+ const BAR: u32 = ;
965
+ }
966
+ "# ,
967
+ )
968
+ }
969
+
970
+ #[ test]
971
+ fn generics_are_inlined_in_where_clause ( ) {
972
+ check_edit (
973
+ "function" ,
974
+ r#"
975
+ trait SomeTrait<T> {}
976
+
977
+ trait Foo<T> {
978
+ fn function()
979
+ where Self: SomeTrait<T>;
980
+ }
981
+ struct Bar;
982
+
983
+ impl Foo<u32> for Bar {
984
+ fn f$0
985
+ }
986
+ "# ,
987
+ r#"
988
+ trait SomeTrait<T> {}
989
+
990
+ trait Foo<T> {
991
+ fn function()
992
+ where Self: SomeTrait<T>;
993
+ }
994
+ struct Bar;
995
+
996
+ impl Foo<u32> for Bar {
997
+ fn function()
998
+ where Self: SomeTrait<u32> {
999
+ $0
1000
+ }
1001
+ }
1002
+ "# ,
1003
+ )
1004
+ }
782
1005
}
0 commit comments