diff options
author | rdambrosio <[email protected]> | 2021-06-18 00:54:28 +0100 |
---|---|---|
committer | rdambrosio <[email protected]> | 2021-06-18 00:54:28 +0100 |
commit | 8e08b86304f8cf91e06f64855c8de306ad7efaa4 (patch) | |
tree | 134d42353a19d61fd7ebefd129fd7924c1d205f4 /crates/ide_completion | |
parent | 0d863ccea96c6c3256fad12807a0eedbfccd8294 (diff) |
Feat: inline generics in const and func trait completions
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/src/completions/trait_impl.rs | 279 |
1 files changed, 252 insertions, 27 deletions
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index dc1d198cc..1f6b959af 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs | |||
@@ -32,7 +32,7 @@ | |||
32 | //! ``` | 32 | //! ``` |
33 | 33 | ||
34 | use hir::{self, HasAttrs, HasSource}; | 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 | use syntax::{ | 36 | use syntax::{ |
37 | ast::{self, edit}, | 37 | ast::{self, edit}, |
38 | display::function_declaration, | 38 | display::function_declaration, |
@@ -56,7 +56,9 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext | |||
56 | hir::AssocItem::Function(fn_item) | 56 | hir::AssocItem::Function(fn_item) |
57 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => | 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 | hir::AssocItem::TypeAlias(type_item) | 63 | hir::AssocItem::TypeAlias(type_item) |
62 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => | 64 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => |
@@ -66,7 +68,9 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext | |||
66 | hir::AssocItem::Const(const_item) | 68 | hir::AssocItem::Const(const_item) |
67 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => | 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 | acc: &mut Completions, | 133 | acc: &mut Completions, |
130 | ctx: &CompletionContext, | 134 | ctx: &CompletionContext, |
131 | func: hir::Function, | 135 | func: hir::Function, |
136 | impl_def: hir::Impl, | ||
132 | ) { | 137 | ) { |
133 | let fn_name = func.name(ctx.db).to_string(); | 138 | let fn_name = func.name(ctx.db).to_string(); |
134 | 139 | ||
@@ -147,23 +152,55 @@ fn add_function_impl( | |||
147 | CompletionItemKind::SymbolKind(SymbolKind::Function) | 152 | CompletionItemKind::SymbolKind(SymbolKind::Function) |
148 | }; | 153 | }; |
149 | let range = replacement_range(ctx, fn_def_node); | 154 | let range = replacement_range(ctx, fn_def_node); |
150 | if let Some(src) = func.source(ctx.db) { | 155 | |
151 | let function_decl = function_declaration(&src.value); | 156 | if let Some(source) = func.source(ctx.db) { |
152 | match ctx.config.snippet_cap { | 157 | let assoc_item = ast::AssocItem::Fn(source.value); |
153 | Some(cap) => { | 158 | if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { |
154 | let snippet = format!("{} {{\n $0\n}}", function_decl); | 159 | let transformed_fn = match transformed_item { |
155 | item.snippet_edit(cap, TextEdit::replace(range, snippet)); | 160 | ast::AssocItem::Fn(func) => func, |
156 | } | 161 | _ => unreachable!(), |
157 | None => { | 162 | }; |
158 | let header = format!("{} {{", function_decl); | 163 | |
159 | item.text_edit(TextEdit::replace(range, header)); | 164 | let function_decl = function_declaration(&transformed_fn); |
160 | } | 165 | match ctx.config.snippet_cap { |
161 | }; | 166 | Some(cap) => { |
162 | item.kind(completion_kind); | 167 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
163 | item.add_to(acc); | 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 | fn add_type_alias_impl( | 204 | fn add_type_alias_impl( |
168 | type_def_node: &SyntaxNode, | 205 | type_def_node: &SyntaxNode, |
169 | acc: &mut Completions, | 206 | acc: &mut Completions, |
@@ -188,21 +225,30 @@ fn add_const_impl( | |||
188 | acc: &mut Completions, | 225 | acc: &mut Completions, |
189 | ctx: &CompletionContext, | 226 | ctx: &CompletionContext, |
190 | const_: hir::Const, | 227 | const_: hir::Const, |
228 | impl_def: hir::Impl, | ||
191 | ) { | 229 | ) { |
192 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | 230 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); |
193 | 231 | ||
194 | if let Some(const_name) = const_name { | 232 | if let Some(const_name) = const_name { |
195 | if let Some(source) = const_.source(ctx.db) { | 233 | if let Some(source) = const_.source(ctx.db) { |
196 | let snippet = make_const_compl_syntax(&source.value); | 234 | let assoc_item = ast::AssocItem::Const(source.value); |
197 | 235 | if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { | |
198 | let range = replacement_range(ctx, const_def_node); | 236 | let transformed_const = match transformed_item { |
199 | let mut item = | 237 | ast::AssocItem::Const(const_) => const_, |
200 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | 238 | _ => unreachable!(), |
201 | item.text_edit(TextEdit::replace(range, snippet)) | 239 | }; |
202 | .lookup_by(const_name) | 240 | |
203 | .kind(SymbolKind::Const) | 241 | let snippet = make_const_compl_syntax(&transformed_const); |
204 | .set_documentation(const_.docs(ctx.db)); | 242 | |
205 | item.add_to(acc); | 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 | test("Type", "type T$0", "type Type = "); | 825 | test("Type", "type T$0", "type Type = "); |
780 | test("CONST", "const C$0", "const CONST: i32 = "); | 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 | } |