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