aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/Cargo.toml2
-rw-r--r--crates/hir_expand/src/name.rs2
-rw-r--r--crates/hir_ty/Cargo.toml4
-rw-r--r--crates/ide/Cargo.toml2
-rw-r--r--crates/ide_assists/Cargo.toml2
-rw-r--r--crates/ide_assists/src/handlers/generate_is_empty_from_len.rs255
-rw-r--r--crates/ide_assists/src/lib.rs2
-rw-r--r--crates/ide_assists/src/tests/generated.rs29
-rw-r--r--crates/ide_completion/Cargo.toml2
-rw-r--r--crates/ide_completion/src/completions/pattern.rs116
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs88
-rw-r--r--crates/ide_completion/src/context.rs2
-rw-r--r--crates/ide_completion/src/render.rs60
-rw-r--r--crates/ide_completion/src/render/function.rs17
-rw-r--r--crates/ide_completion/src/render/pattern.rs36
-rw-r--r--crates/ide_db/Cargo.toml2
-rw-r--r--crates/ide_ssr/Cargo.toml2
-rw-r--r--crates/mbe/Cargo.toml2
-rw-r--r--crates/proc_macro_api/src/lib.rs3
-rw-r--r--crates/proc_macro_api/src/version.rs13
-rw-r--r--crates/proc_macro_srv/src/tests/mod.rs7
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs2
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--docs/user/generated_config.adoc2
-rw-r--r--editors/code/package.json2
-rw-r--r--xtask/src/metrics.rs3
27 files changed, 516 insertions, 145 deletions
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index c2d99280f..475d337f3 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1" 13cov-mark = { version = "1.1", features = ["thread-local"] }
14log = "0.4.8" 14log = "0.4.8"
15once_cell = "1.3.1" 15once_cell = "1.3.1"
16rustc-hash = "1.1.0" 16rustc-hash = "1.1.0"
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index e833e032c..43de9edd6 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -191,6 +191,8 @@ pub mod known {
191 filter_map, 191 filter_map,
192 next, 192 next,
193 iter_mut, 193 iter_mut,
194 len,
195 is_empty,
194 // Builtin macros 196 // Builtin macros
195 file, 197 file,
196 column, 198 column,
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index b9c93f56f..0ef27cd37 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1" 13cov-mark = { version = "1.1", features = ["thread-local"] }
14itertools = "0.10.0" 14itertools = "0.10.0"
15arrayvec = "0.5.1" 15arrayvec = "0.5.1"
16smallvec = "1.2.0" 16smallvec = "1.2.0"
@@ -31,7 +31,7 @@ profile = { path = "../profile", version = "0.0.0" }
31syntax = { path = "../syntax", version = "0.0.0" } 31syntax = { path = "../syntax", version = "0.0.0" }
32 32
33[dev-dependencies] 33[dev-dependencies]
34test_utils = { path = "../test_utils" } 34test_utils = { path = "../test_utils" }
35expect-test = "1.1" 35expect-test = "1.1"
36tracing = "0.1" 36tracing = "0.1"
37tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } 37tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 6ae7c9e6c..f04bcf531 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1" 13cov-mark = { version = "1.1", features = ["thread-local"] }
14either = "1.5.3" 14either = "1.5.3"
15indexmap = "1.4.0" 15indexmap = "1.4.0"
16itertools = "0.10.0" 16itertools = "0.10.0"
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml
index dd9aa27c6..a83acb191 100644
--- a/crates/ide_assists/Cargo.toml
+++ b/crates/ide_assists/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1" 13cov-mark = { version = "1.1", features = ["thread-local"] }
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15itertools = "0.10.0" 15itertools = "0.10.0"
16either = "1.6.1" 16either = "1.6.1"
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
new file mode 100644
index 000000000..aa7072f25
--- /dev/null
+++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
@@ -0,0 +1,255 @@
1use hir::{known, HasSource, Name};
2use syntax::{
3 ast::{self, NameOwner},
4 AstNode, TextRange,
5};
6
7use crate::{
8 assist_context::{AssistContext, Assists},
9 AssistId, AssistKind,
10};
11
12// Assist: generate_is_empty_from_len
13//
14// Generates is_empty implementation from the len method.
15//
16// ```
17// struct MyStruct { data: Vec<String> }
18//
19// impl MyStruct {
20// p$0ub fn len(&self) -> usize {
21// self.data.len()
22// }
23// }
24// ```
25// ->
26// ```
27// struct MyStruct { data: Vec<String> }
28//
29// impl MyStruct {
30// pub fn len(&self) -> usize {
31// self.data.len()
32// }
33//
34// pub fn is_empty(&self) -> bool {
35// self.len() == 0
36// }
37// }
38// ```
39pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let fn_node = ctx.find_node_at_offset::<ast::Fn>()?;
41 let fn_name = fn_node.name()?;
42
43 if fn_name.text() != "len" {
44 cov_mark::hit!(len_function_not_present);
45 return None;
46 }
47
48 if fn_node.param_list()?.params().next().is_some() {
49 cov_mark::hit!(len_function_with_parameters);
50 return None;
51 }
52
53 let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
54 if get_impl_method(ctx, &impl_, &known::is_empty).is_some() {
55 cov_mark::hit!(is_empty_already_implemented);
56 return None;
57 }
58
59 let range = get_text_range_of_len_function(ctx, &impl_)?;
60
61 acc.add(
62 AssistId("generate_is_empty_from_len", AssistKind::Generate),
63 "Generate a is_empty impl from a len function",
64 range,
65 |builder| {
66 let code = r#"
67
68 pub fn is_empty(&self) -> bool {
69 self.len() == 0
70 }"#
71 .to_string();
72 builder.insert(range.end(), code)
73 },
74 )
75}
76
77fn get_impl_method(
78 ctx: &AssistContext,
79 impl_: &ast::Impl,
80 fn_name: &Name,
81) -> Option<hir::Function> {
82 let db = ctx.sema.db;
83 let impl_def: hir::Impl = ctx.sema.to_def(impl_)?;
84
85 let scope = ctx.sema.scope(impl_.syntax());
86 let krate = impl_def.module(db).krate();
87 let ty = impl_def.target_ty(db);
88 let traits_in_scope = scope.traits_in_scope();
89 ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func))
90}
91
92fn get_text_range_of_len_function(ctx: &AssistContext, impl_: &ast::Impl) -> Option<TextRange> {
93 let db = ctx.sema.db;
94 let func = get_impl_method(ctx, impl_, &known::len)?;
95 let node = func.source(db)?;
96 Some(node.syntax().value.text_range())
97}
98
99#[cfg(test)]
100mod tests {
101 use crate::tests::{check_assist, check_assist_not_applicable};
102
103 use super::*;
104
105 #[test]
106 fn len_function_not_present() {
107 cov_mark::check!(len_function_not_present);
108 check_assist_not_applicable(
109 generate_is_empty_from_len,
110 r#"
111struct MyStruct { data: Vec<String> }
112
113impl MyStruct {
114 p$0ub fn test(&self) -> usize {
115 self.data.len()
116 }
117 }
118"#,
119 );
120 }
121
122 #[test]
123 fn len_function_with_parameters() {
124 cov_mark::check!(len_function_with_parameters);
125 check_assist_not_applicable(
126 generate_is_empty_from_len,
127 r#"
128struct MyStruct { data: Vec<String> }
129
130impl MyStruct {
131 p$0ub fn len(&self, _i: bool) -> usize {
132 self.data.len()
133 }
134}
135"#,
136 );
137 }
138
139 #[test]
140 fn is_empty_already_implemented() {
141 cov_mark::check!(is_empty_already_implemented);
142 check_assist_not_applicable(
143 generate_is_empty_from_len,
144 r#"
145struct MyStruct { data: Vec<String> }
146
147impl MyStruct {
148 p$0ub fn len(&self) -> usize {
149 self.data.len()
150 }
151
152 pub fn is_empty(&self) -> bool {
153 self.len() == 0
154 }
155}
156"#,
157 );
158 }
159
160 #[test]
161 fn generate_is_empty() {
162 check_assist(
163 generate_is_empty_from_len,
164 r#"
165struct MyStruct { data: Vec<String> }
166
167impl MyStruct {
168 p$0ub fn len(&self) -> usize {
169 self.data.len()
170 }
171}
172"#,
173 r#"
174struct MyStruct { data: Vec<String> }
175
176impl MyStruct {
177 pub fn len(&self) -> usize {
178 self.data.len()
179 }
180
181 pub fn is_empty(&self) -> bool {
182 self.len() == 0
183 }
184}
185"#,
186 );
187 }
188
189 #[test]
190 fn multiple_functions_in_impl() {
191 check_assist(
192 generate_is_empty_from_len,
193 r#"
194struct MyStruct { data: Vec<String> }
195
196impl MyStruct {
197 pub fn new() -> Self {
198 Self { data: 0 }
199 }
200
201 p$0ub fn len(&self) -> usize {
202 self.data.len()
203 }
204
205 pub fn work(&self) -> Option<usize> {
206
207 }
208}
209"#,
210 r#"
211struct MyStruct { data: Vec<String> }
212
213impl MyStruct {
214 pub fn new() -> Self {
215 Self { data: 0 }
216 }
217
218 pub fn len(&self) -> usize {
219 self.data.len()
220 }
221
222 pub fn is_empty(&self) -> bool {
223 self.len() == 0
224 }
225
226 pub fn work(&self) -> Option<usize> {
227
228 }
229}
230"#,
231 );
232 }
233
234 #[test]
235 fn multiple_impls() {
236 check_assist_not_applicable(
237 generate_is_empty_from_len,
238 r#"
239struct MyStruct { data: Vec<String> }
240
241impl MyStruct {
242 p$0ub fn len(&self) -> usize {
243 self.data.len()
244 }
245}
246
247impl MyStruct {
248 pub fn is_empty(&self) -> bool {
249 self.len() == 0
250 }
251}
252"#,
253 );
254 }
255}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index f1aab74d4..8c068a6c0 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -129,6 +129,7 @@ mod handlers {
129 mod flip_trait_bound; 129 mod flip_trait_bound;
130 mod generate_default_from_enum_variant; 130 mod generate_default_from_enum_variant;
131 mod generate_default_from_new; 131 mod generate_default_from_new;
132 mod generate_is_empty_from_len;
132 mod generate_derive; 133 mod generate_derive;
133 mod generate_enum_is_method; 134 mod generate_enum_is_method;
134 mod generate_enum_projection_method; 135 mod generate_enum_projection_method;
@@ -193,6 +194,7 @@ mod handlers {
193 flip_trait_bound::flip_trait_bound, 194 flip_trait_bound::flip_trait_bound,
194 generate_default_from_enum_variant::generate_default_from_enum_variant, 195 generate_default_from_enum_variant::generate_default_from_enum_variant,
195 generate_default_from_new::generate_default_from_new, 196 generate_default_from_new::generate_default_from_new,
197 generate_is_empty_from_len::generate_is_empty_from_len,
196 generate_derive::generate_derive, 198 generate_derive::generate_derive,
197 generate_enum_is_method::generate_enum_is_method, 199 generate_enum_is_method::generate_enum_is_method,
198 generate_enum_projection_method::generate_enum_as_method, 200 generate_enum_projection_method::generate_enum_as_method,
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 3f77edd8d..736027ff0 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -722,6 +722,35 @@ impl<T: Clone> Ctx<T> {
722} 722}
723 723
724#[test] 724#[test]
725fn doctest_generate_is_empty_from_len() {
726 check_doc_test(
727 "generate_is_empty_from_len",
728 r#####"
729struct MyStruct { data: Vec<String> }
730
731impl MyStruct {
732 p$0ub fn len(&self) -> usize {
733 self.data.len()
734 }
735}
736"#####,
737 r#####"
738struct MyStruct { data: Vec<String> }
739
740impl MyStruct {
741 pub fn len(&self) -> usize {
742 self.data.len()
743 }
744
745 pub fn is_empty(&self) -> bool {
746 self.len() == 0
747 }
748}
749"#####,
750 )
751}
752
753#[test]
725fn doctest_generate_new() { 754fn doctest_generate_new() {
726 check_doc_test( 755 check_doc_test(
727 "generate_new", 756 "generate_new",
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml
index 585ecca50..6bd8a5500 100644
--- a/crates/ide_completion/Cargo.toml
+++ b/crates/ide_completion/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1" 13cov-mark = { version = "1.1", features = ["thread-local"] }
14itertools = "0.10.0" 14itertools = "0.10.0"
15log = "0.4.8" 15log = "0.4.8"
16rustc-hash = "1.1.0" 16rustc-hash = "1.1.0"
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index 9282c3827..46cef58f0 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -11,10 +11,13 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
11 return; 11 return;
12 } 12 }
13 13
14 if let Some(ty) = &ctx.expected_type { 14 if !ctx.is_irrefutable_pat_binding {
15 super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| { 15 if let Some(ty) = ctx.expected_type.as_ref() {
16 acc.add_qualified_variant_pat(ctx, variant, path) 16 super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| {
17 }); 17 acc.add_qualified_variant_pat(ctx, variant, path.clone());
18 acc.add_qualified_enum_variant(ctx, variant, path);
19 });
20 }
18 } 21 }
19 22
20 // FIXME: ideally, we should look at the type we are matching against and 23 // FIXME: ideally, we should look at the type we are matching against and
@@ -85,7 +88,7 @@ static FOO: E = E::X;
85struct Bar { f: u32 } 88struct Bar { f: u32 }
86 89
87fn foo() { 90fn foo() {
88 match E::X { $0 } 91 match E::X { a$0 }
89} 92}
90"#, 93"#,
91 expect![[r#" 94 expect![[r#"
@@ -106,10 +109,11 @@ macro_rules! m { ($e:expr) => { $e } }
106enum E { X } 109enum E { X }
107 110
108fn foo() { 111fn foo() {
109 m!(match E::X { $0 }) 112 m!(match E::X { a$0 })
110} 113}
111"#, 114"#,
112 expect![[r#" 115 expect![[r#"
116 ev E::X ()
113 en E 117 en E
114 ma m!(…) macro_rules! m 118 ma m!(…) macro_rules! m
115 "#]], 119 "#]],
@@ -129,7 +133,7 @@ static FOO: E = E::X;
129struct Bar { f: u32 } 133struct Bar { f: u32 }
130 134
131fn foo() { 135fn foo() {
132 let $0 136 let a$0
133} 137}
134"#, 138"#,
135 expect![[r#" 139 expect![[r#"
@@ -147,7 +151,7 @@ enum E { X }
147static FOO: E = E::X; 151static FOO: E = E::X;
148struct Bar { f: u32 } 152struct Bar { f: u32 }
149 153
150fn foo($0) { 154fn foo(a$0) {
151} 155}
152"#, 156"#,
153 expect![[r#" 157 expect![[r#"
@@ -163,7 +167,7 @@ fn foo($0) {
163struct Bar { f: u32 } 167struct Bar { f: u32 }
164 168
165fn foo() { 169fn foo() {
166 let $0 170 let a$0
167} 171}
168"#, 172"#,
169 expect![[r#" 173 expect![[r#"
@@ -179,7 +183,7 @@ fn foo() {
179struct Foo { bar: String, baz: String } 183struct Foo { bar: String, baz: String }
180struct Bar(String, String); 184struct Bar(String, String);
181struct Baz; 185struct Baz;
182fn outer($0) {} 186fn outer(a$0) {}
183"#, 187"#,
184 expect![[r#" 188 expect![[r#"
185 bn Foo Foo { bar$1, baz$2 }: Foo$0 189 bn Foo Foo { bar$1, baz$2 }: Foo$0
@@ -196,7 +200,7 @@ struct Foo { bar: String, baz: String }
196struct Bar(String, String); 200struct Bar(String, String);
197struct Baz; 201struct Baz;
198fn outer() { 202fn outer() {
199 let $0 203 let a$0
200} 204}
201"#, 205"#,
202 expect![[r#" 206 expect![[r#"
@@ -215,7 +219,7 @@ struct Bar(String, String);
215struct Baz; 219struct Baz;
216fn outer() { 220fn outer() {
217 match () { 221 match () {
218 $0 222 a$0
219 } 223 }
220} 224}
221"#, 225"#,
@@ -239,7 +243,7 @@ use foo::*;
239 243
240fn outer() { 244fn outer() {
241 match () { 245 match () {
242 $0 246 a$0
243 } 247 }
244} 248}
245"#, 249"#,
@@ -258,7 +262,7 @@ fn outer() {
258struct Foo(i32); 262struct Foo(i32);
259fn main() { 263fn main() {
260 match Foo(92) { 264 match Foo(92) {
261 $0(92) => (), 265 a$0(92) => (),
262 } 266 }
263} 267}
264"#, 268"#,
@@ -281,7 +285,7 @@ struct Foo(i32);
281impl Foo { 285impl Foo {
282 fn foo() { 286 fn foo() {
283 match () { 287 match () {
284 $0 288 a$0
285 } 289 }
286 } 290 }
287} 291}
@@ -314,4 +318,86 @@ impl Foo {
314 "#]], 318 "#]],
315 ) 319 )
316 } 320 }
321
322 #[test]
323 fn completes_enum_variant_matcharm() {
324 check(
325 r#"
326enum Foo { Bar, Baz, Quux }
327
328fn main() {
329 let foo = Foo::Quux;
330 match foo { Qu$0 }
331}
332"#,
333 expect![[r#"
334 ev Foo::Bar ()
335 ev Foo::Baz ()
336 ev Foo::Quux ()
337 en Foo
338 "#]],
339 )
340 }
341
342 #[test]
343 fn completes_enum_variant_matcharm_ref() {
344 check(
345 r#"
346enum Foo { Bar, Baz, Quux }
347
348fn main() {
349 let foo = Foo::Quux;
350 match &foo { Qu$0 }
351}
352"#,
353 expect![[r#"
354 ev Foo::Bar ()
355 ev Foo::Baz ()
356 ev Foo::Quux ()
357 en Foo
358 "#]],
359 )
360 }
361
362 #[test]
363 fn completes_enum_variant_iflet() {
364 check(
365 r#"
366enum Foo { Bar, Baz, Quux }
367
368fn main() {
369 let foo = Foo::Quux;
370 if let Qu$0 = foo { }
371}
372"#,
373 expect![[r#"
374 ev Foo::Bar ()
375 ev Foo::Baz ()
376 ev Foo::Quux ()
377 en Foo
378 "#]],
379 )
380 }
381
382 #[test]
383 fn completes_enum_variant_impl() {
384 check(
385 r#"
386enum Foo { Bar, Baz, Quux }
387impl Foo {
388 fn foo() { match Foo::Bar { Q$0 } }
389}
390"#,
391 expect![[r#"
392 ev Self::Bar ()
393 ev Self::Baz ()
394 ev Self::Quux ()
395 ev Foo::Bar ()
396 ev Foo::Baz ()
397 ev Foo::Quux ()
398 sp Self
399 en Foo
400 "#]],
401 )
402 }
317} 403}
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 044dfd160..5ef80f6a7 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -6,7 +6,7 @@ use syntax::AstNode;
6use crate::{CompletionContext, Completions}; 6use crate::{CompletionContext, Completions};
7 7
8pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 8pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
9 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 9 if !ctx.is_trivial_path {
10 return; 10 return;
11 } 11 }
12 if ctx.record_lit_syntax.is_some() 12 if ctx.record_lit_syntax.is_some()
@@ -23,10 +23,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
23 }); 23 });
24 } 24 }
25 25
26 if ctx.is_pat_binding_or_const {
27 return;
28 }
29
30 ctx.scope.process_all_names(&mut |name, res| { 26 ctx.scope.process_all_names(&mut |name, res| {
31 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { 27 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
32 cov_mark::hit!(skip_lifetime_completion); 28 cov_mark::hit!(skip_lifetime_completion);
@@ -609,66 +605,6 @@ fn main() { $0 }
609 } 605 }
610 606
611 #[test] 607 #[test]
612 fn completes_enum_variant_matcharm() {
613 check(
614 r#"
615enum Foo { Bar, Baz, Quux }
616
617fn main() {
618 let foo = Foo::Quux;
619 match foo { Qu$0 }
620}
621"#,
622 expect![[r#"
623 ev Foo::Bar ()
624 ev Foo::Baz ()
625 ev Foo::Quux ()
626 en Foo
627 "#]],
628 )
629 }
630
631 #[test]
632 fn completes_enum_variant_matcharm_ref() {
633 check(
634 r#"
635enum Foo { Bar, Baz, Quux }
636
637fn main() {
638 let foo = Foo::Quux;
639 match &foo { Qu$0 }
640}
641"#,
642 expect![[r#"
643 ev Foo::Bar ()
644 ev Foo::Baz ()
645 ev Foo::Quux ()
646 en Foo
647 "#]],
648 )
649 }
650
651 #[test]
652 fn completes_enum_variant_iflet() {
653 check(
654 r#"
655enum Foo { Bar, Baz, Quux }
656
657fn main() {
658 let foo = Foo::Quux;
659 if let Qu$0 = foo { }
660}
661"#,
662 expect![[r#"
663 ev Foo::Bar ()
664 ev Foo::Baz ()
665 ev Foo::Quux ()
666 en Foo
667 "#]],
668 )
669 }
670
671 #[test]
672 fn completes_enum_variant_basic_expr() { 608 fn completes_enum_variant_basic_expr() {
673 check( 609 check(
674 r#" 610 r#"
@@ -701,28 +637,6 @@ fn f() -> m::E { V$0 }
701 } 637 }
702 638
703 #[test] 639 #[test]
704 fn completes_enum_variant_impl() {
705 check(
706 r#"
707enum Foo { Bar, Baz, Quux }
708impl Foo {
709 fn foo() { match Foo::Bar { Q$0 } }
710}
711"#,
712 expect![[r#"
713 ev Self::Bar ()
714 ev Self::Baz ()
715 ev Self::Quux ()
716 ev Foo::Bar ()
717 ev Foo::Baz ()
718 ev Foo::Quux ()
719 sp Self
720 en Foo
721 "#]],
722 )
723 }
724
725 #[test]
726 fn dont_complete_attr() { 640 fn dont_complete_attr() {
727 check( 641 check(
728 r#" 642 r#"
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 89e9bda78..e6cc6329c 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -350,7 +350,6 @@ impl<'a> CompletionContext<'a> {
350 }, 350 },
351 ast::IdentPat(it) => { 351 ast::IdentPat(it) => {
352 cov_mark::hit!(expected_type_if_let_with_leading_char); 352 cov_mark::hit!(expected_type_if_let_with_leading_char);
353 cov_mark::hit!(expected_type_if_let_without_leading_char);
354 cov_mark::hit!(expected_type_match_arm_with_leading_char); 353 cov_mark::hit!(expected_type_match_arm_with_leading_char);
355 let ty = self.sema.type_of_pat(&ast::Pat::from(it)); 354 let ty = self.sema.type_of_pat(&ast::Pat::from(it));
356 355
@@ -748,7 +747,6 @@ fn foo() {
748 747
749 #[test] 748 #[test]
750 fn expected_type_if_let_without_leading_char() { 749 fn expected_type_if_let_without_leading_char() {
751 cov_mark::check!(expected_type_if_let_without_leading_char);
752 check_expected_type_and_name( 750 check_expected_type_and_name(
753 r#" 751 r#"
754enum Foo { Bar, Baz, Quux } 752enum Foo { Bar, Baz, Quux }
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 670563e50..2514dda7c 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -928,6 +928,66 @@ fn f(foo: &Foo) { f(foo, w$0) }
928 } 928 }
929 929
930 #[test] 930 #[test]
931 fn score_fn_type_and_name_match() {
932 check_relevance(
933 r#"
934struct A { bar: u8 }
935fn baz() -> u8 { 0 }
936fn bar() -> u8 { 0 }
937fn f() { A { bar: b$0 }; }
938"#,
939 expect![[r#"
940 fn baz() [type]
941 st A []
942 fn bar() [type+name]
943 fn f() []
944 "#]],
945 );
946 }
947
948 #[test]
949 fn score_method_type_and_name_match() {
950 check_relevance(
951 r#"
952fn baz(aaa: u32){}
953struct Foo;
954impl Foo {
955fn aaa(&self) -> u32 { 0 }
956fn bbb(&self) -> u32 { 0 }
957fn ccc(&self) -> u64 { 0 }
958}
959fn f() {
960 baz(Foo.$0
961}
962"#,
963 expect![[r#"
964 me aaa() [type+name]
965 me bbb() [type]
966 me ccc() []
967 "#]],
968 );
969 }
970
971 #[test]
972 fn score_method_name_match_only() {
973 check_relevance(
974 r#"
975fn baz(aaa: u32){}
976struct Foo;
977impl Foo {
978fn aaa(&self) -> u64 { 0 }
979}
980fn f() {
981 baz(Foo.$0
982}
983"#,
984 expect![[r#"
985 me aaa() [name]
986 "#]],
987 );
988 }
989
990 #[test]
931 fn suggest_ref_mut() { 991 fn suggest_ref_mut() {
932 cov_mark::check!(suggest_ref); 992 cov_mark::check!(suggest_ref);
933 check( 993 check(
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index f4dabe3d1..47e26a5d8 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -5,7 +5,7 @@ use ide_db::SymbolKind;
5use syntax::ast::Fn; 5use syntax::ast::Fn;
6 6
7use crate::{ 7use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, 8 item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit},
9 render::{builder_ext::Params, RenderContext}, 9 render::{builder_ext::Params, RenderContext},
10}; 10};
11 11
@@ -55,6 +55,21 @@ impl<'a> FunctionRender<'a> {
55 .add_call_parens(self.ctx.completion, self.name, params) 55 .add_call_parens(self.ctx.completion, self.name, params)
56 .add_import(import_to_add); 56 .add_import(import_to_add);
57 57
58 let mut relevance = CompletionRelevance::default();
59 if let Some(expected_type) = &self.ctx.completion.expected_type {
60 let ret_ty = self.func.ret_type(self.ctx.db());
61
62 // We don't ever consider a function which returns unit type to be an
63 // exact type match, since nearly always this is not meaningful to the
64 // user.
65 relevance.exact_type_match = &ret_ty == expected_type && !ret_ty.is_unit();
66 }
67 if let Some(expected_name) = &self.ctx.completion.expected_name {
68 relevance.exact_name_match =
69 expected_name == &self.func.name(self.ctx.db()).to_string();
70 }
71 item.set_relevance(relevance);
72
58 item.build() 73 item.build()
59 } 74 }
60 75
diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs
index ca2926125..b4e80f424 100644
--- a/crates/ide_completion/src/render/pattern.rs
+++ b/crates/ide_completion/src/render/pattern.rs
@@ -6,24 +6,6 @@ use itertools::Itertools;
6 6
7use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind}; 7use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind};
8 8
9fn visible_fields(
10 ctx: &RenderContext<'_>,
11 fields: &[hir::Field],
12 item: impl HasAttrs,
13) -> Option<(Vec<hir::Field>, bool)> {
14 let module = ctx.completion.scope.module()?;
15 let n_fields = fields.len();
16 let fields = fields
17 .into_iter()
18 .filter(|field| field.is_visible_from(ctx.db(), module))
19 .copied()
20 .collect::<Vec<_>>();
21
22 let fields_omitted =
23 n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists();
24 Some((fields, fields_omitted))
25}
26
27pub(crate) fn render_struct_pat( 9pub(crate) fn render_struct_pat(
28 ctx: RenderContext<'_>, 10 ctx: RenderContext<'_>,
29 strukt: hir::Struct, 11 strukt: hir::Struct,
@@ -148,3 +130,21 @@ fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool)
148 name = name 130 name = name
149 ) 131 )
150} 132}
133
134fn visible_fields(
135 ctx: &RenderContext<'_>,
136 fields: &[hir::Field],
137 item: impl HasAttrs,
138) -> Option<(Vec<hir::Field>, bool)> {
139 let module = ctx.completion.scope.module()?;
140 let n_fields = fields.len();
141 let fields = fields
142 .into_iter()
143 .filter(|field| field.is_visible_from(ctx.db(), module))
144 .copied()
145 .collect::<Vec<_>>();
146
147 let fields_omitted =
148 n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists();
149 Some((fields, fields_omitted))
150}
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index 1f7a90d20..6229996ec 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1" 13cov-mark = { version = "1.1", features = ["thread-local"] }
14log = "0.4.8" 14log = "0.4.8"
15rayon = "1.5.0" 15rayon = "1.5.0"
16fst = { version = "0.4", default-features = false } 16fst = { version = "0.4", default-features = false }
diff --git a/crates/ide_ssr/Cargo.toml b/crates/ide_ssr/Cargo.toml
index 8c31df13a..5d2221ebc 100644
--- a/crates/ide_ssr/Cargo.toml
+++ b/crates/ide_ssr/Cargo.toml
@@ -11,7 +11,7 @@ edition = "2018"
11doctest = false 11doctest = false
12 12
13[dependencies] 13[dependencies]
14cov-mark = "1.1" 14cov-mark = { version = "1.1", features = ["thread-local"] }
15rustc-hash = "1.1.0" 15rustc-hash = "1.1.0"
16itertools = "0.10.0" 16itertools = "0.10.0"
17 17
diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml
index 139214207..8856787c0 100644
--- a/crates/mbe/Cargo.toml
+++ b/crates/mbe/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1" 13cov-mark = { version = "1.1", features = ["thread-local"] }
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15smallvec = "1.2.0" 15smallvec = "1.2.0"
16log = "0.4.8" 16log = "0.4.8"
diff --git a/crates/proc_macro_api/src/lib.rs b/crates/proc_macro_api/src/lib.rs
index 941d0fe9e..2dd2a8541 100644
--- a/crates/proc_macro_api/src/lib.rs
+++ b/crates/proc_macro_api/src/lib.rs
@@ -23,6 +23,7 @@ use tt::{SmolStr, Subtree};
23use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread}; 23use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
24 24
25pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind}; 25pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
26pub use version::{read_dylib_info, RustCInfo};
26 27
27#[derive(Debug, Clone)] 28#[derive(Debug, Clone)]
28struct ProcMacroProcessExpander { 29struct ProcMacroProcessExpander {
@@ -76,7 +77,7 @@ impl ProcMacroClient {
76 } 77 }
77 78
78 pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> { 79 pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> {
79 match version::read_info(dylib_path) { 80 match version::read_dylib_info(dylib_path) {
80 Ok(info) => { 81 Ok(info) => {
81 if info.version.0 < 1 || info.version.1 < 47 { 82 if info.version.0 < 1 || info.version.1 < 47 {
82 eprintln!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", dylib_path.to_string_lossy(), info); 83 eprintln!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", dylib_path.to_string_lossy(), info);
diff --git a/crates/proc_macro_api/src/version.rs b/crates/proc_macro_api/src/version.rs
index b903658fb..dcf8fae8f 100644
--- a/crates/proc_macro_api/src/version.rs
+++ b/crates/proc_macro_api/src/version.rs
@@ -11,14 +11,15 @@ use object::read::{File as BinaryFile, Object, ObjectSection};
11use snap::read::FrameDecoder as SnapDecoder; 11use snap::read::FrameDecoder as SnapDecoder;
12 12
13#[derive(Debug)] 13#[derive(Debug)]
14pub(crate) struct RustCInfo { 14pub struct RustCInfo {
15 pub(crate) version: (usize, usize, usize), 15 pub version: (usize, usize, usize),
16 pub(crate) channel: String, 16 pub channel: String,
17 pub(crate) commit: String, 17 pub commit: String,
18 pub(crate) date: String, 18 pub date: String,
19} 19}
20 20
21pub(crate) fn read_info(dylib_path: &Path) -> io::Result<RustCInfo> { 21/// Read rustc dylib information
22pub fn read_dylib_info(dylib_path: &Path) -> io::Result<RustCInfo> {
22 macro_rules! err { 23 macro_rules! err {
23 ($e:literal) => { 24 ($e:literal) => {
24 io::Error::new(io::ErrorKind::InvalidData, $e) 25 io::Error::new(io::ErrorKind::InvalidData, $e)
diff --git a/crates/proc_macro_srv/src/tests/mod.rs b/crates/proc_macro_srv/src/tests/mod.rs
index fd54f8dfd..b4ab4c077 100644
--- a/crates/proc_macro_srv/src/tests/mod.rs
+++ b/crates/proc_macro_srv/src/tests/mod.rs
@@ -56,3 +56,10 @@ DummyTrait [CustomDerive]"#,
56 &res 56 &res
57 ); 57 );
58} 58}
59
60#[test]
61fn test_version_check() {
62 let path = fixtures::dylib_path("proc_macro_test", "0.0.0");
63 let info = proc_macro_api::read_dylib_info(&path).unwrap();
64 assert!(info.version.1 >= 50);
65}
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs
index 0484c3af4..f15381f0f 100644
--- a/crates/proc_macro_srv/src/tests/utils.rs
+++ b/crates/proc_macro_srv/src/tests/utils.rs
@@ -6,7 +6,7 @@ use proc_macro_api::ListMacrosTask;
6use std::str::FromStr; 6use std::str::FromStr;
7use test_utils::assert_eq_text; 7use test_utils::assert_eq_text;
8 8
9mod fixtures { 9pub mod fixtures {
10 use cargo_metadata::Message; 10 use cargo_metadata::Message;
11 use std::path::PathBuf; 11 use std::path::PathBuf;
12 use std::process::Command; 12 use std::process::Command;
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 8af7871ac..8f541976e 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -172,7 +172,7 @@ config_data! {
172 notifications_cargoTomlNotFound: bool = "true", 172 notifications_cargoTomlNotFound: bool = "true",
173 173
174 /// Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`. 174 /// Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`.
175 procMacro_enable: bool = "false", 175 procMacro_enable: bool = "true",
176 /// Internal config, path to proc-macro server executable (typically, 176 /// Internal config, path to proc-macro server executable (typically,
177 /// this is rust-analyzer itself, but we override this in tests). 177 /// this is rust-analyzer itself, but we override this in tests).
178 procMacro_server: Option<PathBuf> = "null", 178 procMacro_server: Option<PathBuf> = "null",
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 05fca5dc4..c0fd894b0 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -11,7 +11,7 @@ edition = "2018"
11doctest = false 11doctest = false
12 12
13[dependencies] 13[dependencies]
14cov-mark = "1.1" 14cov-mark = { version = "1.1", features = ["thread-local"] }
15itertools = "0.10.0" 15itertools = "0.10.0"
16rowan = "0.12.2" 16rowan = "0.12.2"
17rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" } 17rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" }
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 042ba2d54..c2521289c 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -276,7 +276,7 @@ Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
276-- 276--
277Whether to show `can't find Cargo.toml` error message. 277Whether to show `can't find Cargo.toml` error message.
278-- 278--
279[[rust-analyzer.procMacro.enable]]rust-analyzer.procMacro.enable (default: `false`):: 279[[rust-analyzer.procMacro.enable]]rust-analyzer.procMacro.enable (default: `true`)::
280+ 280+
281-- 281--
282Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`. 282Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`.
diff --git a/editors/code/package.json b/editors/code/package.json
index 923e9b35a..a2ed9b2d5 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -690,7 +690,7 @@
690 }, 690 },
691 "rust-analyzer.procMacro.enable": { 691 "rust-analyzer.procMacro.enable": {
692 "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`.", 692 "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`.",
693 "default": false, 693 "default": true,
694 "type": "boolean" 694 "type": "boolean"
695 }, 695 },
696 "rust-analyzer.procMacro.server": { 696 "rust-analyzer.procMacro.server": {
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs
index 72de92c64..3d8d7589b 100644
--- a/xtask/src/metrics.rs
+++ b/xtask/src/metrics.rs
@@ -26,7 +26,7 @@ impl flags::Metrics {
26 } 26 }
27 { 27 {
28 let _d = pushd("./target/rustc-perf")?; 28 let _d = pushd("./target/rustc-perf")?;
29 cmd!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033").run()?; 29 cmd!("git reset --hard c52ee623e231e7690a93be88d943016968c1036b").run()?;
30 } 30 }
31 31
32 let _env = pushenv("RA_METRICS", "1"); 32 let _env = pushenv("RA_METRICS", "1");
@@ -35,6 +35,7 @@ impl flags::Metrics {
35 metrics.measure_analysis_stats_self()?; 35 metrics.measure_analysis_stats_self()?;
36 metrics.measure_analysis_stats("ripgrep")?; 36 metrics.measure_analysis_stats("ripgrep")?;
37 metrics.measure_analysis_stats("webrender")?; 37 metrics.measure_analysis_stats("webrender")?;
38 metrics.measure_analysis_stats("diesel/diesel")?;
38 39
39 if !self.dry_run { 40 if !self.dry_run {
40 let _d = pushd("target")?; 41 let _d = pushd("target")?;