diff options
20 files changed, 730 insertions, 735 deletions
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 03b8dd767..916d39a0b 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! cfg defines conditional compiling options, `cfg` attibute parser and evaluator | 1 | //! cfg defines conditional compiling options, `cfg` attribute parser and evaluator |
2 | 2 | ||
3 | mod cfg_expr; | 3 | mod cfg_expr; |
4 | mod dnf; | 4 | mod dnf; |
@@ -52,6 +52,7 @@ impl CfgOptions { | |||
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
55 | pub struct CfgDiff { | 56 | pub struct CfgDiff { |
56 | // Invariants: No duplicates, no atom that's both in `enable` and `disable`. | 57 | // Invariants: No duplicates, no atom that's both in `enable` and `disable`. |
57 | enable: Vec<CfgAtom>, | 58 | enable: Vec<CfgAtom>, |
@@ -59,6 +60,20 @@ pub struct CfgDiff { | |||
59 | } | 60 | } |
60 | 61 | ||
61 | impl CfgDiff { | 62 | impl CfgDiff { |
63 | /// Create a new CfgDiff. Will return None if the same item appears more than once in the set | ||
64 | /// of both. | ||
65 | pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> { | ||
66 | let mut occupied = FxHashSet::default(); | ||
67 | for item in enable.iter().chain(disable.iter()) { | ||
68 | if !occupied.insert(item) { | ||
69 | // was present | ||
70 | return None; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | Some(CfgDiff { enable, disable }) | ||
75 | } | ||
76 | |||
62 | /// Returns the total number of atoms changed by this diff. | 77 | /// Returns the total number of atoms changed by this diff. |
63 | pub fn len(&self) -> usize { | 78 | pub fn len(&self) -> usize { |
64 | self.enable.len() + self.disable.len() | 79 | self.enable.len() + self.disable.len() |
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index 4ad49eca0..37ae92350 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs | |||
@@ -23,7 +23,7 @@ use syntax::{ | |||
23 | algo::find_node_at_offset, | 23 | algo::find_node_at_offset, |
24 | ast::{self, edit::IndentLevel, AstToken}, | 24 | ast::{self, edit::IndentLevel, AstToken}, |
25 | AstNode, Parse, SourceFile, | 25 | AstNode, Parse, SourceFile, |
26 | SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, | 26 | SyntaxKind::{self, FIELD_EXPR, METHOD_CALL_EXPR}, |
27 | TextRange, TextSize, | 27 | TextRange, TextSize, |
28 | }; | 28 | }; |
29 | 29 | ||
@@ -95,9 +95,16 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option< | |||
95 | } | 95 | } |
96 | 96 | ||
97 | let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; | 97 | let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; |
98 | if brace_token.kind() != SyntaxKind::L_CURLY { | ||
99 | return None; | ||
100 | } | ||
98 | 101 | ||
99 | // Remove the `{` to get a better parse tree, and reparse | 102 | // Remove the `{` to get a better parse tree, and reparse. |
100 | let file = file.reparse(&Indel::delete(brace_token.text_range())); | 103 | let range = brace_token.text_range(); |
104 | if !stdx::always!(range.len() == TextSize::of('{')) { | ||
105 | return None; | ||
106 | } | ||
107 | let file = file.reparse(&Indel::delete(range)); | ||
101 | 108 | ||
102 | if let Some(edit) = brace_expr(&file.tree(), offset) { | 109 | if let Some(edit) = brace_expr(&file.tree(), offset) { |
103 | return Some(edit); | 110 | return Some(edit); |
@@ -550,6 +557,29 @@ fn f() { | |||
550 | } | 557 | } |
551 | 558 | ||
552 | #[test] | 559 | #[test] |
560 | fn noop_in_string_literal() { | ||
561 | // Regression test for #9351 | ||
562 | type_char_noop( | ||
563 | '{', | ||
564 | r##" | ||
565 | fn check_with(ra_fixture: &str, expect: Expect) { | ||
566 | let base = r#" | ||
567 | enum E { T(), R$0, C } | ||
568 | use self::E::X; | ||
569 | const Z: E = E::C; | ||
570 | mod m {} | ||
571 | asdasdasdasdasdasda | ||
572 | sdasdasdasdasdasda | ||
573 | sdasdasdasdasd | ||
574 | "#; | ||
575 | let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); | ||
576 | expect.assert_eq(&actual) | ||
577 | } | ||
578 | "##, | ||
579 | ); | ||
580 | } | ||
581 | |||
582 | #[test] | ||
553 | fn adds_closing_brace_for_use_tree() { | 583 | fn adds_closing_brace_for_use_tree() { |
554 | type_char( | 584 | type_char( |
555 | '{', | 585 | '{', |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 07541c79c..407f796ef 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -92,7 +92,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
92 | } | 92 | } |
93 | 93 | ||
94 | if !ctx.has_visibility_prev_sibling() | 94 | if !ctx.has_visibility_prev_sibling() |
95 | && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field()) | 95 | && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field()) |
96 | { | 96 | { |
97 | add_keyword("pub(crate)", "pub(crate) "); | 97 | add_keyword("pub(crate)", "pub(crate) "); |
98 | add_keyword("pub", "pub "); | 98 | add_keyword("pub", "pub "); |
@@ -122,6 +122,10 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
122 | add_keyword("union", "union $1 {\n $0\n}"); | 122 | add_keyword("union", "union $1 {\n $0\n}"); |
123 | } | 123 | } |
124 | 124 | ||
125 | if ctx.expects_type() { | ||
126 | return; | ||
127 | } | ||
128 | |||
125 | if ctx.expects_expression() { | 129 | if ctx.expects_expression() { |
126 | if !has_block_expr_parent { | 130 | if !has_block_expr_parent { |
127 | add_keyword("unsafe", "unsafe {\n $0\n}"); | 131 | add_keyword("unsafe", "unsafe {\n $0\n}"); |
@@ -373,28 +377,6 @@ fn quux() -> i32 { | |||
373 | } | 377 | } |
374 | 378 | ||
375 | #[test] | 379 | #[test] |
376 | fn test_mut_in_ref_and_in_fn_parameters_list() { | ||
377 | check( | ||
378 | r"fn my_fn(&$0) {}", | ||
379 | expect![[r#" | ||
380 | kw mut | ||
381 | "#]], | ||
382 | ); | ||
383 | check( | ||
384 | r"fn my_fn($0) {}", | ||
385 | expect![[r#" | ||
386 | kw mut | ||
387 | "#]], | ||
388 | ); | ||
389 | check( | ||
390 | r"fn my_fn() { let &$0 }", | ||
391 | expect![[r#" | ||
392 | kw mut | ||
393 | "#]], | ||
394 | ); | ||
395 | } | ||
396 | |||
397 | #[test] | ||
398 | fn no_keyword_completion_in_comments() { | 380 | fn no_keyword_completion_in_comments() { |
399 | cov_mark::check!(no_keyword_completion_in_comments); | 381 | cov_mark::check!(no_keyword_completion_in_comments); |
400 | check( | 382 | check( |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index efe3c957a..bd13a62d7 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -55,398 +55,3 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
55 | } | 55 | } |
56 | }); | 56 | }); |
57 | } | 57 | } |
58 | |||
59 | #[cfg(test)] | ||
60 | mod tests { | ||
61 | use expect_test::{expect, Expect}; | ||
62 | |||
63 | use crate::{ | ||
64 | tests::{check_edit, filtered_completion_list}, | ||
65 | CompletionKind, | ||
66 | }; | ||
67 | |||
68 | fn check(ra_fixture: &str, expect: Expect) { | ||
69 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); | ||
70 | expect.assert_eq(&actual) | ||
71 | } | ||
72 | |||
73 | fn check_snippet(ra_fixture: &str, expect: Expect) { | ||
74 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet); | ||
75 | expect.assert_eq(&actual) | ||
76 | } | ||
77 | |||
78 | #[test] | ||
79 | fn completes_enum_variants_and_modules() { | ||
80 | check( | ||
81 | r#" | ||
82 | enum E { X } | ||
83 | use self::E::X; | ||
84 | const Z: E = E::X; | ||
85 | mod m {} | ||
86 | |||
87 | static FOO: E = E::X; | ||
88 | struct Bar { f: u32 } | ||
89 | |||
90 | fn foo() { | ||
91 | match E::X { a$0 } | ||
92 | } | ||
93 | "#, | ||
94 | expect![[r#" | ||
95 | en E | ||
96 | ct Z | ||
97 | st Bar | ||
98 | ev X | ||
99 | md m | ||
100 | "#]], | ||
101 | ); | ||
102 | } | ||
103 | |||
104 | #[test] | ||
105 | fn does_not_complete_non_fn_macros() { | ||
106 | check( | ||
107 | r#" | ||
108 | macro_rules! m { ($e:expr) => { $e } } | ||
109 | enum E { X } | ||
110 | |||
111 | #[rustc_builtin_macro] | ||
112 | macro Clone {} | ||
113 | |||
114 | fn foo() { | ||
115 | match E::X { $0 } | ||
116 | } | ||
117 | "#, | ||
118 | expect![[r#" | ||
119 | ev E::X () | ||
120 | en E | ||
121 | ma m!(…) macro_rules! m | ||
122 | "#]], | ||
123 | ); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
127 | fn completes_in_simple_macro_call() { | ||
128 | check( | ||
129 | r#" | ||
130 | macro_rules! m { ($e:expr) => { $e } } | ||
131 | enum E { X } | ||
132 | |||
133 | fn foo() { | ||
134 | m!(match E::X { a$0 }) | ||
135 | } | ||
136 | "#, | ||
137 | expect![[r#" | ||
138 | ev E::X () | ||
139 | en E | ||
140 | ma m!(…) macro_rules! m | ||
141 | "#]], | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn completes_in_irrefutable_let() { | ||
147 | check( | ||
148 | r#" | ||
149 | enum E { X } | ||
150 | use self::E::X; | ||
151 | const Z: E = E::X; | ||
152 | mod m {} | ||
153 | |||
154 | static FOO: E = E::X; | ||
155 | struct Bar { f: u32 } | ||
156 | |||
157 | fn foo() { | ||
158 | let a$0 | ||
159 | } | ||
160 | "#, | ||
161 | expect![[r#" | ||
162 | st Bar | ||
163 | "#]], | ||
164 | ); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn completes_in_param() { | ||
169 | check( | ||
170 | r#" | ||
171 | enum E { X } | ||
172 | |||
173 | static FOO: E = E::X; | ||
174 | struct Bar { f: u32 } | ||
175 | |||
176 | fn foo(a$0) { | ||
177 | } | ||
178 | "#, | ||
179 | expect![[r#" | ||
180 | st Bar | ||
181 | "#]], | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn completes_pat_in_let() { | ||
187 | check_snippet( | ||
188 | r#" | ||
189 | struct Bar { f: u32 } | ||
190 | |||
191 | fn foo() { | ||
192 | let a$0 | ||
193 | } | ||
194 | "#, | ||
195 | expect![[r#" | ||
196 | bn Bar Bar { f$1 }$0 | ||
197 | "#]], | ||
198 | ); | ||
199 | } | ||
200 | |||
201 | #[test] | ||
202 | fn completes_param_pattern() { | ||
203 | check_snippet( | ||
204 | r#" | ||
205 | struct Foo { bar: String, baz: String } | ||
206 | struct Bar(String, String); | ||
207 | struct Baz; | ||
208 | fn outer(a$0) {} | ||
209 | "#, | ||
210 | expect![[r#" | ||
211 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | ||
212 | bn Bar Bar($1, $2): Bar$0 | ||
213 | "#]], | ||
214 | ) | ||
215 | } | ||
216 | |||
217 | #[test] | ||
218 | fn completes_let_pattern() { | ||
219 | check_snippet( | ||
220 | r#" | ||
221 | struct Foo { bar: String, baz: String } | ||
222 | struct Bar(String, String); | ||
223 | struct Baz; | ||
224 | fn outer() { | ||
225 | let a$0 | ||
226 | } | ||
227 | "#, | ||
228 | expect![[r#" | ||
229 | bn Foo Foo { bar$1, baz$2 }$0 | ||
230 | bn Bar Bar($1, $2)$0 | ||
231 | "#]], | ||
232 | ) | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn completes_refutable_pattern() { | ||
237 | check_snippet( | ||
238 | r#" | ||
239 | struct Foo { bar: i32, baz: i32 } | ||
240 | struct Bar(String, String); | ||
241 | struct Baz; | ||
242 | fn outer() { | ||
243 | match () { | ||
244 | a$0 | ||
245 | } | ||
246 | } | ||
247 | "#, | ||
248 | expect![[r#" | ||
249 | bn Foo Foo { bar$1, baz$2 }$0 | ||
250 | bn Bar Bar($1, $2)$0 | ||
251 | "#]], | ||
252 | ) | ||
253 | } | ||
254 | |||
255 | #[test] | ||
256 | fn omits_private_fields_pat() { | ||
257 | check_snippet( | ||
258 | r#" | ||
259 | mod foo { | ||
260 | pub struct Foo { pub bar: i32, baz: i32 } | ||
261 | pub struct Bar(pub String, String); | ||
262 | pub struct Invisible(String, String); | ||
263 | } | ||
264 | use foo::*; | ||
265 | |||
266 | fn outer() { | ||
267 | match () { | ||
268 | a$0 | ||
269 | } | ||
270 | } | ||
271 | "#, | ||
272 | expect![[r#" | ||
273 | bn Foo Foo { bar$1, .. }$0 | ||
274 | bn Bar Bar($1, ..)$0 | ||
275 | "#]], | ||
276 | ) | ||
277 | } | ||
278 | |||
279 | #[test] | ||
280 | fn only_shows_ident_completion() { | ||
281 | check_edit( | ||
282 | "Foo", | ||
283 | r#" | ||
284 | struct Foo(i32); | ||
285 | fn main() { | ||
286 | match Foo(92) { | ||
287 | a$0(92) => (), | ||
288 | } | ||
289 | } | ||
290 | "#, | ||
291 | r#" | ||
292 | struct Foo(i32); | ||
293 | fn main() { | ||
294 | match Foo(92) { | ||
295 | Foo(92) => (), | ||
296 | } | ||
297 | } | ||
298 | "#, | ||
299 | ); | ||
300 | } | ||
301 | |||
302 | #[test] | ||
303 | fn completes_self_pats() { | ||
304 | check_snippet( | ||
305 | r#" | ||
306 | struct Foo(i32); | ||
307 | impl Foo { | ||
308 | fn foo() { | ||
309 | match () { | ||
310 | a$0 | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | "#, | ||
315 | expect![[r#" | ||
316 | bn Self Self($1)$0 | ||
317 | bn Foo Foo($1)$0 | ||
318 | "#]], | ||
319 | ) | ||
320 | } | ||
321 | |||
322 | #[test] | ||
323 | fn completes_qualified_variant() { | ||
324 | check_snippet( | ||
325 | r#" | ||
326 | enum Foo { | ||
327 | Bar { baz: i32 } | ||
328 | } | ||
329 | impl Foo { | ||
330 | fn foo() { | ||
331 | match {Foo::Bar { baz: 0 }} { | ||
332 | B$0 | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | "#, | ||
337 | expect![[r#" | ||
338 | bn Self::Bar Self::Bar { baz$1 }$0 | ||
339 | bn Foo::Bar Foo::Bar { baz$1 }$0 | ||
340 | "#]], | ||
341 | ) | ||
342 | } | ||
343 | |||
344 | #[test] | ||
345 | fn completes_enum_variant_matcharm() { | ||
346 | check( | ||
347 | r#" | ||
348 | enum Foo { Bar, Baz, Quux } | ||
349 | |||
350 | fn main() { | ||
351 | let foo = Foo::Quux; | ||
352 | match foo { Qu$0 } | ||
353 | } | ||
354 | "#, | ||
355 | expect![[r#" | ||
356 | ev Foo::Bar () | ||
357 | ev Foo::Baz () | ||
358 | ev Foo::Quux () | ||
359 | en Foo | ||
360 | "#]], | ||
361 | ) | ||
362 | } | ||
363 | |||
364 | #[test] | ||
365 | fn completes_enum_variant_matcharm_ref() { | ||
366 | check( | ||
367 | r#" | ||
368 | enum Foo { Bar, Baz, Quux } | ||
369 | |||
370 | fn main() { | ||
371 | let foo = Foo::Quux; | ||
372 | match &foo { Qu$0 } | ||
373 | } | ||
374 | "#, | ||
375 | expect![[r#" | ||
376 | ev Foo::Bar () | ||
377 | ev Foo::Baz () | ||
378 | ev Foo::Quux () | ||
379 | en Foo | ||
380 | "#]], | ||
381 | ) | ||
382 | } | ||
383 | |||
384 | #[test] | ||
385 | fn completes_enum_variant_iflet() { | ||
386 | check( | ||
387 | r#" | ||
388 | enum Foo { Bar, Baz, Quux } | ||
389 | |||
390 | fn main() { | ||
391 | let foo = Foo::Quux; | ||
392 | if let Qu$0 = foo { } | ||
393 | } | ||
394 | "#, | ||
395 | expect![[r#" | ||
396 | ev Foo::Bar () | ||
397 | ev Foo::Baz () | ||
398 | ev Foo::Quux () | ||
399 | en Foo | ||
400 | "#]], | ||
401 | ) | ||
402 | } | ||
403 | |||
404 | #[test] | ||
405 | fn completes_enum_variant_impl() { | ||
406 | check( | ||
407 | r#" | ||
408 | enum Foo { Bar, Baz, Quux } | ||
409 | impl Foo { | ||
410 | fn foo() { match Foo::Bar { Q$0 } } | ||
411 | } | ||
412 | "#, | ||
413 | expect![[r#" | ||
414 | ev Self::Bar () | ||
415 | ev Self::Baz () | ||
416 | ev Self::Quux () | ||
417 | ev Foo::Bar () | ||
418 | ev Foo::Baz () | ||
419 | ev Foo::Quux () | ||
420 | sp Self | ||
421 | en Foo | ||
422 | "#]], | ||
423 | ) | ||
424 | } | ||
425 | |||
426 | #[test] | ||
427 | fn completes_in_record_field_pat() { | ||
428 | check_snippet( | ||
429 | r#" | ||
430 | struct Foo { bar: Bar } | ||
431 | struct Bar(u32); | ||
432 | fn outer(Foo { bar: $0 }: Foo) {} | ||
433 | "#, | ||
434 | expect![[r#" | ||
435 | bn Foo Foo { bar$1 }$0 | ||
436 | bn Bar Bar($1)$0 | ||
437 | "#]], | ||
438 | ) | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn skips_in_record_field_pat_name() { | ||
443 | check_snippet( | ||
444 | r#" | ||
445 | struct Foo { bar: Bar } | ||
446 | struct Bar(u32); | ||
447 | fn outer(Foo { bar$0 }: Foo) {} | ||
448 | "#, | ||
449 | expect![[r#""#]], | ||
450 | ) | ||
451 | } | ||
452 | } | ||
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index f5dbd203b..1b8997ecf 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -219,36 +219,6 @@ mod tests { | |||
219 | } | 219 | } |
220 | 220 | ||
221 | #[test] | 221 | #[test] |
222 | fn dont_complete_values_in_type_pos() { | ||
223 | check( | ||
224 | r#" | ||
225 | const FOO: () = (); | ||
226 | static BAR: () = (); | ||
227 | struct Baz; | ||
228 | fn foo() { | ||
229 | let _: self::$0; | ||
230 | } | ||
231 | "#, | ||
232 | expect![[r#" | ||
233 | st Baz | ||
234 | "#]], | ||
235 | ); | ||
236 | } | ||
237 | |||
238 | #[test] | ||
239 | fn dont_complete_enum_variants_in_type_pos() { | ||
240 | check( | ||
241 | r#" | ||
242 | enum Foo { Bar } | ||
243 | fn foo() { | ||
244 | let _: Foo::$0; | ||
245 | } | ||
246 | "#, | ||
247 | expect![[r#""#]], | ||
248 | ); | ||
249 | } | ||
250 | |||
251 | #[test] | ||
252 | fn dont_complete_primitive_in_use() { | 222 | fn dont_complete_primitive_in_use() { |
253 | check_builtin(r#"use self::$0;"#, expect![[""]]); | 223 | check_builtin(r#"use self::$0;"#, expect![[""]]); |
254 | } | 224 | } |
@@ -259,32 +229,6 @@ fn foo() { | |||
259 | } | 229 | } |
260 | 230 | ||
261 | #[test] | 231 | #[test] |
262 | fn completes_primitives() { | ||
263 | check_builtin( | ||
264 | r#"fn main() { let _: $0 = 92; }"#, | ||
265 | expect![[r#" | ||
266 | bt u32 | ||
267 | bt bool | ||
268 | bt u8 | ||
269 | bt isize | ||
270 | bt u16 | ||
271 | bt u64 | ||
272 | bt u128 | ||
273 | bt f32 | ||
274 | bt i128 | ||
275 | bt i16 | ||
276 | bt str | ||
277 | bt i64 | ||
278 | bt char | ||
279 | bt f64 | ||
280 | bt i32 | ||
281 | bt i8 | ||
282 | bt usize | ||
283 | "#]], | ||
284 | ); | ||
285 | } | ||
286 | |||
287 | #[test] | ||
288 | fn completes_enum_variant() { | 232 | fn completes_enum_variant() { |
289 | check( | 233 | check( |
290 | r#" | 234 | r#" |
@@ -749,24 +693,4 @@ fn main() { | |||
749 | "#]], | 693 | "#]], |
750 | ); | 694 | ); |
751 | } | 695 | } |
752 | |||
753 | #[test] | ||
754 | fn completes_types_and_const_in_arg_list() { | ||
755 | check( | ||
756 | r#" | ||
757 | mod foo { | ||
758 | pub const CONST: () = (); | ||
759 | pub type Type = (); | ||
760 | } | ||
761 | |||
762 | struct Foo<T>(t); | ||
763 | |||
764 | fn foo(_: Foo<foo::$0>) {} | ||
765 | "#, | ||
766 | expect![[r#" | ||
767 | ta Type | ||
768 | ct CONST | ||
769 | "#]], | ||
770 | ); | ||
771 | } | ||
772 | } | 696 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 81c4fb305..380c1e079 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -113,78 +113,6 @@ mod tests { | |||
113 | } | 113 | } |
114 | 114 | ||
115 | #[test] | 115 | #[test] |
116 | fn dont_complete_values_in_type_pos() { | ||
117 | check( | ||
118 | r#" | ||
119 | const FOO: () = (); | ||
120 | static BAR: () = (); | ||
121 | enum Foo { | ||
122 | Bar | ||
123 | } | ||
124 | struct Baz; | ||
125 | fn foo() { | ||
126 | let local = (); | ||
127 | let _: $0; | ||
128 | } | ||
129 | "#, | ||
130 | expect![[r#" | ||
131 | en Foo | ||
132 | st Baz | ||
133 | "#]], | ||
134 | ); | ||
135 | } | ||
136 | |||
137 | #[test] | ||
138 | fn bind_pat_and_path_ignore_at() { | ||
139 | check( | ||
140 | r#" | ||
141 | enum Enum { A, B } | ||
142 | fn quux(x: Option<Enum>) { | ||
143 | match x { | ||
144 | None => (), | ||
145 | Some(en$0 @ Enum::A) => (), | ||
146 | } | ||
147 | } | ||
148 | "#, | ||
149 | expect![[r#""#]], | ||
150 | ); | ||
151 | } | ||
152 | |||
153 | #[test] | ||
154 | fn bind_pat_and_path_ignore_ref() { | ||
155 | check( | ||
156 | r#" | ||
157 | enum Enum { A, B } | ||
158 | fn quux(x: Option<Enum>) { | ||
159 | match x { | ||
160 | None => (), | ||
161 | Some(ref en$0) => (), | ||
162 | } | ||
163 | } | ||
164 | "#, | ||
165 | expect![[r#""#]], | ||
166 | ); | ||
167 | } | ||
168 | |||
169 | #[test] | ||
170 | fn bind_pat_and_path() { | ||
171 | check( | ||
172 | r#" | ||
173 | enum Enum { A, B } | ||
174 | fn quux(x: Option<Enum>) { | ||
175 | match x { | ||
176 | None => (), | ||
177 | Some(En$0) => (), | ||
178 | } | ||
179 | } | ||
180 | "#, | ||
181 | expect![[r#" | ||
182 | en Enum | ||
183 | "#]], | ||
184 | ); | ||
185 | } | ||
186 | |||
187 | #[test] | ||
188 | fn completes_bindings_from_let() { | 116 | fn completes_bindings_from_let() { |
189 | check( | 117 | check( |
190 | r#" | 118 | r#" |
@@ -289,29 +217,6 @@ fn main() { | |||
289 | } | 217 | } |
290 | 218 | ||
291 | #[test] | 219 | #[test] |
292 | fn completes_generic_params_in_struct() { | ||
293 | check( | ||
294 | r#"struct S<T> { x: $0}"#, | ||
295 | expect![[r#" | ||
296 | sp Self | ||
297 | tp T | ||
298 | st S<…> | ||
299 | "#]], | ||
300 | ); | ||
301 | } | ||
302 | |||
303 | #[test] | ||
304 | fn completes_self_in_enum() { | ||
305 | check( | ||
306 | r#"enum X { Y($0) }"#, | ||
307 | expect![[r#" | ||
308 | sp Self | ||
309 | en X | ||
310 | "#]], | ||
311 | ); | ||
312 | } | ||
313 | |||
314 | #[test] | ||
315 | fn completes_module_items() { | 220 | fn completes_module_items() { |
316 | check( | 221 | check( |
317 | r#" | 222 | r#" |
@@ -365,19 +270,6 @@ mod m { | |||
365 | } | 270 | } |
366 | 271 | ||
367 | #[test] | 272 | #[test] |
368 | fn completes_return_type() { | ||
369 | check( | ||
370 | r#" | ||
371 | struct Foo; | ||
372 | fn x() -> $0 | ||
373 | "#, | ||
374 | expect![[r#" | ||
375 | st Foo | ||
376 | "#]], | ||
377 | ); | ||
378 | } | ||
379 | |||
380 | #[test] | ||
381 | fn dont_show_both_completions_for_shadowing() { | 273 | fn dont_show_both_completions_for_shadowing() { |
382 | check( | 274 | check( |
383 | r#" | 275 | r#" |
@@ -559,19 +451,6 @@ fn foo() { $0 } | |||
559 | } | 451 | } |
560 | 452 | ||
561 | #[test] | 453 | #[test] |
562 | fn completes_macros_as_type() { | ||
563 | check( | ||
564 | r#" | ||
565 | macro_rules! foo { () => {} } | ||
566 | fn main() { let x: $0 } | ||
567 | "#, | ||
568 | expect![[r#" | ||
569 | ma foo!(…) macro_rules! foo | ||
570 | "#]], | ||
571 | ); | ||
572 | } | ||
573 | |||
574 | #[test] | ||
575 | fn completes_macros_as_stmt() { | 454 | fn completes_macros_as_stmt() { |
576 | check( | 455 | check( |
577 | r#" | 456 | r#" |
@@ -716,30 +595,4 @@ fn f() {} | |||
716 | expect![[""]], | 595 | expect![[""]], |
717 | ) | 596 | ) |
718 | } | 597 | } |
719 | |||
720 | #[test] | ||
721 | fn completes_types_and_const_in_arg_list() { | ||
722 | check( | ||
723 | r#" | ||
724 | enum Bar { | ||
725 | Baz | ||
726 | } | ||
727 | trait Foo { | ||
728 | type Bar; | ||
729 | } | ||
730 | |||
731 | const CONST: () = (); | ||
732 | |||
733 | fn foo<T: Foo<$0>, const CONST_PARAM: usize>(_: T) {} | ||
734 | "#, | ||
735 | expect![[r#" | ||
736 | ta Bar = type Bar; | ||
737 | tp T | ||
738 | cp CONST_PARAM | ||
739 | tt Foo | ||
740 | en Bar | ||
741 | ct CONST | ||
742 | "#]], | ||
743 | ); | ||
744 | } | ||
745 | } | 598 | } |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 7b76600df..f0da98739 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -286,8 +286,11 @@ impl<'a> CompletionContext<'a> { | |||
286 | ) | 286 | ) |
287 | } | 287 | } |
288 | 288 | ||
289 | pub(crate) fn expect_record_field(&self) -> bool { | 289 | pub(crate) fn expect_field(&self) -> bool { |
290 | matches!(self.completion_location, Some(ImmediateLocation::RecordField)) | 290 | matches!( |
291 | self.completion_location, | ||
292 | Some(ImmediateLocation::RecordField | ImmediateLocation::TupleField) | ||
293 | ) | ||
291 | } | 294 | } |
292 | 295 | ||
293 | pub(crate) fn in_use_tree(&self) -> bool { | 296 | pub(crate) fn in_use_tree(&self) -> bool { |
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 271409c38..757c9a3da 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -31,6 +31,7 @@ pub(crate) enum ImmediateLocation { | |||
31 | Impl, | 31 | Impl, |
32 | Trait, | 32 | Trait, |
33 | RecordField, | 33 | RecordField, |
34 | TupleField, | ||
34 | RefExpr, | 35 | RefExpr, |
35 | IdentPat, | 36 | IdentPat, |
36 | BlockExpr, | 37 | BlockExpr, |
@@ -187,7 +188,13 @@ pub(crate) fn determine_location( | |||
187 | ast::SourceFile(_it) => ImmediateLocation::ItemList, | 188 | ast::SourceFile(_it) => ImmediateLocation::ItemList, |
188 | ast::ItemList(_it) => ImmediateLocation::ItemList, | 189 | ast::ItemList(_it) => ImmediateLocation::ItemList, |
189 | ast::RefExpr(_it) => ImmediateLocation::RefExpr, | 190 | ast::RefExpr(_it) => ImmediateLocation::RefExpr, |
190 | ast::RecordField(_it) => ImmediateLocation::RecordField, | 191 | ast::RecordField(it) => if it.ty().map_or(false, |it| it.syntax().text_range().contains(offset)) { |
192 | return None; | ||
193 | } else { | ||
194 | ImmediateLocation::RecordField | ||
195 | }, | ||
196 | ast::TupleField(_it) => ImmediateLocation::TupleField, | ||
197 | ast::TupleFieldList(_it) => ImmediateLocation::TupleField, | ||
191 | ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { | 198 | ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { |
192 | Some(IMPL) => ImmediateLocation::Impl, | 199 | Some(IMPL) => ImmediateLocation::Impl, |
193 | Some(TRAIT) => ImmediateLocation::Trait, | 200 | Some(TRAIT) => ImmediateLocation::Trait, |
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs index 211c89c40..97298ff27 100644 --- a/crates/ide_completion/src/tests.rs +++ b/crates/ide_completion/src/tests.rs | |||
@@ -7,6 +7,10 @@ | |||
7 | mod item_list; | 7 | mod item_list; |
8 | mod use_tree; | 8 | mod use_tree; |
9 | mod items; | 9 | mod items; |
10 | mod pattern; | ||
11 | mod type_pos; | ||
12 | |||
13 | use std::mem; | ||
10 | 14 | ||
11 | use hir::{PrefixKind, Semantics}; | 15 | use hir::{PrefixKind, Semantics}; |
12 | use ide_db::{ | 16 | use ide_db::{ |
@@ -45,7 +49,16 @@ pub(crate) fn completion_list(code: &str) -> String { | |||
45 | } | 49 | } |
46 | 50 | ||
47 | fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { | 51 | fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { |
48 | render_completion_list(get_all_items(config, code)) | 52 | // filter out all but one builtintype completion for smaller test outputs |
53 | let items = get_all_items(config, code); | ||
54 | let mut bt_seen = false; | ||
55 | let items = items | ||
56 | .into_iter() | ||
57 | .filter(|it| { | ||
58 | it.completion_kind != CompletionKind::BuiltinType || !mem::replace(&mut bt_seen, true) | ||
59 | }) | ||
60 | .collect(); | ||
61 | render_completion_list(items) | ||
49 | } | 62 | } |
50 | 63 | ||
51 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 64 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
diff --git a/crates/ide_completion/src/tests/items.rs b/crates/ide_completion/src/tests/items.rs index 8dfb8221b..b98baffd6 100644 --- a/crates/ide_completion/src/tests/items.rs +++ b/crates/ide_completion/src/tests/items.rs | |||
@@ -35,22 +35,6 @@ impl Tra$0 | |||
35 | ma foo!(…) #[macro_export] macro_rules! foo | 35 | ma foo!(…) #[macro_export] macro_rules! foo |
36 | ma foo!(…) #[macro_export] macro_rules! foo | 36 | ma foo!(…) #[macro_export] macro_rules! foo |
37 | bt u32 | 37 | bt u32 |
38 | bt bool | ||
39 | bt u8 | ||
40 | bt isize | ||
41 | bt u16 | ||
42 | bt u64 | ||
43 | bt u128 | ||
44 | bt f32 | ||
45 | bt i128 | ||
46 | bt i16 | ||
47 | bt str | ||
48 | bt i64 | ||
49 | bt char | ||
50 | bt f64 | ||
51 | bt i32 | ||
52 | bt i8 | ||
53 | bt usize | ||
54 | "##]], | 38 | "##]], |
55 | ) | 39 | ) |
56 | } | 40 | } |
@@ -69,22 +53,6 @@ impl Trait for Str$0 | |||
69 | ma foo!(…) #[macro_export] macro_rules! foo | 53 | ma foo!(…) #[macro_export] macro_rules! foo |
70 | ma foo!(…) #[macro_export] macro_rules! foo | 54 | ma foo!(…) #[macro_export] macro_rules! foo |
71 | bt u32 | 55 | bt u32 |
72 | bt bool | ||
73 | bt u8 | ||
74 | bt isize | ||
75 | bt u16 | ||
76 | bt u64 | ||
77 | bt u128 | ||
78 | bt f32 | ||
79 | bt i128 | ||
80 | bt i16 | ||
81 | bt str | ||
82 | bt i64 | ||
83 | bt char | ||
84 | bt f64 | ||
85 | bt i32 | ||
86 | bt i8 | ||
87 | bt usize | ||
88 | "##]], | 56 | "##]], |
89 | ) | 57 | ) |
90 | } | 58 | } |
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs new file mode 100644 index 000000000..1ad5ccd97 --- /dev/null +++ b/crates/ide_completion/src/tests/pattern.rs | |||
@@ -0,0 +1,348 @@ | |||
1 | //! Completions tests for pattern position. | ||
2 | use expect_test::{expect, Expect}; | ||
3 | |||
4 | use crate::tests::completion_list; | ||
5 | |||
6 | fn check(ra_fixture: &str, expect: Expect) { | ||
7 | let actual = completion_list(ra_fixture); | ||
8 | expect.assert_eq(&actual) | ||
9 | } | ||
10 | |||
11 | fn check_with(ra_fixture: &str, expect: Expect) { | ||
12 | let base = r#" | ||
13 | enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV } | ||
14 | use self::Enum::TupleV; | ||
15 | mod module {} | ||
16 | |||
17 | static STATIC: Unit = Unit; | ||
18 | const CONST: Unit = Unit; | ||
19 | struct Record { field: u32 } | ||
20 | struct Tuple(u32); | ||
21 | struct Unit | ||
22 | macro_rules! makro {} | ||
23 | "#; | ||
24 | let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); | ||
25 | expect.assert_eq(&actual) | ||
26 | } | ||
27 | |||
28 | #[test] | ||
29 | fn ident_rebind_pat() { | ||
30 | check( | ||
31 | r#" | ||
32 | fn quux() { | ||
33 | let en$0 @ x | ||
34 | } | ||
35 | "#, | ||
36 | expect![[r#" | ||
37 | kw mut | ||
38 | "#]], | ||
39 | ); | ||
40 | } | ||
41 | |||
42 | #[test] | ||
43 | fn ident_ref_pat() { | ||
44 | check( | ||
45 | r#" | ||
46 | fn quux() { | ||
47 | let ref en$0 | ||
48 | } | ||
49 | "#, | ||
50 | expect![[r#" | ||
51 | kw mut | ||
52 | "#]], | ||
53 | ); | ||
54 | check( | ||
55 | r#" | ||
56 | fn quux() { | ||
57 | let ref en$0 @ x | ||
58 | } | ||
59 | "#, | ||
60 | expect![[r#" | ||
61 | kw mut | ||
62 | "#]], | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | #[test] | ||
67 | fn ident_ref_mut_pat() { | ||
68 | // FIXME mut is already here, don't complete it again | ||
69 | check( | ||
70 | r#" | ||
71 | fn quux() { | ||
72 | let ref mut en$0 | ||
73 | } | ||
74 | "#, | ||
75 | expect![[r#" | ||
76 | kw mut | ||
77 | "#]], | ||
78 | ); | ||
79 | check( | ||
80 | r#" | ||
81 | fn quux() { | ||
82 | let ref mut en$0 @ x | ||
83 | } | ||
84 | "#, | ||
85 | expect![[r#" | ||
86 | kw mut | ||
87 | "#]], | ||
88 | ); | ||
89 | } | ||
90 | |||
91 | #[test] | ||
92 | fn ref_pat() { | ||
93 | check( | ||
94 | r#" | ||
95 | fn quux() { | ||
96 | let &en$0 | ||
97 | } | ||
98 | "#, | ||
99 | expect![[r#" | ||
100 | kw mut | ||
101 | "#]], | ||
102 | ); | ||
103 | // FIXME mut is already here, don't complete it again | ||
104 | check( | ||
105 | r#" | ||
106 | fn quux() { | ||
107 | let &mut en$0 | ||
108 | } | ||
109 | "#, | ||
110 | expect![[r#" | ||
111 | kw mut | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn refutable() { | ||
118 | check_with( | ||
119 | r#" | ||
120 | fn foo() { | ||
121 | if let a$0 | ||
122 | } | ||
123 | "#, | ||
124 | expect![[r#" | ||
125 | kw mut | ||
126 | bn Record Record { field$1 }$0 | ||
127 | st Record | ||
128 | en Enum | ||
129 | bn Tuple Tuple($1)$0 | ||
130 | st Tuple | ||
131 | md module | ||
132 | bn TupleV TupleV($1)$0 | ||
133 | ev TupleV | ||
134 | st Unit | ||
135 | ct CONST | ||
136 | ma makro!(…) macro_rules! makro | ||
137 | "#]], | ||
138 | ); | ||
139 | } | ||
140 | |||
141 | #[test] | ||
142 | fn irrefutable() { | ||
143 | check_with( | ||
144 | r#" | ||
145 | fn foo() { | ||
146 | let a$0 | ||
147 | } | ||
148 | "#, | ||
149 | expect![[r#" | ||
150 | kw mut | ||
151 | bn Record Record { field$1 }$0 | ||
152 | st Record | ||
153 | bn Tuple Tuple($1)$0 | ||
154 | st Tuple | ||
155 | st Unit | ||
156 | ma makro!(…) macro_rules! makro | ||
157 | "#]], | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn in_param() { | ||
163 | check_with( | ||
164 | r#" | ||
165 | fn foo(a$0) { | ||
166 | } | ||
167 | "#, | ||
168 | expect![[r#" | ||
169 | kw mut | ||
170 | bn Record Record { field$1 }: Record$0 | ||
171 | st Record | ||
172 | bn Tuple Tuple($1): Tuple$0 | ||
173 | st Tuple | ||
174 | st Unit | ||
175 | ma makro!(…) macro_rules! makro | ||
176 | "#]], | ||
177 | ); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn only_fn_like_macros() { | ||
182 | check( | ||
183 | r#" | ||
184 | macro_rules! m { ($e:expr) => { $e } } | ||
185 | |||
186 | #[rustc_builtin_macro] | ||
187 | macro Clone {} | ||
188 | |||
189 | fn foo() { | ||
190 | let x$0 | ||
191 | } | ||
192 | "#, | ||
193 | expect![[r#" | ||
194 | kw mut | ||
195 | ma m!(…) macro_rules! m | ||
196 | "#]], | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
201 | fn in_simple_macro_call() { | ||
202 | check( | ||
203 | r#" | ||
204 | macro_rules! m { ($e:expr) => { $e } } | ||
205 | enum E { X } | ||
206 | |||
207 | fn foo() { | ||
208 | m!(match E::X { a$0 }) | ||
209 | } | ||
210 | "#, | ||
211 | expect![[r#" | ||
212 | kw mut | ||
213 | ev E::X () | ||
214 | en E | ||
215 | ma m!(…) macro_rules! m | ||
216 | "#]], | ||
217 | ); | ||
218 | } | ||
219 | |||
220 | #[test] | ||
221 | fn omits_private_fields_pat() { | ||
222 | check( | ||
223 | r#" | ||
224 | mod foo { | ||
225 | pub struct Record { pub field: i32, _field: i32 } | ||
226 | pub struct Tuple(pub u32, u32); | ||
227 | pub struct Invisible(u32, u32); | ||
228 | } | ||
229 | use foo::*; | ||
230 | |||
231 | fn outer() { | ||
232 | if let a$0 | ||
233 | } | ||
234 | "#, | ||
235 | expect![[r#" | ||
236 | kw mut | ||
237 | bn Record Record { field$1, .. }$0 | ||
238 | st Record | ||
239 | bn Tuple Tuple($1, ..)$0 | ||
240 | st Tuple | ||
241 | st Invisible | ||
242 | md foo | ||
243 | "#]], | ||
244 | ) | ||
245 | } | ||
246 | |||
247 | // #[test] | ||
248 | // fn only_shows_ident_completion() { | ||
249 | // check_edit( | ||
250 | // "Foo", | ||
251 | // r#" | ||
252 | // struct Foo(i32); | ||
253 | // fn main() { | ||
254 | // match Foo(92) { | ||
255 | // a$0(92) => (), | ||
256 | // } | ||
257 | // } | ||
258 | // "#, | ||
259 | // r#" | ||
260 | // struct Foo(i32); | ||
261 | // fn main() { | ||
262 | // match Foo(92) { | ||
263 | // Foo(92) => (), | ||
264 | // } | ||
265 | // } | ||
266 | // "#, | ||
267 | // ); | ||
268 | // } | ||
269 | |||
270 | #[test] | ||
271 | fn completes_self_pats() { | ||
272 | check( | ||
273 | r#" | ||
274 | struct Foo(i32); | ||
275 | impl Foo { | ||
276 | fn foo() { | ||
277 | match Foo(0) { | ||
278 | a$0 | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | "#, | ||
283 | expect![[r#" | ||
284 | kw mut | ||
285 | bn Self Self($1)$0 | ||
286 | sp Self | ||
287 | bn Foo Foo($1)$0 | ||
288 | st Foo | ||
289 | "#]], | ||
290 | ) | ||
291 | } | ||
292 | |||
293 | #[test] | ||
294 | fn completes_qualified_variant() { | ||
295 | check( | ||
296 | r#" | ||
297 | enum Foo { | ||
298 | Bar { baz: i32 } | ||
299 | } | ||
300 | impl Foo { | ||
301 | fn foo() { | ||
302 | match {Foo::Bar { baz: 0 }} { | ||
303 | B$0 | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | "#, | ||
308 | expect![[r#" | ||
309 | kw mut | ||
310 | bn Self::Bar Self::Bar { baz$1 }$0 | ||
311 | ev Self::Bar { baz: i32 } | ||
312 | bn Foo::Bar Foo::Bar { baz$1 }$0 | ||
313 | ev Foo::Bar { baz: i32 } | ||
314 | sp Self | ||
315 | en Foo | ||
316 | "#]], | ||
317 | ) | ||
318 | } | ||
319 | |||
320 | #[test] | ||
321 | fn completes_in_record_field_pat() { | ||
322 | check( | ||
323 | r#" | ||
324 | struct Foo { bar: Bar } | ||
325 | struct Bar(u32); | ||
326 | fn outer(Foo { bar: $0 }: Foo) {} | ||
327 | "#, | ||
328 | expect![[r#" | ||
329 | kw mut | ||
330 | bn Foo Foo { bar$1 }$0 | ||
331 | st Foo | ||
332 | bn Bar Bar($1)$0 | ||
333 | st Bar | ||
334 | "#]], | ||
335 | ) | ||
336 | } | ||
337 | |||
338 | #[test] | ||
339 | fn skips_in_record_field_pat_name() { | ||
340 | check( | ||
341 | r#" | ||
342 | struct Foo { bar: Bar } | ||
343 | struct Bar(u32); | ||
344 | fn outer(Foo { bar$0 }: Foo) {} | ||
345 | "#, | ||
346 | expect![[r#""#]], | ||
347 | ) | ||
348 | } | ||
diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs new file mode 100644 index 000000000..1ab47b27e --- /dev/null +++ b/crates/ide_completion/src/tests/type_pos.rs | |||
@@ -0,0 +1,177 @@ | |||
1 | //! Completions tests for type position. | ||
2 | use expect_test::{expect, Expect}; | ||
3 | |||
4 | use crate::tests::completion_list; | ||
5 | |||
6 | fn check_with(ra_fixture: &str, expect: Expect) { | ||
7 | let base = r#" | ||
8 | enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV } | ||
9 | use self::Enum::TupleV; | ||
10 | mod module {} | ||
11 | |||
12 | trait Trait {} | ||
13 | static STATIC: Unit = Unit; | ||
14 | const CONST: Unit = Unit; | ||
15 | struct Record { field: u32 } | ||
16 | struct Tuple(u32); | ||
17 | struct Unit | ||
18 | macro_rules! makro {} | ||
19 | "#; | ||
20 | let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); | ||
21 | expect.assert_eq(&actual) | ||
22 | } | ||
23 | |||
24 | #[test] | ||
25 | fn record_field_ty() { | ||
26 | check_with( | ||
27 | r#" | ||
28 | struct Foo<'lt, T, const C: usize> { | ||
29 | f: $0 | ||
30 | } | ||
31 | "#, | ||
32 | expect![[r#" | ||
33 | sp Self | ||
34 | tp T | ||
35 | tt Trait | ||
36 | en Enum | ||
37 | st Record | ||
38 | st Tuple | ||
39 | md module | ||
40 | st Foo<…> | ||
41 | st Unit | ||
42 | ma makro!(…) macro_rules! makro | ||
43 | bt u32 | ||
44 | "#]], | ||
45 | ) | ||
46 | } | ||
47 | |||
48 | #[test] | ||
49 | fn tuple_struct_field() { | ||
50 | check_with( | ||
51 | r#" | ||
52 | struct Foo<'lt, T, const C: usize>(f$0); | ||
53 | "#, | ||
54 | expect![[r#" | ||
55 | kw pub(crate) | ||
56 | kw pub | ||
57 | sp Self | ||
58 | tp T | ||
59 | tt Trait | ||
60 | en Enum | ||
61 | st Record | ||
62 | st Tuple | ||
63 | md module | ||
64 | st Foo<…> | ||
65 | st Unit | ||
66 | ma makro!(…) macro_rules! makro | ||
67 | bt u32 | ||
68 | "#]], | ||
69 | ) | ||
70 | } | ||
71 | |||
72 | #[test] | ||
73 | fn fn_return_type() { | ||
74 | check_with( | ||
75 | r#" | ||
76 | fn x<'lt, T, const C: usize>() -> $0 | ||
77 | "#, | ||
78 | expect![[r#" | ||
79 | tp T | ||
80 | tt Trait | ||
81 | en Enum | ||
82 | st Record | ||
83 | st Tuple | ||
84 | md module | ||
85 | st Unit | ||
86 | ma makro!(…) macro_rules! makro | ||
87 | bt u32 | ||
88 | "#]], | ||
89 | ); | ||
90 | } | ||
91 | |||
92 | #[test] | ||
93 | fn body_type_pos() { | ||
94 | check_with( | ||
95 | r#" | ||
96 | fn foo<'lt, T, const C: usize>() { | ||
97 | let local = (); | ||
98 | let _: $0; | ||
99 | } | ||
100 | "#, | ||
101 | expect![[r#" | ||
102 | tp T | ||
103 | tt Trait | ||
104 | en Enum | ||
105 | st Record | ||
106 | st Tuple | ||
107 | md module | ||
108 | st Unit | ||
109 | ma makro!(…) macro_rules! makro | ||
110 | bt u32 | ||
111 | "#]], | ||
112 | ); | ||
113 | check_with( | ||
114 | r#" | ||
115 | fn foo<'lt, T, const C: usize>() { | ||
116 | let local = (); | ||
117 | let _: self::$0; | ||
118 | } | ||
119 | "#, | ||
120 | expect![[r#" | ||
121 | tt Trait | ||
122 | en Enum | ||
123 | st Record | ||
124 | st Tuple | ||
125 | md module | ||
126 | st Unit | ||
127 | "#]], | ||
128 | ); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn completes_types_and_const_in_arg_list() { | ||
133 | // FIXME: we should complete the lifetime here for now | ||
134 | check_with( | ||
135 | r#" | ||
136 | trait Trait2 { | ||
137 | type Foo; | ||
138 | } | ||
139 | |||
140 | fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} | ||
141 | "#, | ||
142 | expect![[r#" | ||
143 | ta Foo = type Foo; | ||
144 | tp T | ||
145 | cp CONST_PARAM | ||
146 | tt Trait | ||
147 | en Enum | ||
148 | st Record | ||
149 | st Tuple | ||
150 | tt Trait2 | ||
151 | md module | ||
152 | st Unit | ||
153 | ct CONST | ||
154 | ma makro!(…) macro_rules! makro | ||
155 | bt u32 | ||
156 | "#]], | ||
157 | ); | ||
158 | check_with( | ||
159 | r#" | ||
160 | trait Trait2 { | ||
161 | type Foo; | ||
162 | } | ||
163 | |||
164 | fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {} | ||
165 | "#, | ||
166 | expect![[r#" | ||
167 | tt Trait | ||
168 | en Enum | ||
169 | st Record | ||
170 | st Tuple | ||
171 | tt Trait2 | ||
172 | md module | ||
173 | st Unit | ||
174 | ct CONST | ||
175 | "#]], | ||
176 | ); | ||
177 | } | ||
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index ac079f83e..0935ea967 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! See [`CargoWorkspace`]. | 1 | //! See [`CargoWorkspace`]. |
2 | 2 | ||
3 | use std::iter; | ||
3 | use std::path::PathBuf; | 4 | use std::path::PathBuf; |
4 | use std::{convert::TryInto, ops, process::Command, sync::Arc}; | 5 | use std::{convert::TryInto, ops, process::Command, sync::Arc}; |
5 | 6 | ||
@@ -12,6 +13,7 @@ use rustc_hash::FxHashMap; | |||
12 | use serde::Deserialize; | 13 | use serde::Deserialize; |
13 | use serde_json::from_value; | 14 | use serde_json::from_value; |
14 | 15 | ||
16 | use crate::CfgOverrides; | ||
15 | use crate::{build_data::BuildDataConfig, utf8_stdout}; | 17 | use crate::{build_data::BuildDataConfig, utf8_stdout}; |
16 | 18 | ||
17 | /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo | 19 | /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo |
@@ -76,6 +78,21 @@ pub struct CargoConfig { | |||
76 | 78 | ||
77 | /// rustc private crate source | 79 | /// rustc private crate source |
78 | pub rustc_source: Option<RustcSource>, | 80 | pub rustc_source: Option<RustcSource>, |
81 | |||
82 | /// crates to disable `#[cfg(test)]` on | ||
83 | pub unset_test_crates: Vec<String>, | ||
84 | } | ||
85 | |||
86 | impl CargoConfig { | ||
87 | pub fn cfg_overrides(&self) -> CfgOverrides { | ||
88 | self.unset_test_crates | ||
89 | .iter() | ||
90 | .cloned() | ||
91 | .zip(iter::repeat_with(|| { | ||
92 | cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap() | ||
93 | })) | ||
94 | .collect() | ||
95 | } | ||
79 | } | 96 | } |
80 | 97 | ||
81 | pub type Package = Idx<PackageData>; | 98 | pub type Package = Idx<PackageData>; |
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 8c6cf94c2..1d408dff2 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -41,7 +41,7 @@ pub use crate::{ | |||
41 | }, | 41 | }, |
42 | project_json::{ProjectJson, ProjectJsonData}, | 42 | project_json::{ProjectJson, ProjectJsonData}, |
43 | sysroot::Sysroot, | 43 | sysroot::Sysroot, |
44 | workspace::{PackageRoot, ProjectWorkspace}, | 44 | workspace::{CfgOverrides, PackageRoot, ProjectWorkspace}, |
45 | }; | 45 | }; |
46 | 46 | ||
47 | pub use proc_macro_api::ProcMacroClient; | 47 | pub use proc_macro_api::ProcMacroClient; |
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs index a22f79c15..006263da8 100644 --- a/crates/project_model/src/sysroot.rs +++ b/crates/project_model/src/sysroot.rs | |||
@@ -68,8 +68,9 @@ impl Sysroot { | |||
68 | pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { | 68 | pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { |
69 | let mut sysroot = Sysroot { crates: Arena::default() }; | 69 | let mut sysroot = Sysroot { crates: Arena::default() }; |
70 | 70 | ||
71 | for name in SYSROOT_CRATES.trim().lines() { | 71 | for path in SYSROOT_CRATES.trim().lines() { |
72 | let root = [format!("{}/src/lib.rs", name), format!("lib{}/lib.rs", name)] | 72 | let name = path.split('/').last().unwrap(); |
73 | let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)] | ||
73 | .iter() | 74 | .iter() |
74 | .map(|it| sysroot_src_dir.join(it)) | 75 | .map(|it| sysroot_src_dir.join(it)) |
75 | .find(|it| it.exists()); | 76 | .find(|it| it.exists()); |
@@ -191,9 +192,8 @@ panic_abort | |||
191 | panic_unwind | 192 | panic_unwind |
192 | proc_macro | 193 | proc_macro |
193 | profiler_builtins | 194 | profiler_builtins |
194 | rtstartup | ||
195 | std | 195 | std |
196 | stdarch | 196 | stdarch/crates/std_detect |
197 | term | 197 | term |
198 | test | 198 | test |
199 | unwind"; | 199 | unwind"; |
@@ -204,9 +204,8 @@ core | |||
204 | panic_abort | 204 | panic_abort |
205 | panic_unwind | 205 | panic_unwind |
206 | profiler_builtins | 206 | profiler_builtins |
207 | rtstartup | ||
208 | proc_macro | 207 | proc_macro |
209 | stdarch | 208 | std_detect |
210 | term | 209 | term |
211 | test | 210 | test |
212 | unwind"; | 211 | unwind"; |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index ef0f3c9e4..d8217f714 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command}; | |||
7 | use anyhow::{format_err, Context, Result}; | 7 | use anyhow::{format_err, Context, Result}; |
8 | use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; | 8 | use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; |
9 | use cargo_workspace::DepKind; | 9 | use cargo_workspace::DepKind; |
10 | use cfg::CfgOptions; | 10 | use cfg::{CfgDiff, CfgOptions}; |
11 | use paths::{AbsPath, AbsPathBuf}; | 11 | use paths::{AbsPath, AbsPathBuf}; |
12 | use proc_macro_api::ProcMacroClient; | 12 | use proc_macro_api::ProcMacroClient; |
13 | use rustc_hash::{FxHashMap, FxHashSet}; | 13 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -22,6 +22,8 @@ use crate::{ | |||
22 | Sysroot, TargetKind, | 22 | Sysroot, TargetKind, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | pub type CfgOverrides = FxHashMap<String, CfgDiff>; | ||
26 | |||
25 | /// `PackageRoot` describes a package root folder. | 27 | /// `PackageRoot` describes a package root folder. |
26 | /// Which may be an external dependency, or a member of | 28 | /// Which may be an external dependency, or a member of |
27 | /// the current workspace. | 29 | /// the current workspace. |
@@ -46,6 +48,7 @@ pub enum ProjectWorkspace { | |||
46 | /// FIXME: make this a per-crate map, as, eg, build.rs might have a | 48 | /// FIXME: make this a per-crate map, as, eg, build.rs might have a |
47 | /// different target. | 49 | /// different target. |
48 | rustc_cfg: Vec<CfgFlag>, | 50 | rustc_cfg: Vec<CfgFlag>, |
51 | cfg_overrides: CfgOverrides, | ||
49 | }, | 52 | }, |
50 | /// Project workspace was manually specified using a `rust-project.json` file. | 53 | /// Project workspace was manually specified using a `rust-project.json` file. |
51 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, | 54 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, |
@@ -67,7 +70,7 @@ impl fmt::Debug for ProjectWorkspace { | |||
67 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 70 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
68 | // Make sure this isn't too verbose. | 71 | // Make sure this isn't too verbose. |
69 | match self { | 72 | match self { |
70 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f | 73 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f |
71 | .debug_struct("Cargo") | 74 | .debug_struct("Cargo") |
72 | .field("root", &cargo.workspace_root().file_name()) | 75 | .field("root", &cargo.workspace_root().file_name()) |
73 | .field("n_packages", &cargo.packages().len()) | 76 | .field("n_packages", &cargo.packages().len()) |
@@ -77,6 +80,7 @@ impl fmt::Debug for ProjectWorkspace { | |||
77 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), | 80 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), |
78 | ) | 81 | ) |
79 | .field("n_rustc_cfg", &rustc_cfg.len()) | 82 | .field("n_rustc_cfg", &rustc_cfg.len()) |
83 | .field("n_cfg_overrides", &cfg_overrides.len()) | ||
80 | .finish(), | 84 | .finish(), |
81 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { | 85 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { |
82 | let mut debug_struct = f.debug_struct("Json"); | 86 | let mut debug_struct = f.debug_struct("Json"); |
@@ -164,7 +168,9 @@ impl ProjectWorkspace { | |||
164 | }; | 168 | }; |
165 | 169 | ||
166 | let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); | 170 | let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); |
167 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } | 171 | |
172 | let cfg_overrides = config.cfg_overrides(); | ||
173 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } | ||
168 | } | 174 | } |
169 | }; | 175 | }; |
170 | 176 | ||
@@ -213,43 +219,45 @@ impl ProjectWorkspace { | |||
213 | }) | 219 | }) |
214 | })) | 220 | })) |
215 | .collect::<Vec<_>>(), | 221 | .collect::<Vec<_>>(), |
216 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo | 222 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => { |
217 | .packages() | 223 | cargo |
218 | .map(|pkg| { | 224 | .packages() |
219 | let is_member = cargo[pkg].is_member; | 225 | .map(|pkg| { |
220 | let pkg_root = cargo[pkg].root().to_path_buf(); | 226 | let is_member = cargo[pkg].is_member; |
221 | 227 | let pkg_root = cargo[pkg].root().to_path_buf(); | |
222 | let mut include = vec![pkg_root.clone()]; | 228 | |
223 | include.extend( | 229 | let mut include = vec![pkg_root.clone()]; |
224 | build_data | 230 | include.extend( |
225 | .and_then(|it| it.get(cargo.workspace_root())) | 231 | build_data |
226 | .and_then(|map| map.get(&cargo[pkg].id)) | 232 | .and_then(|it| it.get(cargo.workspace_root())) |
227 | .and_then(|it| it.out_dir.clone()), | 233 | .and_then(|map| map.get(&cargo[pkg].id)) |
228 | ); | 234 | .and_then(|it| it.out_dir.clone()), |
235 | ); | ||
229 | 236 | ||
230 | let mut exclude = vec![pkg_root.join(".git")]; | 237 | let mut exclude = vec![pkg_root.join(".git")]; |
231 | if is_member { | 238 | if is_member { |
232 | exclude.push(pkg_root.join("target")); | 239 | exclude.push(pkg_root.join("target")); |
233 | } else { | 240 | } else { |
234 | exclude.push(pkg_root.join("tests")); | 241 | exclude.push(pkg_root.join("tests")); |
235 | exclude.push(pkg_root.join("examples")); | 242 | exclude.push(pkg_root.join("examples")); |
236 | exclude.push(pkg_root.join("benches")); | 243 | exclude.push(pkg_root.join("benches")); |
237 | } | 244 | } |
238 | PackageRoot { is_member, include, exclude } | 245 | PackageRoot { is_member, include, exclude } |
239 | }) | 246 | }) |
240 | .chain(sysroot.crates().map(|krate| PackageRoot { | 247 | .chain(sysroot.crates().map(|krate| PackageRoot { |
241 | is_member: false, | ||
242 | include: vec![sysroot[krate].root_dir().to_path_buf()], | ||
243 | exclude: Vec::new(), | ||
244 | })) | ||
245 | .chain(rustc.into_iter().flat_map(|rustc| { | ||
246 | rustc.packages().map(move |krate| PackageRoot { | ||
247 | is_member: false, | 248 | is_member: false, |
248 | include: vec![rustc[krate].root().to_path_buf()], | 249 | include: vec![sysroot[krate].root_dir().to_path_buf()], |
249 | exclude: Vec::new(), | 250 | exclude: Vec::new(), |
250 | }) | 251 | })) |
251 | })) | 252 | .chain(rustc.into_iter().flat_map(|rustc| { |
252 | .collect(), | 253 | rustc.packages().map(move |krate| PackageRoot { |
254 | is_member: false, | ||
255 | include: vec![rustc[krate].root().to_path_buf()], | ||
256 | exclude: Vec::new(), | ||
257 | }) | ||
258 | })) | ||
259 | .collect() | ||
260 | } | ||
253 | ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files | 261 | ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files |
254 | .into_iter() | 262 | .into_iter() |
255 | .map(|detached_file| PackageRoot { | 263 | .map(|detached_file| PackageRoot { |
@@ -299,16 +307,22 @@ impl ProjectWorkspace { | |||
299 | project, | 307 | project, |
300 | sysroot, | 308 | sysroot, |
301 | ), | 309 | ), |
302 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( | 310 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => { |
303 | rustc_cfg.clone(), | 311 | cargo_to_crate_graph( |
304 | &proc_macro_loader, | 312 | rustc_cfg.clone(), |
305 | load, | 313 | cfg_overrides, |
306 | cargo, | 314 | &proc_macro_loader, |
307 | build_data.and_then(|it| it.get(cargo.workspace_root())), | 315 | load, |
308 | sysroot, | 316 | cargo, |
309 | rustc, | 317 | build_data.and_then(|it| it.get(cargo.workspace_root())), |
310 | rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), | 318 | sysroot, |
311 | ), | 319 | rustc, |
320 | rustc | ||
321 | .as_ref() | ||
322 | .zip(build_data) | ||
323 | .and_then(|(it, map)| map.get(it.workspace_root())), | ||
324 | ) | ||
325 | } | ||
312 | ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { | 326 | ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { |
313 | detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) | 327 | detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) |
314 | } | 328 | } |
@@ -398,6 +412,7 @@ fn project_json_to_crate_graph( | |||
398 | 412 | ||
399 | fn cargo_to_crate_graph( | 413 | fn cargo_to_crate_graph( |
400 | rustc_cfg: Vec<CfgFlag>, | 414 | rustc_cfg: Vec<CfgFlag>, |
415 | override_cfg: &CfgOverrides, | ||
401 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 416 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
402 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 417 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
403 | cargo: &CargoWorkspace, | 418 | cargo: &CargoWorkspace, |
@@ -425,6 +440,21 @@ fn cargo_to_crate_graph( | |||
425 | let mut has_private = false; | 440 | let mut has_private = false; |
426 | // Next, create crates for each package, target pair | 441 | // Next, create crates for each package, target pair |
427 | for pkg in cargo.packages() { | 442 | for pkg in cargo.packages() { |
443 | let mut cfg_options = &cfg_options; | ||
444 | let mut replaced_cfg_options; | ||
445 | if let Some(overrides) = override_cfg.get(&cargo[pkg].name) { | ||
446 | // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen | ||
447 | // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while | ||
448 | // working on rust-lang/rust as that's the only time it appears outside sysroot). | ||
449 | // | ||
450 | // A more ideal solution might be to reanalyze crates based on where the cursor is and | ||
451 | // figure out the set of cfgs that would have to apply to make it active. | ||
452 | |||
453 | replaced_cfg_options = cfg_options.clone(); | ||
454 | replaced_cfg_options.apply_diff(overrides.clone()); | ||
455 | cfg_options = &replaced_cfg_options; | ||
456 | }; | ||
457 | |||
428 | has_private |= cargo[pkg].metadata.rustc_private; | 458 | has_private |= cargo[pkg].metadata.rustc_private; |
429 | let mut lib_tgt = None; | 459 | let mut lib_tgt = None; |
430 | for &tgt in cargo[pkg].targets.iter() { | 460 | for &tgt in cargo[pkg].targets.iter() { |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 16c295639..7e0276c10 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -55,6 +55,8 @@ config_data! { | |||
55 | cargo_autoreload: bool = "true", | 55 | cargo_autoreload: bool = "true", |
56 | /// Activate all available features (`--all-features`). | 56 | /// Activate all available features (`--all-features`). |
57 | cargo_allFeatures: bool = "false", | 57 | cargo_allFeatures: bool = "false", |
58 | /// Unsets `#[cfg(test)]` for the specified crates. | ||
59 | cargo_unsetTest: Vec<String> = "[\"core\"]", | ||
58 | /// List of features to activate. | 60 | /// List of features to activate. |
59 | cargo_features: Vec<String> = "[]", | 61 | cargo_features: Vec<String> = "[]", |
60 | /// Run build scripts (`build.rs`) for more precise code analysis. | 62 | /// Run build scripts (`build.rs`) for more precise code analysis. |
@@ -595,8 +597,10 @@ impl Config { | |||
595 | target: self.data.cargo_target.clone(), | 597 | target: self.data.cargo_target.clone(), |
596 | rustc_source, | 598 | rustc_source, |
597 | no_sysroot: self.data.cargo_noSysroot, | 599 | no_sysroot: self.data.cargo_noSysroot, |
600 | unset_test_crates: self.data.cargo_unsetTest.clone(), | ||
598 | } | 601 | } |
599 | } | 602 | } |
603 | |||
600 | pub fn rustfmt(&self) -> RustfmtConfig { | 604 | pub fn rustfmt(&self) -> RustfmtConfig { |
601 | match &self.data.rustfmt_overrideCommand { | 605 | match &self.data.rustfmt_overrideCommand { |
602 | Some(args) if !args.is_empty() => { | 606 | Some(args) if !args.is_empty() => { |
diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md index 5876e71bc..48caec1d8 100644 --- a/docs/dev/debugging.md +++ b/docs/dev/debugging.md | |||
@@ -65,6 +65,11 @@ If you need to debug the server from the very beginning, including its initializ | |||
65 | } | 65 | } |
66 | ``` | 66 | ``` |
67 | 67 | ||
68 | However for this to work, you will need to enable debug_assertions in your build | ||
69 | ```rust | ||
70 | RUSTFLAGS='--cfg debug_assertions' cargo build --release | ||
71 | ``` | ||
72 | |||
68 | ## Demo | 73 | ## Demo |
69 | 74 | ||
70 | - [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM). | 75 | - [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM). |
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 18ea77266..58cb46974 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -39,6 +39,11 @@ Automatically refresh project info via `cargo metadata` on | |||
39 | -- | 39 | -- |
40 | Activate all available features (`--all-features`). | 40 | Activate all available features (`--all-features`). |
41 | -- | 41 | -- |
42 | [[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`):: | ||
43 | + | ||
44 | -- | ||
45 | Unsets `#[cfg(test)]` for the specified crates. | ||
46 | -- | ||
42 | [[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: | 47 | [[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: |
43 | + | 48 | + |
44 | -- | 49 | -- |
diff --git a/editors/code/package.json b/editors/code/package.json index c077bd2c0..b20a39a95 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -452,6 +452,16 @@ | |||
452 | "default": false, | 452 | "default": false, |
453 | "type": "boolean" | 453 | "type": "boolean" |
454 | }, | 454 | }, |
455 | "rust-analyzer.cargo.unsetTest": { | ||
456 | "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.", | ||
457 | "default": [ | ||
458 | "core" | ||
459 | ], | ||
460 | "type": "array", | ||
461 | "items": { | ||
462 | "type": "string" | ||
463 | } | ||
464 | }, | ||
455 | "rust-analyzer.cargo.features": { | 465 | "rust-analyzer.cargo.features": { |
456 | "markdownDescription": "List of features to activate.", | 466 | "markdownDescription": "List of features to activate.", |
457 | "default": [], | 467 | "default": [], |