diff options
-rw-r--r-- | Cargo.lock | 21 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 36 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_attribute.rs | 973 | ||||
-rw-r--r-- | crates/ra_ide_db/src/change.rs | 47 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/analysis_stats.rs | 18 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 5 | ||||
-rw-r--r-- | docs/user/manual.adoc | 56 | ||||
-rw-r--r-- | editors/code/package.json | 29 | ||||
-rw-r--r-- | editors/code/src/config.ts | 6 | ||||
-rw-r--r-- | editors/code/src/debug.ts | 16 | ||||
-rw-r--r-- | editors/code/src/run.ts | 35 | ||||
-rw-r--r-- | editors/code/tests/unit/runnable_env.test.ts | 118 |
13 files changed, 513 insertions, 867 deletions
diff --git a/Cargo.lock b/Cargo.lock index 61ae8157a..ce88b7403 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -208,20 +208,6 @@ dependencies = [ | |||
208 | ] | 208 | ] |
209 | 209 | ||
210 | [[package]] | 210 | [[package]] |
211 | name = "crossbeam" | ||
212 | version = "0.7.3" | ||
213 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
214 | checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" | ||
215 | dependencies = [ | ||
216 | "cfg-if", | ||
217 | "crossbeam-channel", | ||
218 | "crossbeam-deque", | ||
219 | "crossbeam-epoch", | ||
220 | "crossbeam-queue", | ||
221 | "crossbeam-utils", | ||
222 | ] | ||
223 | |||
224 | [[package]] | ||
225 | name = "crossbeam-channel" | 211 | name = "crossbeam-channel" |
226 | version = "0.4.2" | 212 | version = "0.4.2" |
227 | source = "registry+https://github.com/rust-lang/crates.io-index" | 213 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1504,12 +1490,13 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" | |||
1504 | 1490 | ||
1505 | [[package]] | 1491 | [[package]] |
1506 | name = "salsa" | 1492 | name = "salsa" |
1507 | version = "0.14.2" | 1493 | version = "0.14.3" |
1508 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1509 | checksum = "6a976dce155e392af3f1aa540ca23a6fc7303a7fef425cb431c464deb263eb54" | 1495 | checksum = "4cd4f099cf7f1d6147aeb313d3fb093d2be1bf71a9fac0122d171c7593206af3" |
1510 | dependencies = [ | 1496 | dependencies = [ |
1511 | "crossbeam", | 1497 | "crossbeam-utils", |
1512 | "indexmap", | 1498 | "indexmap", |
1499 | "lock_api", | ||
1513 | "log", | 1500 | "log", |
1514 | "parking_lot", | 1501 | "parking_lot", |
1515 | "rand", | 1502 | "rand", |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 3719f76a6..5c56c2eb0 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -28,8 +28,8 @@ use hir_def::{ | |||
28 | path::{path, Path}, | 28 | path::{path, Path}, |
29 | resolver::{HasResolver, Resolver, TypeNs}, | 29 | resolver::{HasResolver, Resolver, TypeNs}, |
30 | type_ref::{Mutability, TypeRef}, | 30 | type_ref::{Mutability, TypeRef}, |
31 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, TraitId, TypeAliasId, | 31 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId, |
32 | VariantId, | 32 | TypeAliasId, VariantId, |
33 | }; | 33 | }; |
34 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; | 34 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; |
35 | use ra_arena::map::ArenaMap; | 35 | use ra_arena::map::ArenaMap; |
@@ -376,17 +376,21 @@ impl<'a> InferenceContext<'a> { | |||
376 | ) -> Ty { | 376 | ) -> Ty { |
377 | match assoc_ty { | 377 | match assoc_ty { |
378 | Some(res_assoc_ty) => { | 378 | Some(res_assoc_ty) => { |
379 | let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container { | ||
380 | hir_def::AssocContainerId::TraitId(trait_) => trait_, | ||
381 | _ => panic!("resolve_associated_type called with non-associated type"), | ||
382 | }; | ||
379 | let ty = self.table.new_type_var(); | 383 | let ty = self.table.new_type_var(); |
380 | let builder = Substs::build_for_def(self.db, res_assoc_ty) | 384 | let substs = Substs::build_for_def(self.db, res_assoc_ty) |
381 | .push(inner_ty) | 385 | .push(inner_ty) |
382 | .fill(params.iter().cloned()); | 386 | .fill(params.iter().cloned()) |
387 | .build(); | ||
388 | let trait_ref = TraitRef { trait_, substs: substs.clone() }; | ||
383 | let projection = ProjectionPredicate { | 389 | let projection = ProjectionPredicate { |
384 | ty: ty.clone(), | 390 | ty: ty.clone(), |
385 | projection_ty: ProjectionTy { | 391 | projection_ty: ProjectionTy { associated_ty: res_assoc_ty, parameters: substs }, |
386 | associated_ty: res_assoc_ty, | ||
387 | parameters: builder.build(), | ||
388 | }, | ||
389 | }; | 392 | }; |
393 | self.obligations.push(Obligation::Trait(trait_ref)); | ||
390 | self.obligations.push(Obligation::Projection(projection)); | 394 | self.obligations.push(Obligation::Projection(projection)); |
391 | self.resolve_ty_as_possible(ty) | 395 | self.resolve_ty_as_possible(ty) |
392 | } | 396 | } |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 766790576..529d9e253 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -541,6 +541,42 @@ mod ops { | |||
541 | } | 541 | } |
542 | 542 | ||
543 | #[test] | 543 | #[test] |
544 | fn infer_ops_index_int() { | ||
545 | check_types( | ||
546 | r#" | ||
547 | //- /main.rs crate:main deps:std | ||
548 | struct Bar; | ||
549 | struct Foo; | ||
550 | |||
551 | impl std::ops::Index<u32> for Bar { | ||
552 | type Output = Foo; | ||
553 | } | ||
554 | |||
555 | struct Range; | ||
556 | impl std::ops::Index<Range> for Bar { | ||
557 | type Output = Bar; | ||
558 | } | ||
559 | |||
560 | fn test() { | ||
561 | let a = Bar; | ||
562 | let b = a[1]; | ||
563 | b; | ||
564 | //^ Foo | ||
565 | } | ||
566 | |||
567 | //- /std.rs crate:std | ||
568 | #[prelude_import] use ops::*; | ||
569 | mod ops { | ||
570 | #[lang = "index"] | ||
571 | pub trait Index<Idx> { | ||
572 | type Output; | ||
573 | } | ||
574 | } | ||
575 | "#, | ||
576 | ); | ||
577 | } | ||
578 | |||
579 | #[test] | ||
544 | fn infer_ops_index_autoderef() { | 580 | fn infer_ops_index_autoderef() { |
545 | check_types( | 581 | check_types( |
546 | r#" | 582 | r#" |
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index 6beeca457..9db317509 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs | |||
@@ -46,7 +46,7 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr | |||
46 | _ => {} | 46 | _ => {} |
47 | } | 47 | } |
48 | 48 | ||
49 | if attribute.kind() == ast::AttrKind::Inner || !attr_completion.should_be_inner { | 49 | if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner { |
50 | acc.add(item); | 50 | acc.add(item); |
51 | } | 51 | } |
52 | } | 52 | } |
@@ -56,159 +56,72 @@ struct AttrCompletion { | |||
56 | label: &'static str, | 56 | label: &'static str, |
57 | lookup: Option<&'static str>, | 57 | lookup: Option<&'static str>, |
58 | snippet: Option<&'static str>, | 58 | snippet: Option<&'static str>, |
59 | should_be_inner: bool, | 59 | prefer_inner: bool, |
60 | } | ||
61 | |||
62 | impl AttrCompletion { | ||
63 | const fn prefer_inner(self) -> AttrCompletion { | ||
64 | AttrCompletion { prefer_inner: true, ..self } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | const fn attr( | ||
69 | label: &'static str, | ||
70 | lookup: Option<&'static str>, | ||
71 | snippet: Option<&'static str>, | ||
72 | ) -> AttrCompletion { | ||
73 | AttrCompletion { label, lookup, snippet, prefer_inner: false } | ||
60 | } | 74 | } |
61 | 75 | ||
62 | const ATTRIBUTES: &[AttrCompletion] = &[ | 76 | const ATTRIBUTES: &[AttrCompletion] = &[ |
63 | AttrCompletion { | 77 | attr("allow(…)", Some("allow"), Some("allow(${0:lint})")), |
64 | label: "allow(…)", | 78 | attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")), |
65 | snippet: Some("allow(${0:lint})"), | 79 | attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")), |
66 | should_be_inner: false, | 80 | attr("deny(…)", Some("deny"), Some("deny(${0:lint})")), |
67 | lookup: Some("allow"), | 81 | attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)), |
68 | }, | 82 | attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)), |
69 | AttrCompletion { | 83 | attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), |
70 | label: "cfg_attr(…)", | 84 | attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), |
71 | snippet: Some("cfg_attr(${1:predicate}, ${0:attr})"), | 85 | attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), |
72 | should_be_inner: false, | ||
73 | lookup: Some("cfg_attr"), | ||
74 | }, | ||
75 | AttrCompletion { | ||
76 | label: "cfg(…)", | ||
77 | snippet: Some("cfg(${0:predicate})"), | ||
78 | should_be_inner: false, | ||
79 | lookup: Some("cfg"), | ||
80 | }, | ||
81 | AttrCompletion { | ||
82 | label: "deny(…)", | ||
83 | snippet: Some("deny(${0:lint})"), | ||
84 | should_be_inner: false, | ||
85 | lookup: Some("deny"), | ||
86 | }, | ||
87 | AttrCompletion { | ||
88 | label: r#"deprecated = "…""#, | ||
89 | snippet: Some(r#"deprecated = "${0:reason}""#), | ||
90 | should_be_inner: false, | ||
91 | lookup: Some("deprecated"), | ||
92 | }, | ||
93 | AttrCompletion { | ||
94 | label: "derive(…)", | ||
95 | snippet: Some(r#"derive(${0:Debug})"#), | ||
96 | should_be_inner: false, | ||
97 | lookup: Some("derive"), | ||
98 | }, | ||
99 | AttrCompletion { | ||
100 | label: r#"doc = "…""#, | ||
101 | snippet: Some(r#"doc = "${0:docs}""#), | ||
102 | should_be_inner: false, | ||
103 | lookup: Some("doc"), | ||
104 | }, | ||
105 | AttrCompletion { | ||
106 | label: "feature(…)", | ||
107 | snippet: Some("feature(${0:flag})"), | ||
108 | should_be_inner: true, | ||
109 | lookup: Some("feature"), | ||
110 | }, | ||
111 | AttrCompletion { | ||
112 | label: "forbid(…)", | ||
113 | snippet: Some("forbid(${0:lint})"), | ||
114 | should_be_inner: false, | ||
115 | lookup: Some("forbid"), | ||
116 | }, | ||
117 | // FIXME: resolve through macro resolution? | 86 | // FIXME: resolve through macro resolution? |
118 | AttrCompletion { | 87 | attr("global_allocator", None, None).prefer_inner(), |
119 | label: "global_allocator", | 88 | attr("ignore(…)", Some("ignore"), Some("ignore(${0:lint})")), |
120 | snippet: None, | 89 | attr("inline(…)", Some("inline"), Some("inline(${0:lint})")), |
121 | should_be_inner: true, | 90 | attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)), |
122 | lookup: None, | 91 | attr("link", None, None), |
123 | }, | 92 | attr("macro_export", None, None), |
124 | AttrCompletion { | 93 | attr("macro_use", None, None), |
125 | label: "ignore(…)", | 94 | attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)), |
126 | snippet: Some("ignore(${0:lint})"), | 95 | attr("no_mangle", None, None), |
127 | should_be_inner: false, | 96 | attr("no_std", None, None).prefer_inner(), |
128 | lookup: Some("ignore"), | 97 | attr("non_exhaustive", None, None), |
129 | }, | 98 | attr("panic_handler", None, None).prefer_inner(), |
130 | AttrCompletion { | 99 | attr("path = \"…\"", Some("path"), Some("path =\"${0:path}\"")), |
131 | label: "inline(…)", | 100 | attr("proc_macro", None, None), |
132 | snippet: Some("inline(${0:lint})"), | 101 | attr("proc_macro_attribute", None, None), |
133 | should_be_inner: false, | 102 | attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")), |
134 | lookup: Some("inline"), | 103 | attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}")) |
135 | }, | 104 | .prefer_inner(), |
136 | AttrCompletion { | 105 | attr("repr(…)", Some("repr"), Some("repr(${0:C})")), |
137 | label: r#"link_name = "…""#, | 106 | attr( |
138 | snippet: Some(r#"link_name = "${0:symbol_name}""#), | 107 | "should_panic(…)", |
139 | should_be_inner: false, | 108 | Some("should_panic"), |
140 | lookup: Some("link_name"), | 109 | Some(r#"should_panic(expected = "${0:reason}")"#), |
141 | }, | 110 | ), |
142 | AttrCompletion { label: "link", snippet: None, should_be_inner: false, lookup: None }, | 111 | attr( |
143 | AttrCompletion { label: "macro_export", snippet: None, should_be_inner: false, lookup: None }, | 112 | r#"target_feature = "…""#, |
144 | AttrCompletion { label: "macro_use", snippet: None, should_be_inner: false, lookup: None }, | 113 | Some("target_feature"), |
145 | AttrCompletion { | 114 | Some("target_feature = \"${0:feature}\""), |
146 | label: r#"must_use = "…""#, | 115 | ), |
147 | snippet: Some(r#"must_use = "${0:reason}""#), | 116 | attr("test", None, None), |
148 | should_be_inner: false, | 117 | attr("used", None, None), |
149 | lookup: Some("must_use"), | 118 | attr("warn(…)", Some("warn"), Some("warn(${0:lint})")), |
150 | }, | 119 | attr( |
151 | AttrCompletion { label: "no_mangle", snippet: None, should_be_inner: false, lookup: None }, | 120 | r#"windows_subsystem = "…""#, |
152 | AttrCompletion { label: "no_std", snippet: None, should_be_inner: true, lookup: None }, | 121 | Some("windows_subsystem"), |
153 | AttrCompletion { label: "non_exhaustive", snippet: None, should_be_inner: false, lookup: None }, | 122 | Some(r#"windows_subsystem = "${0:subsystem}""#), |
154 | AttrCompletion { label: "panic_handler", snippet: None, should_be_inner: true, lookup: None }, | 123 | ) |
155 | AttrCompletion { | 124 | .prefer_inner(), |
156 | label: "path = \"…\"", | ||
157 | snippet: Some("path =\"${0:path}\""), | ||
158 | should_be_inner: false, | ||
159 | lookup: Some("path"), | ||
160 | }, | ||
161 | AttrCompletion { label: "proc_macro", snippet: None, should_be_inner: false, lookup: None }, | ||
162 | AttrCompletion { | ||
163 | label: "proc_macro_attribute", | ||
164 | snippet: None, | ||
165 | should_be_inner: false, | ||
166 | lookup: None, | ||
167 | }, | ||
168 | AttrCompletion { | ||
169 | label: "proc_macro_derive(…)", | ||
170 | snippet: Some("proc_macro_derive(${0:Trait})"), | ||
171 | should_be_inner: false, | ||
172 | lookup: Some("proc_macro_derive"), | ||
173 | }, | ||
174 | AttrCompletion { | ||
175 | label: "recursion_limit = …", | ||
176 | snippet: Some("recursion_limit = ${0:128}"), | ||
177 | should_be_inner: true, | ||
178 | lookup: Some("recursion_limit"), | ||
179 | }, | ||
180 | AttrCompletion { | ||
181 | label: "repr(…)", | ||
182 | snippet: Some("repr(${0:C})"), | ||
183 | should_be_inner: false, | ||
184 | lookup: Some("repr"), | ||
185 | }, | ||
186 | AttrCompletion { | ||
187 | label: "should_panic(…)", | ||
188 | snippet: Some(r#"should_panic(expected = "${0:reason}")"#), | ||
189 | should_be_inner: false, | ||
190 | lookup: Some("should_panic"), | ||
191 | }, | ||
192 | AttrCompletion { | ||
193 | label: r#"target_feature = "…""#, | ||
194 | snippet: Some("target_feature = \"${0:feature}\""), | ||
195 | should_be_inner: false, | ||
196 | lookup: Some("target_feature"), | ||
197 | }, | ||
198 | AttrCompletion { label: "test", snippet: None, should_be_inner: false, lookup: None }, | ||
199 | AttrCompletion { label: "used", snippet: None, should_be_inner: false, lookup: None }, | ||
200 | AttrCompletion { | ||
201 | label: "warn(…)", | ||
202 | snippet: Some("warn(${0:lint})"), | ||
203 | should_be_inner: false, | ||
204 | lookup: Some("warn"), | ||
205 | }, | ||
206 | AttrCompletion { | ||
207 | label: r#"windows_subsystem = "…""#, | ||
208 | snippet: Some(r#"windows_subsystem = "${0:subsystem}""#), | ||
209 | should_be_inner: true, | ||
210 | lookup: Some("windows_subsystem"), | ||
211 | }, | ||
212 | ]; | 125 | ]; |
213 | 126 | ||
214 | fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { | 127 | fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { |
@@ -313,677 +226,147 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ | |||
313 | 226 | ||
314 | #[cfg(test)] | 227 | #[cfg(test)] |
315 | mod tests { | 228 | mod tests { |
316 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 229 | use expect::{expect, Expect}; |
317 | use insta::assert_debug_snapshot; | ||
318 | 230 | ||
319 | fn do_attr_completion(code: &str) -> Vec<CompletionItem> { | 231 | use crate::completion::{test_utils::completion_list, CompletionKind}; |
320 | do_completion(code, CompletionKind::Attribute) | 232 | |
233 | fn check(ra_fixture: &str, expect: Expect) { | ||
234 | let actual = completion_list(ra_fixture, CompletionKind::Attribute); | ||
235 | expect.assert_eq(&actual); | ||
321 | } | 236 | } |
322 | 237 | ||
323 | #[test] | 238 | #[test] |
324 | fn empty_derive_completion() { | 239 | fn empty_derive_completion() { |
325 | assert_debug_snapshot!( | 240 | check( |
326 | do_attr_completion( | 241 | r#" |
327 | r" | 242 | #[derive(<|>)] |
328 | #[derive(<|>)] | 243 | struct Test {} |
329 | struct Test {} | 244 | "#, |
330 | ", | 245 | expect![[r#" |
331 | ), | 246 | at Clone |
332 | @r###" | 247 | at Copy, Clone |
333 | [ | 248 | at Debug |
334 | CompletionItem { | 249 | at Default |
335 | label: "Clone", | 250 | at Eq, PartialEq |
336 | source_range: 9..9, | 251 | at Hash |
337 | delete: 9..9, | 252 | at Ord, PartialOrd, Eq, PartialEq |
338 | insert: "Clone", | 253 | at PartialEq |
339 | kind: Attribute, | 254 | at PartialOrd, PartialEq |
340 | }, | 255 | "#]], |
341 | CompletionItem { | ||
342 | label: "Copy, Clone", | ||
343 | source_range: 9..9, | ||
344 | delete: 9..9, | ||
345 | insert: "Copy, Clone", | ||
346 | kind: Attribute, | ||
347 | }, | ||
348 | CompletionItem { | ||
349 | label: "Debug", | ||
350 | source_range: 9..9, | ||
351 | delete: 9..9, | ||
352 | insert: "Debug", | ||
353 | kind: Attribute, | ||
354 | }, | ||
355 | CompletionItem { | ||
356 | label: "Default", | ||
357 | source_range: 9..9, | ||
358 | delete: 9..9, | ||
359 | insert: "Default", | ||
360 | kind: Attribute, | ||
361 | }, | ||
362 | CompletionItem { | ||
363 | label: "Eq, PartialEq", | ||
364 | source_range: 9..9, | ||
365 | delete: 9..9, | ||
366 | insert: "Eq, PartialEq", | ||
367 | kind: Attribute, | ||
368 | }, | ||
369 | CompletionItem { | ||
370 | label: "Hash", | ||
371 | source_range: 9..9, | ||
372 | delete: 9..9, | ||
373 | insert: "Hash", | ||
374 | kind: Attribute, | ||
375 | }, | ||
376 | CompletionItem { | ||
377 | label: "Ord, PartialOrd, Eq, PartialEq", | ||
378 | source_range: 9..9, | ||
379 | delete: 9..9, | ||
380 | insert: "Ord, PartialOrd, Eq, PartialEq", | ||
381 | kind: Attribute, | ||
382 | }, | ||
383 | CompletionItem { | ||
384 | label: "PartialEq", | ||
385 | source_range: 9..9, | ||
386 | delete: 9..9, | ||
387 | insert: "PartialEq", | ||
388 | kind: Attribute, | ||
389 | }, | ||
390 | CompletionItem { | ||
391 | label: "PartialOrd, PartialEq", | ||
392 | source_range: 9..9, | ||
393 | delete: 9..9, | ||
394 | insert: "PartialOrd, PartialEq", | ||
395 | kind: Attribute, | ||
396 | }, | ||
397 | ] | ||
398 | "### | ||
399 | ); | 256 | ); |
400 | } | 257 | } |
401 | 258 | ||
402 | #[test] | 259 | #[test] |
403 | fn no_completion_for_incorrect_derive() { | 260 | fn no_completion_for_incorrect_derive() { |
404 | assert_debug_snapshot!( | 261 | check( |
405 | do_attr_completion( | 262 | r#" |
406 | r" | 263 | #[derive{<|>)] |
407 | #[derive{<|>)] | 264 | struct Test {} |
408 | struct Test {} | 265 | "#, |
409 | ", | 266 | expect![[r#""#]], |
410 | ), | 267 | ) |
411 | @"[]" | ||
412 | ); | ||
413 | } | 268 | } |
414 | 269 | ||
415 | #[test] | 270 | #[test] |
416 | fn derive_with_input_completion() { | 271 | fn derive_with_input_completion() { |
417 | assert_debug_snapshot!( | 272 | check( |
418 | do_attr_completion( | 273 | r#" |
419 | r" | 274 | #[derive(serde::Serialize, PartialEq, <|>)] |
420 | #[derive(serde::Serialize, PartialEq, <|>)] | 275 | struct Test {} |
421 | struct Test {} | 276 | "#, |
422 | ", | 277 | expect![[r#" |
423 | ), | 278 | at Clone |
424 | @r###" | 279 | at Copy, Clone |
425 | [ | 280 | at Debug |
426 | CompletionItem { | 281 | at Default |
427 | label: "Clone", | 282 | at Eq |
428 | source_range: 38..38, | 283 | at Hash |
429 | delete: 38..38, | 284 | at Ord, PartialOrd, Eq |
430 | insert: "Clone", | 285 | at PartialOrd |
431 | kind: Attribute, | 286 | "#]], |
432 | }, | 287 | ) |
433 | CompletionItem { | ||
434 | label: "Copy, Clone", | ||
435 | source_range: 38..38, | ||
436 | delete: 38..38, | ||
437 | insert: "Copy, Clone", | ||
438 | kind: Attribute, | ||
439 | }, | ||
440 | CompletionItem { | ||
441 | label: "Debug", | ||
442 | source_range: 38..38, | ||
443 | delete: 38..38, | ||
444 | insert: "Debug", | ||
445 | kind: Attribute, | ||
446 | }, | ||
447 | CompletionItem { | ||
448 | label: "Default", | ||
449 | source_range: 38..38, | ||
450 | delete: 38..38, | ||
451 | insert: "Default", | ||
452 | kind: Attribute, | ||
453 | }, | ||
454 | CompletionItem { | ||
455 | label: "Eq", | ||
456 | source_range: 38..38, | ||
457 | delete: 38..38, | ||
458 | insert: "Eq", | ||
459 | kind: Attribute, | ||
460 | }, | ||
461 | CompletionItem { | ||
462 | label: "Hash", | ||
463 | source_range: 38..38, | ||
464 | delete: 38..38, | ||
465 | insert: "Hash", | ||
466 | kind: Attribute, | ||
467 | }, | ||
468 | CompletionItem { | ||
469 | label: "Ord, PartialOrd, Eq", | ||
470 | source_range: 38..38, | ||
471 | delete: 38..38, | ||
472 | insert: "Ord, PartialOrd, Eq", | ||
473 | kind: Attribute, | ||
474 | }, | ||
475 | CompletionItem { | ||
476 | label: "PartialOrd", | ||
477 | source_range: 38..38, | ||
478 | delete: 38..38, | ||
479 | insert: "PartialOrd", | ||
480 | kind: Attribute, | ||
481 | }, | ||
482 | ] | ||
483 | "### | ||
484 | ); | ||
485 | } | 288 | } |
486 | 289 | ||
487 | #[test] | 290 | #[test] |
488 | fn test_attribute_completion() { | 291 | fn test_attribute_completion() { |
489 | assert_debug_snapshot!( | 292 | check( |
490 | do_attr_completion( | 293 | r#"#[<|>]"#, |
491 | r" | 294 | expect![[r#" |
492 | #[<|>] | 295 | at allow(…) |
493 | ", | 296 | at cfg(…) |
494 | ), | 297 | at cfg_attr(…) |
495 | @r###" | 298 | at deny(…) |
496 | [ | 299 | at deprecated = "…" |
497 | CompletionItem { | 300 | at derive(…) |
498 | label: "allow(…)", | 301 | at doc = "…" |
499 | source_range: 2..2, | 302 | at forbid(…) |
500 | delete: 2..2, | 303 | at ignore(…) |
501 | insert: "allow(${0:lint})", | 304 | at inline(…) |
502 | kind: Attribute, | 305 | at link |
503 | lookup: "allow", | 306 | at link_name = "…" |
504 | }, | 307 | at macro_export |
505 | CompletionItem { | 308 | at macro_use |
506 | label: "cfg(…)", | 309 | at must_use = "…" |
507 | source_range: 2..2, | 310 | at no_mangle |
508 | delete: 2..2, | 311 | at non_exhaustive |
509 | insert: "cfg(${0:predicate})", | 312 | at path = "…" |
510 | kind: Attribute, | 313 | at proc_macro |
511 | lookup: "cfg", | 314 | at proc_macro_attribute |
512 | }, | 315 | at proc_macro_derive(…) |
513 | CompletionItem { | 316 | at repr(…) |
514 | label: "cfg_attr(…)", | 317 | at should_panic(…) |
515 | source_range: 2..2, | 318 | at target_feature = "…" |
516 | delete: 2..2, | 319 | at test |
517 | insert: "cfg_attr(${1:predicate}, ${0:attr})", | 320 | at used |
518 | kind: Attribute, | 321 | at warn(…) |
519 | lookup: "cfg_attr", | 322 | "#]], |
520 | }, | 323 | ) |
521 | CompletionItem { | ||
522 | label: "deny(…)", | ||
523 | source_range: 2..2, | ||
524 | delete: 2..2, | ||
525 | insert: "deny(${0:lint})", | ||
526 | kind: Attribute, | ||
527 | lookup: "deny", | ||
528 | }, | ||
529 | CompletionItem { | ||
530 | label: "deprecated = \"…\"", | ||
531 | source_range: 2..2, | ||
532 | delete: 2..2, | ||
533 | insert: "deprecated = \"${0:reason}\"", | ||
534 | kind: Attribute, | ||
535 | lookup: "deprecated", | ||
536 | }, | ||
537 | CompletionItem { | ||
538 | label: "derive(…)", | ||
539 | source_range: 2..2, | ||
540 | delete: 2..2, | ||
541 | insert: "derive(${0:Debug})", | ||
542 | kind: Attribute, | ||
543 | lookup: "derive", | ||
544 | }, | ||
545 | CompletionItem { | ||
546 | label: "doc = \"…\"", | ||
547 | source_range: 2..2, | ||
548 | delete: 2..2, | ||
549 | insert: "doc = \"${0:docs}\"", | ||
550 | kind: Attribute, | ||
551 | lookup: "doc", | ||
552 | }, | ||
553 | CompletionItem { | ||
554 | label: "forbid(…)", | ||
555 | source_range: 2..2, | ||
556 | delete: 2..2, | ||
557 | insert: "forbid(${0:lint})", | ||
558 | kind: Attribute, | ||
559 | lookup: "forbid", | ||
560 | }, | ||
561 | CompletionItem { | ||
562 | label: "ignore(…)", | ||
563 | source_range: 2..2, | ||
564 | delete: 2..2, | ||
565 | insert: "ignore(${0:lint})", | ||
566 | kind: Attribute, | ||
567 | lookup: "ignore", | ||
568 | }, | ||
569 | CompletionItem { | ||
570 | label: "inline(…)", | ||
571 | source_range: 2..2, | ||
572 | delete: 2..2, | ||
573 | insert: "inline(${0:lint})", | ||
574 | kind: Attribute, | ||
575 | lookup: "inline", | ||
576 | }, | ||
577 | CompletionItem { | ||
578 | label: "link", | ||
579 | source_range: 2..2, | ||
580 | delete: 2..2, | ||
581 | insert: "link", | ||
582 | kind: Attribute, | ||
583 | }, | ||
584 | CompletionItem { | ||
585 | label: "link_name = \"…\"", | ||
586 | source_range: 2..2, | ||
587 | delete: 2..2, | ||
588 | insert: "link_name = \"${0:symbol_name}\"", | ||
589 | kind: Attribute, | ||
590 | lookup: "link_name", | ||
591 | }, | ||
592 | CompletionItem { | ||
593 | label: "macro_export", | ||
594 | source_range: 2..2, | ||
595 | delete: 2..2, | ||
596 | insert: "macro_export", | ||
597 | kind: Attribute, | ||
598 | }, | ||
599 | CompletionItem { | ||
600 | label: "macro_use", | ||
601 | source_range: 2..2, | ||
602 | delete: 2..2, | ||
603 | insert: "macro_use", | ||
604 | kind: Attribute, | ||
605 | }, | ||
606 | CompletionItem { | ||
607 | label: "must_use = \"…\"", | ||
608 | source_range: 2..2, | ||
609 | delete: 2..2, | ||
610 | insert: "must_use = \"${0:reason}\"", | ||
611 | kind: Attribute, | ||
612 | lookup: "must_use", | ||
613 | }, | ||
614 | CompletionItem { | ||
615 | label: "no_mangle", | ||
616 | source_range: 2..2, | ||
617 | delete: 2..2, | ||
618 | insert: "no_mangle", | ||
619 | kind: Attribute, | ||
620 | }, | ||
621 | CompletionItem { | ||
622 | label: "non_exhaustive", | ||
623 | source_range: 2..2, | ||
624 | delete: 2..2, | ||
625 | insert: "non_exhaustive", | ||
626 | kind: Attribute, | ||
627 | }, | ||
628 | CompletionItem { | ||
629 | label: "path = \"…\"", | ||
630 | source_range: 2..2, | ||
631 | delete: 2..2, | ||
632 | insert: "path =\"${0:path}\"", | ||
633 | kind: Attribute, | ||
634 | lookup: "path", | ||
635 | }, | ||
636 | CompletionItem { | ||
637 | label: "proc_macro", | ||
638 | source_range: 2..2, | ||
639 | delete: 2..2, | ||
640 | insert: "proc_macro", | ||
641 | kind: Attribute, | ||
642 | }, | ||
643 | CompletionItem { | ||
644 | label: "proc_macro_attribute", | ||
645 | source_range: 2..2, | ||
646 | delete: 2..2, | ||
647 | insert: "proc_macro_attribute", | ||
648 | kind: Attribute, | ||
649 | }, | ||
650 | CompletionItem { | ||
651 | label: "proc_macro_derive(…)", | ||
652 | source_range: 2..2, | ||
653 | delete: 2..2, | ||
654 | insert: "proc_macro_derive(${0:Trait})", | ||
655 | kind: Attribute, | ||
656 | lookup: "proc_macro_derive", | ||
657 | }, | ||
658 | CompletionItem { | ||
659 | label: "repr(…)", | ||
660 | source_range: 2..2, | ||
661 | delete: 2..2, | ||
662 | insert: "repr(${0:C})", | ||
663 | kind: Attribute, | ||
664 | lookup: "repr", | ||
665 | }, | ||
666 | CompletionItem { | ||
667 | label: "should_panic(…)", | ||
668 | source_range: 2..2, | ||
669 | delete: 2..2, | ||
670 | insert: "should_panic(expected = \"${0:reason}\")", | ||
671 | kind: Attribute, | ||
672 | lookup: "should_panic", | ||
673 | }, | ||
674 | CompletionItem { | ||
675 | label: "target_feature = \"…\"", | ||
676 | source_range: 2..2, | ||
677 | delete: 2..2, | ||
678 | insert: "target_feature = \"${0:feature}\"", | ||
679 | kind: Attribute, | ||
680 | lookup: "target_feature", | ||
681 | }, | ||
682 | CompletionItem { | ||
683 | label: "test", | ||
684 | source_range: 2..2, | ||
685 | delete: 2..2, | ||
686 | insert: "test", | ||
687 | kind: Attribute, | ||
688 | }, | ||
689 | CompletionItem { | ||
690 | label: "used", | ||
691 | source_range: 2..2, | ||
692 | delete: 2..2, | ||
693 | insert: "used", | ||
694 | kind: Attribute, | ||
695 | }, | ||
696 | CompletionItem { | ||
697 | label: "warn(…)", | ||
698 | source_range: 2..2, | ||
699 | delete: 2..2, | ||
700 | insert: "warn(${0:lint})", | ||
701 | kind: Attribute, | ||
702 | lookup: "warn", | ||
703 | }, | ||
704 | ] | ||
705 | "### | ||
706 | ); | ||
707 | } | 324 | } |
708 | 325 | ||
709 | #[test] | 326 | #[test] |
710 | fn test_attribute_completion_inside_nested_attr() { | 327 | fn test_attribute_completion_inside_nested_attr() { |
711 | assert_debug_snapshot!( | 328 | check(r#"#[allow(<|>)]"#, expect![[]]) |
712 | do_attr_completion( | ||
713 | r" | ||
714 | #[allow(<|>)] | ||
715 | ", | ||
716 | ), | ||
717 | @r###" | ||
718 | [] | ||
719 | "### | ||
720 | ); | ||
721 | } | 329 | } |
722 | 330 | ||
723 | #[test] | 331 | #[test] |
724 | fn test_inner_attribute_completion() { | 332 | fn test_inner_attribute_completion() { |
725 | assert_debug_snapshot!( | 333 | check( |
726 | do_attr_completion( | 334 | r"#![<|>]", |
727 | r" | 335 | expect![[r#" |
728 | #![<|>] | 336 | at allow(…) |
729 | ", | 337 | at cfg(…) |
730 | ), | 338 | at cfg_attr(…) |
731 | @r###" | 339 | at deny(…) |
732 | [ | 340 | at deprecated = "…" |
733 | CompletionItem { | 341 | at derive(…) |
734 | label: "allow(…)", | 342 | at doc = "…" |
735 | source_range: 3..3, | 343 | at feature(…) |
736 | delete: 3..3, | 344 | at forbid(…) |
737 | insert: "allow(${0:lint})", | 345 | at global_allocator |
738 | kind: Attribute, | 346 | at ignore(…) |
739 | lookup: "allow", | 347 | at inline(…) |
740 | }, | 348 | at link |
741 | CompletionItem { | 349 | at link_name = "…" |
742 | label: "cfg(…)", | 350 | at macro_export |
743 | source_range: 3..3, | 351 | at macro_use |
744 | delete: 3..3, | 352 | at must_use = "…" |
745 | insert: "cfg(${0:predicate})", | 353 | at no_mangle |
746 | kind: Attribute, | 354 | at no_std |
747 | lookup: "cfg", | 355 | at non_exhaustive |
748 | }, | 356 | at panic_handler |
749 | CompletionItem { | 357 | at path = "…" |
750 | label: "cfg_attr(…)", | 358 | at proc_macro |
751 | source_range: 3..3, | 359 | at proc_macro_attribute |
752 | delete: 3..3, | 360 | at proc_macro_derive(…) |
753 | insert: "cfg_attr(${1:predicate}, ${0:attr})", | 361 | at recursion_limit = … |
754 | kind: Attribute, | 362 | at repr(…) |
755 | lookup: "cfg_attr", | 363 | at should_panic(…) |
756 | }, | 364 | at target_feature = "…" |
757 | CompletionItem { | 365 | at test |
758 | label: "deny(…)", | 366 | at used |
759 | source_range: 3..3, | 367 | at warn(…) |
760 | delete: 3..3, | 368 | at windows_subsystem = "…" |
761 | insert: "deny(${0:lint})", | 369 | "#]], |
762 | kind: Attribute, | ||
763 | lookup: "deny", | ||
764 | }, | ||
765 | CompletionItem { | ||
766 | label: "deprecated = \"…\"", | ||
767 | source_range: 3..3, | ||
768 | delete: 3..3, | ||
769 | insert: "deprecated = \"${0:reason}\"", | ||
770 | kind: Attribute, | ||
771 | lookup: "deprecated", | ||
772 | }, | ||
773 | CompletionItem { | ||
774 | label: "derive(…)", | ||
775 | source_range: 3..3, | ||
776 | delete: 3..3, | ||
777 | insert: "derive(${0:Debug})", | ||
778 | kind: Attribute, | ||
779 | lookup: "derive", | ||
780 | }, | ||
781 | CompletionItem { | ||
782 | label: "doc = \"…\"", | ||
783 | source_range: 3..3, | ||
784 | delete: 3..3, | ||
785 | insert: "doc = \"${0:docs}\"", | ||
786 | kind: Attribute, | ||
787 | lookup: "doc", | ||
788 | }, | ||
789 | CompletionItem { | ||
790 | label: "feature(…)", | ||
791 | source_range: 3..3, | ||
792 | delete: 3..3, | ||
793 | insert: "feature(${0:flag})", | ||
794 | kind: Attribute, | ||
795 | lookup: "feature", | ||
796 | }, | ||
797 | CompletionItem { | ||
798 | label: "forbid(…)", | ||
799 | source_range: 3..3, | ||
800 | delete: 3..3, | ||
801 | insert: "forbid(${0:lint})", | ||
802 | kind: Attribute, | ||
803 | lookup: "forbid", | ||
804 | }, | ||
805 | CompletionItem { | ||
806 | label: "global_allocator", | ||
807 | source_range: 3..3, | ||
808 | delete: 3..3, | ||
809 | insert: "global_allocator", | ||
810 | kind: Attribute, | ||
811 | }, | ||
812 | CompletionItem { | ||
813 | label: "ignore(…)", | ||
814 | source_range: 3..3, | ||
815 | delete: 3..3, | ||
816 | insert: "ignore(${0:lint})", | ||
817 | kind: Attribute, | ||
818 | lookup: "ignore", | ||
819 | }, | ||
820 | CompletionItem { | ||
821 | label: "inline(…)", | ||
822 | source_range: 3..3, | ||
823 | delete: 3..3, | ||
824 | insert: "inline(${0:lint})", | ||
825 | kind: Attribute, | ||
826 | lookup: "inline", | ||
827 | }, | ||
828 | CompletionItem { | ||
829 | label: "link", | ||
830 | source_range: 3..3, | ||
831 | delete: 3..3, | ||
832 | insert: "link", | ||
833 | kind: Attribute, | ||
834 | }, | ||
835 | CompletionItem { | ||
836 | label: "link_name = \"…\"", | ||
837 | source_range: 3..3, | ||
838 | delete: 3..3, | ||
839 | insert: "link_name = \"${0:symbol_name}\"", | ||
840 | kind: Attribute, | ||
841 | lookup: "link_name", | ||
842 | }, | ||
843 | CompletionItem { | ||
844 | label: "macro_export", | ||
845 | source_range: 3..3, | ||
846 | delete: 3..3, | ||
847 | insert: "macro_export", | ||
848 | kind: Attribute, | ||
849 | }, | ||
850 | CompletionItem { | ||
851 | label: "macro_use", | ||
852 | source_range: 3..3, | ||
853 | delete: 3..3, | ||
854 | insert: "macro_use", | ||
855 | kind: Attribute, | ||
856 | }, | ||
857 | CompletionItem { | ||
858 | label: "must_use = \"…\"", | ||
859 | source_range: 3..3, | ||
860 | delete: 3..3, | ||
861 | insert: "must_use = \"${0:reason}\"", | ||
862 | kind: Attribute, | ||
863 | lookup: "must_use", | ||
864 | }, | ||
865 | CompletionItem { | ||
866 | label: "no_mangle", | ||
867 | source_range: 3..3, | ||
868 | delete: 3..3, | ||
869 | insert: "no_mangle", | ||
870 | kind: Attribute, | ||
871 | }, | ||
872 | CompletionItem { | ||
873 | label: "no_std", | ||
874 | source_range: 3..3, | ||
875 | delete: 3..3, | ||
876 | insert: "no_std", | ||
877 | kind: Attribute, | ||
878 | }, | ||
879 | CompletionItem { | ||
880 | label: "non_exhaustive", | ||
881 | source_range: 3..3, | ||
882 | delete: 3..3, | ||
883 | insert: "non_exhaustive", | ||
884 | kind: Attribute, | ||
885 | }, | ||
886 | CompletionItem { | ||
887 | label: "panic_handler", | ||
888 | source_range: 3..3, | ||
889 | delete: 3..3, | ||
890 | insert: "panic_handler", | ||
891 | kind: Attribute, | ||
892 | }, | ||
893 | CompletionItem { | ||
894 | label: "path = \"…\"", | ||
895 | source_range: 3..3, | ||
896 | delete: 3..3, | ||
897 | insert: "path =\"${0:path}\"", | ||
898 | kind: Attribute, | ||
899 | lookup: "path", | ||
900 | }, | ||
901 | CompletionItem { | ||
902 | label: "proc_macro", | ||
903 | source_range: 3..3, | ||
904 | delete: 3..3, | ||
905 | insert: "proc_macro", | ||
906 | kind: Attribute, | ||
907 | }, | ||
908 | CompletionItem { | ||
909 | label: "proc_macro_attribute", | ||
910 | source_range: 3..3, | ||
911 | delete: 3..3, | ||
912 | insert: "proc_macro_attribute", | ||
913 | kind: Attribute, | ||
914 | }, | ||
915 | CompletionItem { | ||
916 | label: "proc_macro_derive(…)", | ||
917 | source_range: 3..3, | ||
918 | delete: 3..3, | ||
919 | insert: "proc_macro_derive(${0:Trait})", | ||
920 | kind: Attribute, | ||
921 | lookup: "proc_macro_derive", | ||
922 | }, | ||
923 | CompletionItem { | ||
924 | label: "recursion_limit = …", | ||
925 | source_range: 3..3, | ||
926 | delete: 3..3, | ||
927 | insert: "recursion_limit = ${0:128}", | ||
928 | kind: Attribute, | ||
929 | lookup: "recursion_limit", | ||
930 | }, | ||
931 | CompletionItem { | ||
932 | label: "repr(…)", | ||
933 | source_range: 3..3, | ||
934 | delete: 3..3, | ||
935 | insert: "repr(${0:C})", | ||
936 | kind: Attribute, | ||
937 | lookup: "repr", | ||
938 | }, | ||
939 | CompletionItem { | ||
940 | label: "should_panic(…)", | ||
941 | source_range: 3..3, | ||
942 | delete: 3..3, | ||
943 | insert: "should_panic(expected = \"${0:reason}\")", | ||
944 | kind: Attribute, | ||
945 | lookup: "should_panic", | ||
946 | }, | ||
947 | CompletionItem { | ||
948 | label: "target_feature = \"…\"", | ||
949 | source_range: 3..3, | ||
950 | delete: 3..3, | ||
951 | insert: "target_feature = \"${0:feature}\"", | ||
952 | kind: Attribute, | ||
953 | lookup: "target_feature", | ||
954 | }, | ||
955 | CompletionItem { | ||
956 | label: "test", | ||
957 | source_range: 3..3, | ||
958 | delete: 3..3, | ||
959 | insert: "test", | ||
960 | kind: Attribute, | ||
961 | }, | ||
962 | CompletionItem { | ||
963 | label: "used", | ||
964 | source_range: 3..3, | ||
965 | delete: 3..3, | ||
966 | insert: "used", | ||
967 | kind: Attribute, | ||
968 | }, | ||
969 | CompletionItem { | ||
970 | label: "warn(…)", | ||
971 | source_range: 3..3, | ||
972 | delete: 3..3, | ||
973 | insert: "warn(${0:lint})", | ||
974 | kind: Attribute, | ||
975 | lookup: "warn", | ||
976 | }, | ||
977 | CompletionItem { | ||
978 | label: "windows_subsystem = \"…\"", | ||
979 | source_range: 3..3, | ||
980 | delete: 3..3, | ||
981 | insert: "windows_subsystem = \"${0:subsystem}\"", | ||
982 | kind: Attribute, | ||
983 | lookup: "windows_subsystem", | ||
984 | }, | ||
985 | ] | ||
986 | "### | ||
987 | ); | 370 | ); |
988 | } | 371 | } |
989 | } | 372 | } |
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index dbe6eacc5..2504d7a33 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs | |||
@@ -191,12 +191,10 @@ impl RootDatabase { | |||
191 | 191 | ||
192 | // AstDatabase | 192 | // AstDatabase |
193 | hir::db::AstIdMapQuery | 193 | hir::db::AstIdMapQuery |
194 | hir::db::InternMacroQuery | ||
195 | hir::db::MacroArgQuery | 194 | hir::db::MacroArgQuery |
196 | hir::db::MacroDefQuery | 195 | hir::db::MacroDefQuery |
197 | hir::db::ParseMacroQuery | 196 | hir::db::ParseMacroQuery |
198 | hir::db::MacroExpandQuery | 197 | hir::db::MacroExpandQuery |
199 | hir::db::InternEagerExpansionQuery | ||
200 | 198 | ||
201 | // DefDatabase | 199 | // DefDatabase |
202 | hir::db::ItemTreeQuery | 200 | hir::db::ItemTreeQuery |
@@ -221,17 +219,6 @@ impl RootDatabase { | |||
221 | hir::db::DocumentationQuery | 219 | hir::db::DocumentationQuery |
222 | hir::db::ImportMapQuery | 220 | hir::db::ImportMapQuery |
223 | 221 | ||
224 | // InternDatabase | ||
225 | hir::db::InternFunctionQuery | ||
226 | hir::db::InternStructQuery | ||
227 | hir::db::InternUnionQuery | ||
228 | hir::db::InternEnumQuery | ||
229 | hir::db::InternConstQuery | ||
230 | hir::db::InternStaticQuery | ||
231 | hir::db::InternTraitQuery | ||
232 | hir::db::InternTypeAliasQuery | ||
233 | hir::db::InternImplQuery | ||
234 | |||
235 | // HirDatabase | 222 | // HirDatabase |
236 | hir::db::InferQueryQuery | 223 | hir::db::InferQueryQuery |
237 | hir::db::TyQuery | 224 | hir::db::TyQuery |
@@ -246,10 +233,6 @@ impl RootDatabase { | |||
246 | hir::db::InherentImplsInCrateQuery | 233 | hir::db::InherentImplsInCrateQuery |
247 | hir::db::TraitImplsInCrateQuery | 234 | hir::db::TraitImplsInCrateQuery |
248 | hir::db::TraitImplsInDepsQuery | 235 | hir::db::TraitImplsInDepsQuery |
249 | hir::db::InternTypeCtorQuery | ||
250 | hir::db::InternTypeParamIdQuery | ||
251 | hir::db::InternChalkImplQuery | ||
252 | hir::db::InternAssocTyValueQuery | ||
253 | hir::db::AssociatedTyDataQuery | 236 | hir::db::AssociatedTyDataQuery |
254 | hir::db::TraitDatumQuery | 237 | hir::db::TraitDatumQuery |
255 | hir::db::StructDatumQuery | 238 | hir::db::StructDatumQuery |
@@ -264,6 +247,36 @@ impl RootDatabase { | |||
264 | // LineIndexDatabase | 247 | // LineIndexDatabase |
265 | crate::LineIndexQuery | 248 | crate::LineIndexQuery |
266 | ]; | 249 | ]; |
250 | |||
251 | // To collect interned data, we need to bump the revision counter by performing a synthetic | ||
252 | // write. | ||
253 | // We do this after collecting the non-interned queries to correctly attribute memory used | ||
254 | // by interned data. | ||
255 | self.runtime.synthetic_write(Durability::HIGH); | ||
256 | |||
257 | sweep_each_query![ | ||
258 | // AstDatabase | ||
259 | hir::db::InternMacroQuery | ||
260 | hir::db::InternEagerExpansionQuery | ||
261 | |||
262 | // InternDatabase | ||
263 | hir::db::InternFunctionQuery | ||
264 | hir::db::InternStructQuery | ||
265 | hir::db::InternUnionQuery | ||
266 | hir::db::InternEnumQuery | ||
267 | hir::db::InternConstQuery | ||
268 | hir::db::InternStaticQuery | ||
269 | hir::db::InternTraitQuery | ||
270 | hir::db::InternTypeAliasQuery | ||
271 | hir::db::InternImplQuery | ||
272 | |||
273 | // HirDatabase | ||
274 | hir::db::InternTypeCtorQuery | ||
275 | hir::db::InternTypeParamIdQuery | ||
276 | hir::db::InternChalkImplQuery | ||
277 | hir::db::InternAssocTyValueQuery | ||
278 | ]; | ||
279 | |||
267 | acc.sort_by_key(|it| std::cmp::Reverse(it.1)); | 280 | acc.sort_by_key(|it| std::cmp::Reverse(it.1)); |
268 | acc | 281 | acc |
269 | } | 282 | } |
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 14982919d..846264046 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -273,12 +273,22 @@ pub fn analysis_stats( | |||
273 | println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); | 273 | println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); |
274 | 274 | ||
275 | if memory_usage { | 275 | if memory_usage { |
276 | for (name, bytes) in host.per_query_memory_usage() { | 276 | let mut mem = host.per_query_memory_usage(); |
277 | println!("{:>8} {}", bytes, name) | 277 | |
278 | } | 278 | let before = ra_prof::memory_usage(); |
279 | drop(vfs); | ||
280 | let vfs = before.allocated - ra_prof::memory_usage().allocated; | ||
281 | mem.push(("VFS".into(), vfs)); | ||
282 | |||
279 | let before = ra_prof::memory_usage(); | 283 | let before = ra_prof::memory_usage(); |
280 | drop(host); | 284 | drop(host); |
281 | println!("leftover: {}", before.allocated - ra_prof::memory_usage().allocated) | 285 | mem.push(("Unaccounted".into(), before.allocated - ra_prof::memory_usage().allocated)); |
286 | |||
287 | mem.push(("Remaining".into(), ra_prof::memory_usage().allocated)); | ||
288 | |||
289 | for (name, bytes) in mem { | ||
290 | println!("{:>8} {}", bytes, name) | ||
291 | } | ||
282 | } | 292 | } |
283 | 293 | ||
284 | Ok(()) | 294 | Ok(()) |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 21acfe644..0c7c36716 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -9,7 +9,6 @@ | |||
9 | 9 | ||
10 | use std::{ffi::OsString, path::PathBuf}; | 10 | use std::{ffi::OsString, path::PathBuf}; |
11 | 11 | ||
12 | use crate::diagnostics::DiagnosticsConfig; | ||
13 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
14 | use lsp_types::ClientCapabilities; | 13 | use lsp_types::ClientCapabilities; |
15 | use ra_db::AbsPathBuf; | 14 | use ra_db::AbsPathBuf; |
@@ -17,6 +16,8 @@ use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; | |||
17 | use ra_project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 16 | use ra_project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
18 | use serde::Deserialize; | 17 | use serde::Deserialize; |
19 | 18 | ||
19 | use crate::diagnostics::DiagnosticsConfig; | ||
20 | |||
20 | #[derive(Debug, Clone)] | 21 | #[derive(Debug, Clone)] |
21 | pub struct Config { | 22 | pub struct Config { |
22 | pub client_caps: ClientCapsConfig, | 23 | pub client_caps: ClientCapsConfig, |
@@ -182,8 +183,10 @@ impl Config { | |||
182 | log::info!("Config::update({:#})", value); | 183 | log::info!("Config::update({:#})", value); |
183 | 184 | ||
184 | let client_caps = self.client_caps.clone(); | 185 | let client_caps = self.client_caps.clone(); |
186 | let linked_projects = self.linked_projects.clone(); | ||
185 | *self = Config::new(self.root_path.clone()); | 187 | *self = Config::new(self.root_path.clone()); |
186 | self.client_caps = client_caps; | 188 | self.client_caps = client_caps; |
189 | self.linked_projects = linked_projects; | ||
187 | 190 | ||
188 | set(value, "/withSysroot", &mut self.with_sysroot); | 191 | set(value, "/withSysroot", &mut self.with_sysroot); |
189 | set(value, "/diagnostics/enable", &mut self.publish_diagnostics); | 192 | set(value, "/diagnostics/enable", &mut self.publish_diagnostics); |
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index b763958fe..7816287e4 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc | |||
@@ -109,18 +109,6 @@ Here are some useful self-diagnostic commands: | |||
109 | * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. | 109 | * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. |
110 | * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. | 110 | * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. |
111 | 111 | ||
112 | ==== Special `when` clause context for keybindings. | ||
113 | You may use `inRustProject` context to configure keybindings for rust projects only. For example: | ||
114 | [source,json] | ||
115 | ---- | ||
116 | { | ||
117 | "key": "ctrl+i", | ||
118 | "command": "rust-analyzer.toggleInlayHints", | ||
119 | "when": "inRustProject" | ||
120 | } | ||
121 | ---- | ||
122 | More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here]. | ||
123 | |||
124 | === rust-analyzer Language Server Binary | 112 | === rust-analyzer Language Server Binary |
125 | 113 | ||
126 | Other editors generally require the `rust-analyzer` binary to be in `$PATH`. | 114 | Other editors generally require the `rust-analyzer` binary to be in `$PATH`. |
@@ -337,3 +325,47 @@ They are usually triggered by a shortcut or by clicking a light bulb icon in the | |||
337 | Cursor position or selection is signified by `┃` character. | 325 | Cursor position or selection is signified by `┃` character. |
338 | 326 | ||
339 | include::./generated_assists.adoc[] | 327 | include::./generated_assists.adoc[] |
328 | |||
329 | == Editor Features | ||
330 | === VS Code | ||
331 | ==== Special `when` clause context for keybindings. | ||
332 | You may use `inRustProject` context to configure keybindings for rust projects only. For example: | ||
333 | [source,json] | ||
334 | ---- | ||
335 | { | ||
336 | "key": "ctrl+i", | ||
337 | "command": "rust-analyzer.toggleInlayHints", | ||
338 | "when": "inRustProject" | ||
339 | } | ||
340 | ---- | ||
341 | More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here]. | ||
342 | |||
343 | ==== Setting runnable environment variables | ||
344 | You can use "rust-analyzer.runnableEnv" setting to define runnable environment-specific substitution variables. | ||
345 | The simplest way for all runnables in a bunch: | ||
346 | ```jsonc | ||
347 | "rust-analyzer.runnableEnv": { | ||
348 | "RUN_SLOW_TESTS": "1" | ||
349 | } | ||
350 | ``` | ||
351 | |||
352 | Or it is possible to specify vars more granularly: | ||
353 | ```jsonc | ||
354 | "rust-analyzer.runnableEnv": [ | ||
355 | { | ||
356 | // "mask": null, // null mask means that this rule will be applied for all runnables | ||
357 | env: { | ||
358 | "APP_ID": "1", | ||
359 | "APP_DATA": "asdf" | ||
360 | } | ||
361 | }, | ||
362 | { | ||
363 | "mask": "test_name", | ||
364 | "env": { | ||
365 | "APP_ID": "2", // overwrites only APP_ID | ||
366 | } | ||
367 | } | ||
368 | ] | ||
369 | ``` | ||
370 | |||
371 | You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. | ||
diff --git a/editors/code/package.json b/editors/code/package.json index 938df475f..4b47fc9d3 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -344,6 +344,35 @@ | |||
344 | "default": null, | 344 | "default": null, |
345 | "description": "Custom cargo runner extension ID." | 345 | "description": "Custom cargo runner extension ID." |
346 | }, | 346 | }, |
347 | "rust-analyzer.runnableEnv": { | ||
348 | "anyOf": [ | ||
349 | { | ||
350 | "type": "null" | ||
351 | }, | ||
352 | { | ||
353 | "type": "array", | ||
354 | "items": { | ||
355 | "type": "object", | ||
356 | "properties": { | ||
357 | "mask": { | ||
358 | "type": "string", | ||
359 | "description": "Runnable name mask" | ||
360 | }, | ||
361 | "env": { | ||
362 | "type": "object", | ||
363 | "description": "Variables in form of { \"key\": \"value\"}" | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | }, | ||
368 | { | ||
369 | "type": "object", | ||
370 | "description": "Variables in form of { \"key\": \"value\"}" | ||
371 | } | ||
372 | ], | ||
373 | "default": null, | ||
374 | "description": "Environment variables passed to the runnable launched using `Test ` or `Debug` lens or `rust-analyzer.run` command." | ||
375 | }, | ||
347 | "rust-analyzer.inlayHints.enable": { | 376 | "rust-analyzer.inlayHints.enable": { |
348 | "type": "boolean", | 377 | "type": "boolean", |
349 | "default": true, | 378 | "default": true, |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index fc95a7de6..23975c726 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -5,6 +5,8 @@ export type UpdatesChannel = "stable" | "nightly"; | |||
5 | 5 | ||
6 | export const NIGHTLY_TAG = "nightly"; | 6 | export const NIGHTLY_TAG = "nightly"; |
7 | 7 | ||
8 | export type RunnableEnvCfg = undefined | Record<string, string> | { mask?: string; env: Record<string, string> }[]; | ||
9 | |||
8 | export class Config { | 10 | export class Config { |
9 | readonly extensionId = "matklad.rust-analyzer"; | 11 | readonly extensionId = "matklad.rust-analyzer"; |
10 | 12 | ||
@@ -114,6 +116,10 @@ export class Config { | |||
114 | return this.get<string | undefined>("cargoRunner"); | 116 | return this.get<string | undefined>("cargoRunner"); |
115 | } | 117 | } |
116 | 118 | ||
119 | get runnableEnv() { | ||
120 | return this.get<RunnableEnvCfg>("runnableEnv"); | ||
121 | } | ||
122 | |||
117 | get debug() { | 123 | get debug() { |
118 | // "/rustc/<id>" used by suggestions only. | 124 | // "/rustc/<id>" used by suggestions only. |
119 | const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap"); | 125 | const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap"); |
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 61c12dbe0..bd92c5b6d 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts | |||
@@ -5,9 +5,10 @@ import * as ra from './lsp_ext'; | |||
5 | 5 | ||
6 | import { Cargo } from './toolchain'; | 6 | import { Cargo } from './toolchain'; |
7 | import { Ctx } from "./ctx"; | 7 | import { Ctx } from "./ctx"; |
8 | import { prepareEnv } from "./run"; | ||
8 | 9 | ||
9 | const debugOutput = vscode.window.createOutputChannel("Debug"); | 10 | const debugOutput = vscode.window.createOutputChannel("Debug"); |
10 | type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration; | 11 | type DebugConfigProvider = (config: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration; |
11 | 12 | ||
12 | export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> { | 13 | export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> { |
13 | const scope = ctx.activeRustEditor?.document.uri; | 14 | const scope = ctx.activeRustEditor?.document.uri; |
@@ -92,7 +93,8 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise<v | |||
92 | } | 93 | } |
93 | 94 | ||
94 | const executable = await getDebugExecutable(runnable); | 95 | const executable = await getDebugExecutable(runnable); |
95 | const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), debugOptions.sourceFileMap); | 96 | const env = prepareEnv(runnable, ctx.config.runnableEnv); |
97 | const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), env, debugOptions.sourceFileMap); | ||
96 | if (debugConfig.type in debugOptions.engineSettings) { | 98 | if (debugConfig.type in debugOptions.engineSettings) { |
97 | const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type]; | 99 | const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type]; |
98 | for (var key in settingsMap) { | 100 | for (var key in settingsMap) { |
@@ -121,7 +123,7 @@ async function getDebugExecutable(runnable: ra.Runnable): Promise<string> { | |||
121 | return executable; | 123 | return executable; |
122 | } | 124 | } |
123 | 125 | ||
124 | function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { | 126 | function getLldbDebugConfig(runnable: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { |
125 | return { | 127 | return { |
126 | type: "lldb", | 128 | type: "lldb", |
127 | request: "launch", | 129 | request: "launch", |
@@ -130,11 +132,12 @@ function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFil | |||
130 | args: runnable.args.executableArgs, | 132 | args: runnable.args.executableArgs, |
131 | cwd: runnable.args.workspaceRoot, | 133 | cwd: runnable.args.workspaceRoot, |
132 | sourceMap: sourceFileMap, | 134 | sourceMap: sourceFileMap, |
133 | sourceLanguages: ["rust"] | 135 | sourceLanguages: ["rust"], |
136 | env | ||
134 | }; | 137 | }; |
135 | } | 138 | } |
136 | 139 | ||
137 | function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { | 140 | function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { |
138 | return { | 141 | return { |
139 | type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg", | 142 | type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg", |
140 | request: "launch", | 143 | request: "launch", |
@@ -142,6 +145,7 @@ function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFi | |||
142 | program: executable, | 145 | program: executable, |
143 | args: runnable.args.executableArgs, | 146 | args: runnable.args.executableArgs, |
144 | cwd: runnable.args.workspaceRoot, | 147 | cwd: runnable.args.workspaceRoot, |
145 | sourceFileMap: sourceFileMap, | 148 | sourceFileMap, |
149 | env, | ||
146 | }; | 150 | }; |
147 | } | 151 | } |
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index e1430e31f..de68f27ae 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts | |||
@@ -5,7 +5,7 @@ import * as tasks from './tasks'; | |||
5 | 5 | ||
6 | import { Ctx } from './ctx'; | 6 | import { Ctx } from './ctx'; |
7 | import { makeDebugConfig } from './debug'; | 7 | import { makeDebugConfig } from './debug'; |
8 | import { Config } from './config'; | 8 | import { Config, RunnableEnvCfg } from './config'; |
9 | 9 | ||
10 | const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; | 10 | const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; |
11 | 11 | ||
@@ -96,6 +96,30 @@ export class RunnableQuickPick implements vscode.QuickPickItem { | |||
96 | } | 96 | } |
97 | } | 97 | } |
98 | 98 | ||
99 | export function prepareEnv(runnable: ra.Runnable, runnableEnvCfg: RunnableEnvCfg): Record<string, string> { | ||
100 | const env: Record<string, string> = { "RUST_BACKTRACE": "short" }; | ||
101 | |||
102 | if (runnable.args.expectTest) { | ||
103 | env["UPDATE_EXPECT"] = "1"; | ||
104 | } | ||
105 | |||
106 | Object.assign(env, process.env as { [key: string]: string }); | ||
107 | |||
108 | if (runnableEnvCfg) { | ||
109 | if (Array.isArray(runnableEnvCfg)) { | ||
110 | for (const it of runnableEnvCfg) { | ||
111 | if (!it.mask || new RegExp(it.mask).test(runnable.label)) { | ||
112 | Object.assign(env, it.env); | ||
113 | } | ||
114 | } | ||
115 | } else { | ||
116 | Object.assign(env, runnableEnvCfg); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | return env; | ||
121 | } | ||
122 | |||
99 | export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> { | 123 | export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> { |
100 | if (runnable.kind !== "cargo") { | 124 | if (runnable.kind !== "cargo") { |
101 | // rust-analyzer supports only one kind, "cargo" | 125 | // rust-analyzer supports only one kind, "cargo" |
@@ -108,16 +132,13 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise | |||
108 | if (runnable.args.executableArgs.length > 0) { | 132 | if (runnable.args.executableArgs.length > 0) { |
109 | args.push('--', ...runnable.args.executableArgs); | 133 | args.push('--', ...runnable.args.executableArgs); |
110 | } | 134 | } |
111 | const env: { [key: string]: string } = { "RUST_BACKTRACE": "short" }; | 135 | |
112 | if (runnable.args.expectTest) { | ||
113 | env["UPDATE_EXPECT"] = "1"; | ||
114 | } | ||
115 | const definition: tasks.CargoTaskDefinition = { | 136 | const definition: tasks.CargoTaskDefinition = { |
116 | type: tasks.TASK_TYPE, | 137 | type: tasks.TASK_TYPE, |
117 | command: args[0], // run, test, etc... | 138 | command: args[0], // run, test, etc... |
118 | args: args.slice(1), | 139 | args: args.slice(1), |
119 | cwd: runnable.args.workspaceRoot, | 140 | cwd: runnable.args.workspaceRoot || ".", |
120 | env: Object.assign({}, process.env as { [key: string]: string }, env), | 141 | env: prepareEnv(runnable, config.runnableEnv), |
121 | }; | 142 | }; |
122 | 143 | ||
123 | const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() | 144 | const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() |
diff --git a/editors/code/tests/unit/runnable_env.test.ts b/editors/code/tests/unit/runnable_env.test.ts new file mode 100644 index 000000000..f2f53e91a --- /dev/null +++ b/editors/code/tests/unit/runnable_env.test.ts | |||
@@ -0,0 +1,118 @@ | |||
1 | import * as assert from 'assert'; | ||
2 | import { prepareEnv } from '../../src/run'; | ||
3 | import { RunnableEnvCfg } from '../../src/config'; | ||
4 | import * as ra from '../../src/lsp_ext'; | ||
5 | |||
6 | function makeRunnable(label: string): ra.Runnable { | ||
7 | return { | ||
8 | label, | ||
9 | kind: "cargo", | ||
10 | args: { | ||
11 | cargoArgs: [], | ||
12 | executableArgs: [] | ||
13 | } | ||
14 | }; | ||
15 | } | ||
16 | |||
17 | function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record<string, string> { | ||
18 | const runnable = makeRunnable(runnableName); | ||
19 | return prepareEnv(runnable, config); | ||
20 | } | ||
21 | |||
22 | suite('Runnable env', () => { | ||
23 | test('Global config works', () => { | ||
24 | const binEnv = fakePrepareEnv("run project_name", { "GLOBAL": "g" }); | ||
25 | assert.equal(binEnv["GLOBAL"], "g"); | ||
26 | |||
27 | const testEnv = fakePrepareEnv("test some::mod::test_name", { "GLOBAL": "g" }); | ||
28 | assert.equal(testEnv["GLOBAL"], "g"); | ||
29 | }); | ||
30 | |||
31 | test('null mask works', () => { | ||
32 | const config = [ | ||
33 | { | ||
34 | env: { DATA: "data" } | ||
35 | } | ||
36 | ]; | ||
37 | const binEnv = fakePrepareEnv("run project_name", config); | ||
38 | assert.equal(binEnv["DATA"], "data"); | ||
39 | |||
40 | const testEnv = fakePrepareEnv("test some::mod::test_name", config); | ||
41 | assert.equal(testEnv["DATA"], "data"); | ||
42 | }); | ||
43 | |||
44 | test('order works', () => { | ||
45 | const config = [ | ||
46 | { | ||
47 | env: { DATA: "data" } | ||
48 | }, | ||
49 | { | ||
50 | env: { DATA: "newdata" } | ||
51 | } | ||
52 | ]; | ||
53 | const binEnv = fakePrepareEnv("run project_name", config); | ||
54 | assert.equal(binEnv["DATA"], "newdata"); | ||
55 | |||
56 | const testEnv = fakePrepareEnv("test some::mod::test_name", config); | ||
57 | assert.equal(testEnv["DATA"], "newdata"); | ||
58 | }); | ||
59 | |||
60 | test('mask works', () => { | ||
61 | const config = [ | ||
62 | { | ||
63 | env: { DATA: "data" } | ||
64 | }, | ||
65 | { | ||
66 | mask: "^run", | ||
67 | env: { DATA: "rundata" } | ||
68 | }, | ||
69 | { | ||
70 | mask: "special_test$", | ||
71 | env: { DATA: "special_test" } | ||
72 | } | ||
73 | ]; | ||
74 | const binEnv = fakePrepareEnv("run project_name", config); | ||
75 | assert.equal(binEnv["DATA"], "rundata"); | ||
76 | |||
77 | const testEnv = fakePrepareEnv("test some::mod::test_name", config); | ||
78 | assert.equal(testEnv["DATA"], "data"); | ||
79 | |||
80 | const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config); | ||
81 | assert.equal(specialTestEnv["DATA"], "special_test"); | ||
82 | }); | ||
83 | |||
84 | test('exact test name works', () => { | ||
85 | const config = [ | ||
86 | { | ||
87 | env: { DATA: "data" } | ||
88 | }, | ||
89 | { | ||
90 | mask: "some::mod::test_name", | ||
91 | env: { DATA: "test special" } | ||
92 | } | ||
93 | ]; | ||
94 | const testEnv = fakePrepareEnv("test some::mod::test_name", config); | ||
95 | assert.equal(testEnv["DATA"], "test special"); | ||
96 | |||
97 | const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); | ||
98 | assert.equal(specialTestEnv["DATA"], "data"); | ||
99 | }); | ||
100 | |||
101 | test('test mod name works', () => { | ||
102 | const config = [ | ||
103 | { | ||
104 | env: { DATA: "data" } | ||
105 | }, | ||
106 | { | ||
107 | mask: "some::mod", | ||
108 | env: { DATA: "mod special" } | ||
109 | } | ||
110 | ]; | ||
111 | const testEnv = fakePrepareEnv("test some::mod::test_name", config); | ||
112 | assert.equal(testEnv["DATA"], "mod special"); | ||
113 | |||
114 | const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); | ||
115 | assert.equal(specialTestEnv["DATA"], "mod special"); | ||
116 | }); | ||
117 | |||
118 | }); | ||