aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/completions')
-rw-r--r--crates/ide_completion/src/completions/attribute.rs3
-rw-r--r--crates/ide_completion/src/completions/dot.rs2
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs93
-rw-r--r--crates/ide_completion/src/completions/lifetime.rs316
-rw-r--r--crates/ide_completion/src/completions/pattern.rs2
5 files changed, 410 insertions, 6 deletions
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index e846678b4..b1505c74b 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -246,7 +246,8 @@ fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
246 let mut result = FxHashSet::default(); 246 let mut result = FxHashSet::default();
247 ctx.scope.process_all_names(&mut |name, scope_def| { 247 ctx.scope.process_all_names(&mut |name, scope_def| {
248 if let hir::ScopeDef::MacroDef(mac) = scope_def { 248 if let hir::ScopeDef::MacroDef(mac) = scope_def {
249 if mac.is_derive_macro() { 249 // FIXME kind() doesn't check whether proc-macro is a derive
250 if mac.kind() == hir::MacroKind::Derive || mac.kind() == hir::MacroKind::ProcMacro {
250 result.insert(name.to_string()); 251 result.insert(name.to_string());
251 } 252 }
252 } 253 }
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index cec2d0c3a..7e4efe589 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -51,7 +51,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
51 && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) 51 && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
52 && seen_methods.insert(func.name(ctx.db)) 52 && seen_methods.insert(func.name(ctx.db))
53 { 53 {
54 acc.add_function(ctx, func, None); 54 acc.add_method(ctx, func, None);
55 } 55 }
56 None::<()> 56 None::<()>
57 }); 57 });
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 08df2df3f..1ad017198 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -1,8 +1,10 @@
1//! Feature: completion with imports-on-the-fly 1//! Feature: completion with imports-on-the-fly
2//! 2//!
3//! When completing names in the current scope, proposes additional imports from other modules or crates, 3//! When completing names in the current scope, proposes additional imports from other modules or crates,
4//! if they can be qualified in the scope and their name contains all symbols from the completion input 4//! if they can be qualified in the scope and their name contains all symbols from the completion input.
5//! (case-insensitive, in any order or places). 5//!
6//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
7//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the contaning is checked case-insensitively.
6//! 8//!
7//! ``` 9//! ```
8//! fn main() { 10//! fn main() {
@@ -942,9 +944,94 @@ mod foo {
942} 944}
943 945
944fn main() { 946fn main() {
945 bar::Ass$0 947 bar::ASS$0
946}"#, 948}"#,
947 expect![[]], 949 expect![[]],
948 ) 950 )
949 } 951 }
952
953 #[test]
954 fn unqualified_assoc_items_are_omitted() {
955 check(
956 r#"
957mod something {
958 pub trait BaseTrait {
959 fn test_function() -> i32;
960 }
961
962 pub struct Item1;
963 pub struct Item2;
964
965 impl BaseTrait for Item1 {
966 fn test_function() -> i32 {
967 1
968 }
969 }
970
971 impl BaseTrait for Item2 {
972 fn test_function() -> i32 {
973 2
974 }
975 }
976}
977
978fn main() {
979 test_f$0
980}"#,
981 expect![[]],
982 )
983 }
984
985 #[test]
986 fn case_matters() {
987 check(
988 r#"
989mod foo {
990 pub const TEST_CONST: usize = 3;
991 pub fn test_function() -> i32 {
992 4
993 }
994}
995
996fn main() {
997 TE$0
998}"#,
999 expect![[r#"
1000 ct foo::TEST_CONST
1001 "#]],
1002 );
1003
1004 check(
1005 r#"
1006mod foo {
1007 pub const TEST_CONST: usize = 3;
1008 pub fn test_function() -> i32 {
1009 4
1010 }
1011}
1012
1013fn main() {
1014 te$0
1015}"#,
1016 expect![[r#"
1017 ct foo::TEST_CONST
1018 fn test_function() (foo::test_function) fn() -> i32
1019 "#]],
1020 );
1021
1022 check(
1023 r#"
1024mod foo {
1025 pub const TEST_CONST: usize = 3;
1026 pub fn test_function() -> i32 {
1027 4
1028 }
1029}
1030
1031fn main() {
1032 Te$0
1033}"#,
1034 expect![[]],
1035 );
1036 }
950} 1037}
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs
new file mode 100644
index 000000000..5eeddf7a4
--- /dev/null
+++ b/crates/ide_completion/src/completions/lifetime.rs
@@ -0,0 +1,316 @@
1//! Completes lifetimes and labels.
2use hir::ScopeDef;
3
4use crate::{completions::Completions, context::CompletionContext};
5
6/// Completes lifetimes.
7pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext) {
8 if !ctx.lifetime_allowed {
9 return;
10 }
11 let param_lifetime = match (
12 &ctx.lifetime_syntax,
13 ctx.lifetime_param_syntax.as_ref().and_then(|lp| lp.lifetime()),
14 ) {
15 (Some(lt), Some(lp)) if lp == lt.clone() => return,
16 (Some(_), Some(lp)) => Some(lp.to_string()),
17 _ => None,
18 };
19
20 ctx.scope.process_all_names(&mut |name, res| {
21 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
22 if param_lifetime != Some(name.to_string()) {
23 acc.add_resolution(ctx, name.to_string(), &res);
24 }
25 }
26 });
27 if param_lifetime.is_none() {
28 acc.add_static_lifetime(ctx);
29 }
30}
31
32/// Completes labels.
33pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
34 if !ctx.is_label_ref {
35 return;
36 }
37 ctx.scope.process_all_names(&mut |name, res| {
38 if let ScopeDef::Label(_) = res {
39 acc.add_resolution(ctx, name.to_string(), &res);
40 }
41 });
42}
43
44#[cfg(test)]
45mod tests {
46 use expect_test::{expect, Expect};
47
48 use crate::{
49 test_utils::{check_edit, completion_list_with_config, TEST_CONFIG},
50 CompletionConfig, CompletionKind,
51 };
52
53 fn check(ra_fixture: &str, expect: Expect) {
54 check_with_config(TEST_CONFIG, ra_fixture, expect);
55 }
56
57 fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
58 let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
59 expect.assert_eq(&actual)
60 }
61
62 #[test]
63 fn check_lifetime_edit() {
64 check_edit(
65 "'lifetime",
66 r#"
67fn func<'lifetime>(foo: &'li$0) {}
68"#,
69 r#"
70fn func<'lifetime>(foo: &'lifetime) {}
71"#,
72 );
73 cov_mark::check!(completes_if_lifetime_without_idents);
74 check_edit(
75 "'lifetime",
76 r#"
77fn func<'lifetime>(foo: &'$0) {}
78"#,
79 r#"
80fn func<'lifetime>(foo: &'lifetime) {}
81"#,
82 );
83 }
84
85 #[test]
86 fn complete_lifetime_in_ref() {
87 check(
88 r#"
89fn foo<'lifetime>(foo: &'a$0 usize) {}
90"#,
91 expect![[r#"
92 lt 'lifetime
93 lt 'static
94 "#]],
95 );
96 }
97
98 #[test]
99 fn complete_lifetime_in_ref_missing_ty() {
100 check(
101 r#"
102fn foo<'lifetime>(foo: &'a$0) {}
103"#,
104 expect![[r#"
105 lt 'lifetime
106 lt 'static
107 "#]],
108 );
109 }
110 #[test]
111 fn complete_lifetime_in_self_ref() {
112 check(
113 r#"
114struct Foo;
115impl<'impl> Foo {
116 fn foo<'func>(&'a$0 self) {}
117}
118"#,
119 expect![[r#"
120 lt 'func
121 lt 'impl
122 lt 'static
123 "#]],
124 );
125 }
126
127 #[test]
128 fn complete_lifetime_in_arg_list() {
129 check(
130 r#"
131struct Foo<'lt>;
132fn foo<'lifetime>(_: Foo<'a$0>) {}
133"#,
134 expect![[r#"
135 lt 'lifetime
136 lt 'static
137 "#]],
138 );
139 }
140
141 #[test]
142 fn complete_lifetime_in_where_pred() {
143 check(
144 r#"
145fn foo2<'lifetime, T>() where 'a$0 {}
146"#,
147 expect![[r#"
148 lt 'lifetime
149 lt 'static
150 "#]],
151 );
152 }
153
154 #[test]
155 fn complete_lifetime_in_ty_bound() {
156 check(
157 r#"
158fn foo2<'lifetime, T>() where T: 'a$0 {}
159"#,
160 expect![[r#"
161 lt 'lifetime
162 lt 'static
163 "#]],
164 );
165 check(
166 r#"
167fn foo2<'lifetime, T>() where T: Trait<'a$0> {}
168"#,
169 expect![[r#"
170 lt 'lifetime
171 lt 'static
172 "#]],
173 );
174 }
175
176 #[test]
177 fn dont_complete_lifetime_in_assoc_ty_bound() {
178 check(
179 r#"
180fn foo2<'lifetime, T>() where T: Trait<Item = 'a$0> {}
181"#,
182 expect![[r#""#]],
183 );
184 }
185
186 #[test]
187 fn complete_lifetime_in_param_list() {
188 check(
189 r#"
190fn foo<'a$0>() {}
191"#,
192 expect![[r#""#]],
193 );
194 check(
195 r#"
196fn foo<'footime, 'lifetime: 'a$0>() {}
197"#,
198 expect![[r#"
199 lt 'footime
200 "#]],
201 );
202 }
203
204 #[test]
205 fn check_label_edit() {
206 check_edit(
207 "'label",
208 r#"
209fn foo() {
210 'label: loop {
211 break '$0
212 }
213}
214"#,
215 r#"
216fn foo() {
217 'label: loop {
218 break 'label
219 }
220}
221"#,
222 );
223 }
224
225 #[test]
226 fn complete_label_in_loop() {
227 check(
228 r#"
229fn foo() {
230 'foop: loop {
231 break '$0
232 }
233}
234"#,
235 expect![[r#"
236 lb 'foop
237 "#]],
238 );
239 check(
240 r#"
241fn foo() {
242 'foop: loop {
243 continue '$0
244 }
245}
246"#,
247 expect![[r#"
248 lb 'foop
249 "#]],
250 );
251 }
252
253 #[test]
254 fn complete_label_in_block_nested() {
255 check(
256 r#"
257fn foo() {
258 'foop: {
259 'baap: {
260 break '$0
261 }
262 }
263}
264"#,
265 expect![[r#"
266 lb 'baap
267 lb 'foop
268 "#]],
269 );
270 }
271
272 #[test]
273 fn complete_label_in_loop_with_value() {
274 check(
275 r#"
276fn foo() {
277 'foop: loop {
278 break '$0 i32;
279 }
280}
281"#,
282 expect![[r#"
283 lb 'foop
284 "#]],
285 );
286 }
287
288 #[test]
289 fn complete_label_in_while_cond() {
290 check(
291 r#"
292fn foo() {
293 'outer: while { 'inner: loop { break '$0 } } {}
294}
295"#,
296 expect![[r#"
297 lb 'inner
298 lb 'outer
299 "#]],
300 );
301 }
302
303 #[test]
304 fn complete_label_in_for_iterable() {
305 check(
306 r#"
307fn foo() {
308 'outer: for _ in [{ 'inner: loop { break '$0 } }] {}
309}
310"#,
311 expect![[r#"
312 lb 'inner
313 "#]],
314 );
315 }
316}
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index 476eecff0..b06498e6d 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -1,4 +1,4 @@
1//! Completes constats and paths in patterns. 1//! Completes constants and paths in patterns.
2 2
3use crate::{CompletionContext, Completions}; 3use crate::{CompletionContext, Completions};
4 4