diff options
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/src/completions/attribute.rs | 5 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute/repr.rs | 199 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/dot.rs | 5 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 4 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/postfix.rs | 27 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/trait_impl.rs | 309 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 3 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 20 |
8 files changed, 491 insertions, 81 deletions
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index f3b11e72d..78fc30e16 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs | |||
@@ -17,12 +17,14 @@ use crate::{ | |||
17 | 17 | ||
18 | mod derive; | 18 | mod derive; |
19 | mod lint; | 19 | mod lint; |
20 | mod repr; | ||
20 | 21 | ||
21 | pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 22 | pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
22 | let attribute = ctx.attribute_under_caret.as_ref()?; | 23 | let attribute = ctx.attribute_under_caret.as_ref()?; |
23 | match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) { | 24 | match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) { |
24 | (Some(path), Some(token_tree)) => match path.text().as_str() { | 25 | (Some(path), Some(token_tree)) => match path.text().as_str() { |
25 | "derive" => derive::complete_derive(acc, ctx, token_tree), | 26 | "derive" => derive::complete_derive(acc, ctx, token_tree), |
27 | "repr" => repr::complete_repr(acc, ctx, token_tree), | ||
26 | "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), | 28 | "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), |
27 | "allow" | "warn" | "deny" | "forbid" => { | 29 | "allow" | "warn" | "deny" | "forbid" => { |
28 | lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); | 30 | lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); |
@@ -786,13 +788,13 @@ mod tests { | |||
786 | at target_feature = "…" | 788 | at target_feature = "…" |
787 | at test | 789 | at test |
788 | at track_caller | 790 | at track_caller |
789 | kw return | ||
790 | "#]], | 791 | "#]], |
791 | ); | 792 | ); |
792 | } | 793 | } |
793 | 794 | ||
794 | #[test] | 795 | #[test] |
795 | fn complete_attribute_on_expr() { | 796 | fn complete_attribute_on_expr() { |
797 | cov_mark::check!(no_keyword_completion_in_attr_of_expr); | ||
796 | check( | 798 | check( |
797 | r#"fn main() { #[$0] foo() }"#, | 799 | r#"fn main() { #[$0] foo() }"#, |
798 | expect![[r#" | 800 | expect![[r#" |
@@ -802,7 +804,6 @@ mod tests { | |||
802 | at deny(…) | 804 | at deny(…) |
803 | at forbid(…) | 805 | at forbid(…) |
804 | at warn(…) | 806 | at warn(…) |
805 | kw return | ||
806 | "#]], | 807 | "#]], |
807 | ); | 808 | ); |
808 | } | 809 | } |
diff --git a/crates/ide_completion/src/completions/attribute/repr.rs b/crates/ide_completion/src/completions/attribute/repr.rs new file mode 100644 index 000000000..92a262a43 --- /dev/null +++ b/crates/ide_completion/src/completions/attribute/repr.rs | |||
@@ -0,0 +1,199 @@ | |||
1 | //! Completion for representations. | ||
2 | |||
3 | use syntax::ast; | ||
4 | |||
5 | use crate::{ | ||
6 | context::CompletionContext, | ||
7 | item::{CompletionItem, CompletionItemKind, CompletionKind}, | ||
8 | Completions, | ||
9 | }; | ||
10 | |||
11 | pub(super) fn complete_repr( | ||
12 | acc: &mut Completions, | ||
13 | ctx: &CompletionContext, | ||
14 | derive_input: ast::TokenTree, | ||
15 | ) { | ||
16 | if let Some(existing_reprs) = super::parse_comma_sep_input(derive_input) { | ||
17 | for repr_completion in REPR_COMPLETIONS { | ||
18 | if existing_reprs | ||
19 | .iter() | ||
20 | .any(|it| repr_completion.label == it || repr_completion.collides.contains(&&**it)) | ||
21 | { | ||
22 | continue; | ||
23 | } | ||
24 | let mut item = CompletionItem::new( | ||
25 | CompletionKind::Attribute, | ||
26 | ctx.source_range(), | ||
27 | repr_completion.label, | ||
28 | ); | ||
29 | item.kind(CompletionItemKind::Attribute); | ||
30 | if let Some(lookup) = repr_completion.lookup { | ||
31 | item.lookup_by(lookup); | ||
32 | } | ||
33 | if let Some((snippet, cap)) = repr_completion.snippet.zip(ctx.config.snippet_cap) { | ||
34 | item.insert_snippet(cap, snippet); | ||
35 | } | ||
36 | item.add_to(acc); | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | |||
41 | struct ReprCompletion { | ||
42 | label: &'static str, | ||
43 | snippet: Option<&'static str>, | ||
44 | lookup: Option<&'static str>, | ||
45 | collides: &'static [&'static str], | ||
46 | } | ||
47 | |||
48 | const fn attr(label: &'static str, collides: &'static [&'static str]) -> ReprCompletion { | ||
49 | ReprCompletion { label, snippet: None, lookup: None, collides } | ||
50 | } | ||
51 | |||
52 | #[rustfmt::skip] | ||
53 | const REPR_COMPLETIONS: &[ReprCompletion] = &[ | ||
54 | ReprCompletion { label: "align($0)", snippet: Some("align($0)"), lookup: Some("align"), collides: &["transparent", "packed"] }, | ||
55 | attr("packed", &["transparent", "align"]), | ||
56 | attr("transparent", &["C", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
57 | attr("C", &["transparent"]), | ||
58 | attr("u8", &["transparent", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
59 | attr("u16", &["transparent", "u8", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
60 | attr("u32", &["transparent", "u8", "u16", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
61 | attr("u64", &["transparent", "u8", "u16", "u32", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
62 | attr("u128", &["transparent", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
63 | attr("usize", &["transparent", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
64 | attr("i8", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i16", "i32", "i64", "i128", "isize"]), | ||
65 | attr("i16", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i32", "i64", "i128", "isize"]), | ||
66 | attr("i32", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i64", "i128", "isize"]), | ||
67 | attr("i64", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i128", "isize"]), | ||
68 | attr("i28", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "isize"]), | ||
69 | attr("isize", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128"]), | ||
70 | ]; | ||
71 | |||
72 | #[cfg(test)] | ||
73 | mod tests { | ||
74 | use expect_test::{expect, Expect}; | ||
75 | |||
76 | use crate::tests::completion_list; | ||
77 | |||
78 | fn check(ra_fixture: &str, expect: Expect) { | ||
79 | let actual = completion_list(ra_fixture); | ||
80 | expect.assert_eq(&actual); | ||
81 | } | ||
82 | |||
83 | #[test] | ||
84 | fn no_completion_for_incorrect_repr() { | ||
85 | check(r#"#[repr{$0)] struct Test;"#, expect![[]]) | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn empty() { | ||
90 | check( | ||
91 | r#"#[repr($0)] struct Test;"#, | ||
92 | expect![[r#" | ||
93 | at align($0) | ||
94 | at packed | ||
95 | at transparent | ||
96 | at C | ||
97 | at u8 | ||
98 | at u16 | ||
99 | at u32 | ||
100 | at u64 | ||
101 | at u128 | ||
102 | at usize | ||
103 | at i8 | ||
104 | at i16 | ||
105 | at i32 | ||
106 | at i64 | ||
107 | at i28 | ||
108 | at isize | ||
109 | "#]], | ||
110 | ); | ||
111 | } | ||
112 | |||
113 | #[test] | ||
114 | fn transparent() { | ||
115 | check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); | ||
116 | } | ||
117 | |||
118 | #[test] | ||
119 | fn align() { | ||
120 | check( | ||
121 | r#"#[repr(align(1), $0)] struct Test;"#, | ||
122 | expect![[r#" | ||
123 | at align($0) | ||
124 | at transparent | ||
125 | at C | ||
126 | at u8 | ||
127 | at u16 | ||
128 | at u32 | ||
129 | at u64 | ||
130 | at u128 | ||
131 | at usize | ||
132 | at i8 | ||
133 | at i16 | ||
134 | at i32 | ||
135 | at i64 | ||
136 | at i28 | ||
137 | at isize | ||
138 | "#]], | ||
139 | ); | ||
140 | } | ||
141 | |||
142 | #[test] | ||
143 | fn packed() { | ||
144 | check( | ||
145 | r#"#[repr(packed, $0)] struct Test;"#, | ||
146 | expect![[r#" | ||
147 | at transparent | ||
148 | at C | ||
149 | at u8 | ||
150 | at u16 | ||
151 | at u32 | ||
152 | at u64 | ||
153 | at u128 | ||
154 | at usize | ||
155 | at i8 | ||
156 | at i16 | ||
157 | at i32 | ||
158 | at i64 | ||
159 | at i28 | ||
160 | at isize | ||
161 | "#]], | ||
162 | ); | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn c() { | ||
167 | check( | ||
168 | r#"#[repr(C, $0)] struct Test;"#, | ||
169 | expect![[r#" | ||
170 | at align($0) | ||
171 | at packed | ||
172 | at u8 | ||
173 | at u16 | ||
174 | at u32 | ||
175 | at u64 | ||
176 | at u128 | ||
177 | at usize | ||
178 | at i8 | ||
179 | at i16 | ||
180 | at i32 | ||
181 | at i64 | ||
182 | at i28 | ||
183 | at isize | ||
184 | "#]], | ||
185 | ); | ||
186 | } | ||
187 | |||
188 | #[test] | ||
189 | fn prim() { | ||
190 | check( | ||
191 | r#"#[repr(usize, $0)] struct Test;"#, | ||
192 | expect![[r#" | ||
193 | at align($0) | ||
194 | at packed | ||
195 | at C | ||
196 | "#]], | ||
197 | ); | ||
198 | } | ||
199 | } | ||
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 7f75d4298..286d7cb67 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -498,10 +498,7 @@ mod foo { | |||
498 | fn issue_8931() { | 498 | fn issue_8931() { |
499 | check( | 499 | check( |
500 | r#" | 500 | r#" |
501 | #[lang = "fn_once"] | 501 | //- minicore: fn |
502 | trait FnOnce<Args> { | ||
503 | type Output; | ||
504 | } | ||
505 | struct S; | 502 | struct S; |
506 | 503 | ||
507 | struct Foo; | 504 | struct Foo; |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index c99fdef05..07541c79c 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -48,6 +48,10 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
48 | cov_mark::hit!(no_keyword_completion_in_record_lit); | 48 | cov_mark::hit!(no_keyword_completion_in_record_lit); |
49 | return; | 49 | return; |
50 | } | 50 | } |
51 | if ctx.attribute_under_caret.is_some() { | ||
52 | cov_mark::hit!(no_keyword_completion_in_attr_of_expr); | ||
53 | return; | ||
54 | } | ||
51 | 55 | ||
52 | // Suggest .await syntax for types that implement Future trait | 56 | // Suggest .await syntax for types that implement Future trait |
53 | if let Some(receiver) = ctx.dot_receiver() { | 57 | if let Some(receiver) = ctx.dot_receiver() { |
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index c3c7e4589..4e20ec003 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -436,18 +436,15 @@ fn main() { | |||
436 | check_edit( | 436 | check_edit( |
437 | "ifl", | 437 | "ifl", |
438 | r#" | 438 | r#" |
439 | enum Option<T> { Some(T), None } | 439 | //- minicore: option |
440 | |||
441 | fn main() { | 440 | fn main() { |
442 | let bar = Option::Some(true); | 441 | let bar = Some(true); |
443 | bar.$0 | 442 | bar.$0 |
444 | } | 443 | } |
445 | "#, | 444 | "#, |
446 | r#" | 445 | r#" |
447 | enum Option<T> { Some(T), None } | ||
448 | |||
449 | fn main() { | 446 | fn main() { |
450 | let bar = Option::Some(true); | 447 | let bar = Some(true); |
451 | if let Some($1) = bar { | 448 | if let Some($1) = bar { |
452 | $0 | 449 | $0 |
453 | } | 450 | } |
@@ -461,18 +458,15 @@ fn main() { | |||
461 | check_edit( | 458 | check_edit( |
462 | "match", | 459 | "match", |
463 | r#" | 460 | r#" |
464 | enum Result<T, E> { Ok(T), Err(E) } | 461 | //- minicore: result |
465 | |||
466 | fn main() { | 462 | fn main() { |
467 | let bar = Result::Ok(true); | 463 | let bar = Ok(true); |
468 | bar.$0 | 464 | bar.$0 |
469 | } | 465 | } |
470 | "#, | 466 | "#, |
471 | r#" | 467 | r#" |
472 | enum Result<T, E> { Ok(T), Err(E) } | ||
473 | |||
474 | fn main() { | 468 | fn main() { |
475 | let bar = Result::Ok(true); | 469 | let bar = Ok(true); |
476 | match bar { | 470 | match bar { |
477 | Ok(${1:_}) => {$2}, | 471 | Ok(${1:_}) => {$2}, |
478 | Err(${3:_}) => {$0}, | 472 | Err(${3:_}) => {$0}, |
@@ -515,18 +509,15 @@ fn main() { | |||
515 | check_edit( | 509 | check_edit( |
516 | "ifl", | 510 | "ifl", |
517 | r#" | 511 | r#" |
518 | enum Option<T> { Some(T), None } | 512 | //- minicore: option |
519 | |||
520 | fn main() { | 513 | fn main() { |
521 | let bar = &Option::Some(true); | 514 | let bar = &Some(true); |
522 | bar.$0 | 515 | bar.$0 |
523 | } | 516 | } |
524 | "#, | 517 | "#, |
525 | r#" | 518 | r#" |
526 | enum Option<T> { Some(T), None } | ||
527 | |||
528 | fn main() { | 519 | fn main() { |
529 | let bar = &Option::Some(true); | 520 | let bar = &Some(true); |
530 | if let Some($1) = bar { | 521 | if let Some($1) = bar { |
531 | $0 | 522 | $0 |
532 | } | 523 | } |
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index dc1d198cc..65f0f3843 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, |
@@ -52,24 +52,26 @@ enum ImplCompletionKind { | |||
52 | 52 | ||
53 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 53 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
54 | if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { | 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 { | 55 | if let Some(hir_impl) = ctx.sema.to_def(&impl_def) { |
56 | hir::AssocItem::Function(fn_item) | 56 | get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { |
57 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => | 57 | hir::AssocItem::Function(fn_item) |
58 | { | 58 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => |
59 | add_function_impl(&trigger, acc, ctx, fn_item) | 59 | { |
60 | } | 60 | add_function_impl(&trigger, acc, ctx, fn_item, hir_impl) |
61 | hir::AssocItem::TypeAlias(type_item) | 61 | } |
62 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => | 62 | hir::AssocItem::TypeAlias(type_item) |
63 | { | 63 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => |
64 | add_type_alias_impl(&trigger, acc, ctx, type_item) | 64 | { |
65 | } | 65 | add_type_alias_impl(&trigger, acc, ctx, type_item) |
66 | hir::AssocItem::Const(const_item) | 66 | } |
67 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => | 67 | hir::AssocItem::Const(const_item) |
68 | { | 68 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => |
69 | add_const_impl(&trigger, acc, ctx, const_item) | 69 | { |
70 | } | 70 | add_const_impl(&trigger, acc, ctx, const_item, hir_impl) |
71 | _ => {} | 71 | } |
72 | }); | 72 | _ => {} |
73 | }); | ||
74 | } | ||
73 | } | 75 | } |
74 | } | 76 | } |
75 | 77 | ||
@@ -129,6 +131,7 @@ fn add_function_impl( | |||
129 | acc: &mut Completions, | 131 | acc: &mut Completions, |
130 | ctx: &CompletionContext, | 132 | ctx: &CompletionContext, |
131 | func: hir::Function, | 133 | func: hir::Function, |
134 | impl_def: hir::Impl, | ||
132 | ) { | 135 | ) { |
133 | let fn_name = func.name(ctx.db).to_string(); | 136 | let fn_name = func.name(ctx.db).to_string(); |
134 | 137 | ||
@@ -147,23 +150,55 @@ fn add_function_impl( | |||
147 | CompletionItemKind::SymbolKind(SymbolKind::Function) | 150 | CompletionItemKind::SymbolKind(SymbolKind::Function) |
148 | }; | 151 | }; |
149 | let range = replacement_range(ctx, fn_def_node); | 152 | let range = replacement_range(ctx, fn_def_node); |
150 | if let Some(src) = func.source(ctx.db) { | 153 | |
151 | let function_decl = function_declaration(&src.value); | 154 | if let Some(source) = func.source(ctx.db) { |
152 | match ctx.config.snippet_cap { | 155 | let assoc_item = ast::AssocItem::Fn(source.value); |
153 | Some(cap) => { | 156 | if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { |
154 | let snippet = format!("{} {{\n $0\n}}", function_decl); | 157 | let transformed_fn = match transformed_item { |
155 | item.snippet_edit(cap, TextEdit::replace(range, snippet)); | 158 | ast::AssocItem::Fn(func) => func, |
156 | } | 159 | _ => unreachable!(), |
157 | None => { | 160 | }; |
158 | let header = format!("{} {{", function_decl); | 161 | |
159 | item.text_edit(TextEdit::replace(range, header)); | 162 | let function_decl = function_declaration(&transformed_fn); |
160 | } | 163 | match ctx.config.snippet_cap { |
161 | }; | 164 | Some(cap) => { |
162 | item.kind(completion_kind); | 165 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
163 | item.add_to(acc); | 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 | fn add_type_alias_impl( | 202 | fn add_type_alias_impl( |
168 | type_def_node: &SyntaxNode, | 203 | type_def_node: &SyntaxNode, |
169 | acc: &mut Completions, | 204 | acc: &mut Completions, |
@@ -188,21 +223,30 @@ fn add_const_impl( | |||
188 | acc: &mut Completions, | 223 | acc: &mut Completions, |
189 | ctx: &CompletionContext, | 224 | ctx: &CompletionContext, |
190 | const_: hir::Const, | 225 | const_: hir::Const, |
226 | impl_def: hir::Impl, | ||
191 | ) { | 227 | ) { |
192 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | 228 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); |
193 | 229 | ||
194 | if let Some(const_name) = const_name { | 230 | if let Some(const_name) = const_name { |
195 | if let Some(source) = const_.source(ctx.db) { | 231 | if let Some(source) = const_.source(ctx.db) { |
196 | let snippet = make_const_compl_syntax(&source.value); | 232 | let assoc_item = ast::AssocItem::Const(source.value); |
197 | 233 | if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { | |
198 | let range = replacement_range(ctx, const_def_node); | 234 | let transformed_const = match transformed_item { |
199 | let mut item = | 235 | ast::AssocItem::Const(const_) => const_, |
200 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | 236 | _ => unreachable!(), |
201 | item.text_edit(TextEdit::replace(range, snippet)) | 237 | }; |
202 | .lookup_by(const_name) | 238 | |
203 | .kind(SymbolKind::Const) | 239 | let snippet = make_const_compl_syntax(&transformed_const); |
204 | .set_documentation(const_.docs(ctx.db)); | 240 | |
205 | item.add_to(acc); | 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 | test("Type", "type T$0", "type Type = "); | 823 | test("Type", "type T$0", "type Type = "); |
780 | test("CONST", "const C$0", "const CONST: i32 = "); | 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 | } |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 98fb36042..e49e434fa 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -942,13 +942,12 @@ fn foo() -> u32 { | |||
942 | // FIXME: make this work with `|| $0` | 942 | // FIXME: make this work with `|| $0` |
943 | check_expected_type_and_name( | 943 | check_expected_type_and_name( |
944 | r#" | 944 | r#" |
945 | //- minicore: fn | ||
945 | fn foo() { | 946 | fn foo() { |
946 | bar(|| a$0); | 947 | bar(|| a$0); |
947 | } | 948 | } |
948 | 949 | ||
949 | fn bar(f: impl FnOnce() -> u32) {} | 950 | fn bar(f: impl FnOnce() -> u32) {} |
950 | #[lang = "fn_once"] | ||
951 | trait FnOnce { type Output; } | ||
952 | "#, | 951 | "#, |
953 | expect![[r#"ty: u32, name: ?"#]], | 952 | expect![[r#"ty: u32, name: ?"#]], |
954 | ); | 953 | ); |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 4b55f7504..9bec03e17 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -1269,16 +1269,11 @@ fn bar(t: &Foo) {} | |||
1269 | fn suggest_deref_fn_ret() { | 1269 | fn suggest_deref_fn_ret() { |
1270 | check_relevance( | 1270 | check_relevance( |
1271 | r#" | 1271 | r#" |
1272 | #[lang = "deref"] | 1272 | //- minicore: deref |
1273 | trait Deref { | ||
1274 | type Target; | ||
1275 | fn deref(&self) -> &Self::Target; | ||
1276 | } | ||
1277 | |||
1278 | struct S; | 1273 | struct S; |
1279 | struct T(S); | 1274 | struct T(S); |
1280 | 1275 | ||
1281 | impl Deref for T { | 1276 | impl core::ops::Deref for T { |
1282 | type Target = S; | 1277 | type Target = S; |
1283 | 1278 | ||
1284 | fn deref(&self) -> &Self::Target { | 1279 | fn deref(&self) -> &Self::Target { |
@@ -1292,15 +1287,16 @@ fn bar() -> T {} | |||
1292 | fn main() { | 1287 | fn main() { |
1293 | foo($0); | 1288 | foo($0); |
1294 | } | 1289 | } |
1295 | "#, | 1290 | "#, |
1296 | expect![[r#" | 1291 | expect![[r#" |
1297 | tt Deref [] | ||
1298 | fn bar() [] | ||
1299 | fn &bar() [type] | ||
1300 | fn foo(…) [] | ||
1301 | st T [] | 1292 | st T [] |
1302 | st S [] | 1293 | st S [] |
1303 | fn main() [] | 1294 | fn main() [] |
1295 | fn bar() [] | ||
1296 | fn &bar() [type] | ||
1297 | fn foo(…) [] | ||
1298 | md core [] | ||
1299 | tt Sized [] | ||
1304 | "#]], | 1300 | "#]], |
1305 | ) | 1301 | ) |
1306 | } | 1302 | } |