aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock59
-rw-r--r--crates/hir/src/code_model.rs6
-rw-r--r--crates/hir_def/src/body.rs4
-rw-r--r--crates/hir_def/src/child_by_source.rs4
-rw-r--r--crates/hir_def/src/import_map.rs95
-rw-r--r--crates/hir_def/src/resolver.rs24
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs3
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs374
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs56
-rw-r--r--crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs2
-rw-r--r--crates/ide_assists/src/handlers/replace_string_with_char.rs136
-rw-r--r--crates/ide_assists/src/lib.rs2
-rw-r--r--crates/ide_assists/src/tests.rs1
-rw-r--r--crates/ide_assists/src/tests/generated.rs31
-rw-r--r--crates/ide_completion/src/item.rs11
-rw-r--r--crates/ide_completion/src/lib.rs2
-rw-r--r--crates/ide_completion/src/test_utils.rs3
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs17
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs38
-rw-r--r--crates/proc_macro_srv/src/dylib.rs6
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/client.rs2
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs141
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs2
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/bin/flags.rs15
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs6
-rw-r--r--crates/rust-analyzer/src/config.rs6
-rw-r--r--crates/rust-analyzer/src/to_proto.rs6
-rw-r--r--docs/user/generated_config.adoc4
-rw-r--r--editors/code/package-lock.json17
-rw-r--r--editors/code/package.json8
-rw-r--r--editors/code/src/config.ts8
-rw-r--r--editors/code/src/main.ts6
-rw-r--r--editors/code/src/net.ts25
-rw-r--r--xtask/Cargo.toml2
-rw-r--r--xtask/src/flags.rs17
38 files changed, 882 insertions, 267 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 39f27098a..7335eb911 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
168 168
169[[package]] 169[[package]]
170name = "chalk-derive" 170name = "chalk-derive"
171version = "0.59.0" 171version = "0.60.0"
172source = "registry+https://github.com/rust-lang/crates.io-index" 172source = "registry+https://github.com/rust-lang/crates.io-index"
173checksum = "4b9000fbcb67353dc8973ab9fd136277d321d85b79bd36b8756bb3ae0979a94a" 173checksum = "ab0f74445d4fbeaf0217bc1d23978cc73b95b28e8a738b81894580dd646822d2"
174dependencies = [ 174dependencies = [
175 "proc-macro2", 175 "proc-macro2",
176 "quote", 176 "quote",
@@ -180,9 +180,9 @@ dependencies = [
180 180
181[[package]] 181[[package]]
182name = "chalk-ir" 182name = "chalk-ir"
183version = "0.59.0" 183version = "0.60.0"
184source = "registry+https://github.com/rust-lang/crates.io-index" 184source = "registry+https://github.com/rust-lang/crates.io-index"
185checksum = "b23528d61b3557c676eccf508fa0771a38453b379f0b780154eaa7f70afe8dfc" 185checksum = "294b1fc6210a5b3bd06c1d01dda48a581e2cafec80b8d659139ce45456644be2"
186dependencies = [ 186dependencies = [
187 "bitflags", 187 "bitflags",
188 "chalk-derive", 188 "chalk-derive",
@@ -191,9 +191,9 @@ dependencies = [
191 191
192[[package]] 192[[package]]
193name = "chalk-recursive" 193name = "chalk-recursive"
194version = "0.59.0" 194version = "0.60.0"
195source = "registry+https://github.com/rust-lang/crates.io-index" 195source = "registry+https://github.com/rust-lang/crates.io-index"
196checksum = "a8bdd37afc666b771de8b4429fe014363d0e74aae5cc26f320f60a3eab34d744" 196checksum = "1b9386936070be4545bfa22b094b7065af79aa2aeaccc945438f1c5ffe74c30a"
197dependencies = [ 197dependencies = [
198 "chalk-derive", 198 "chalk-derive",
199 "chalk-ir", 199 "chalk-ir",
@@ -204,9 +204,9 @@ dependencies = [
204 204
205[[package]] 205[[package]]
206name = "chalk-solve" 206name = "chalk-solve"
207version = "0.59.0" 207version = "0.60.0"
208source = "registry+https://github.com/rust-lang/crates.io-index" 208source = "registry+https://github.com/rust-lang/crates.io-index"
209checksum = "4182c42ca319cb71c89898ebc3d2671d1fa7d928123b171b66f1797a2000b9c8" 209checksum = "7c12a1ec7e850b50a049f27ef9cf5df3056bbd1acbb3eeb44d024e501a641f3a"
210dependencies = [ 210dependencies = [
211 "chalk-derive", 211 "chalk-derive",
212 "chalk-ir", 212 "chalk-ir",
@@ -232,15 +232,6 @@ dependencies = [
232] 232]
233 233
234[[package]] 234[[package]]
235name = "cmake"
236version = "0.1.45"
237source = "registry+https://github.com/rust-lang/crates.io-index"
238checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
239dependencies = [
240 "cc",
241]
242
243[[package]]
244name = "countme" 235name = "countme"
245version = "2.0.4" 236version = "2.0.4"
246source = "registry+https://github.com/rust-lang/crates.io-index" 237source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -687,9 +678,9 @@ dependencies = [
687 678
688[[package]] 679[[package]]
689name = "indexmap" 680name = "indexmap"
690version = "1.6.1" 681version = "1.6.2"
691source = "registry+https://github.com/rust-lang/crates.io-index" 682source = "registry+https://github.com/rust-lang/crates.io-index"
692checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" 683checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
693dependencies = [ 684dependencies = [
694 "autocfg", 685 "autocfg",
695 "hashbrown", 686 "hashbrown",
@@ -805,11 +796,11 @@ dependencies = [
805 796
806[[package]] 797[[package]]
807name = "libmimalloc-sys" 798name = "libmimalloc-sys"
808version = "0.1.20" 799version = "0.1.21"
809source = "registry+https://github.com/rust-lang/crates.io-index" 800source = "registry+https://github.com/rust-lang/crates.io-index"
810checksum = "e58f42b6424a0ed536678c65fd97cd64b4344bcf86251e284f7c0ce9eee40e64" 801checksum = "2396cf99d2f58611cd69f0efeee4af3d2e2c7b61bed433515029163aa567e65c"
811dependencies = [ 802dependencies = [
812 "cmake", 803 "cc",
813] 804]
814 805
815[[package]] 806[[package]]
@@ -911,9 +902,9 @@ dependencies = [
911 902
912[[package]] 903[[package]]
913name = "mimalloc" 904name = "mimalloc"
914version = "0.1.24" 905version = "0.1.25"
915source = "registry+https://github.com/rust-lang/crates.io-index" 906source = "registry+https://github.com/rust-lang/crates.io-index"
916checksum = "757efec188b3d2088949d912e01ea2fe87164ed6376b6c5d7dd4f3ce1668a93d" 907checksum = "1e7c6b11afd1e5e689ac96b6d18b1fc763398fe3d7eed99e8773426bc2033dfb"
917dependencies = [ 908dependencies = [
918 "libmimalloc-sys", 909 "libmimalloc-sys",
919] 910]
@@ -1466,18 +1457,18 @@ dependencies = [
1466 1457
1467[[package]] 1458[[package]]
1468name = "serde" 1459name = "serde"
1469version = "1.0.123" 1460version = "1.0.124"
1470source = "registry+https://github.com/rust-lang/crates.io-index" 1461source = "registry+https://github.com/rust-lang/crates.io-index"
1471checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" 1462checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
1472dependencies = [ 1463dependencies = [
1473 "serde_derive", 1464 "serde_derive",
1474] 1465]
1475 1466
1476[[package]] 1467[[package]]
1477name = "serde_derive" 1468name = "serde_derive"
1478version = "1.0.123" 1469version = "1.0.124"
1479source = "registry+https://github.com/rust-lang/crates.io-index" 1470source = "registry+https://github.com/rust-lang/crates.io-index"
1480checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" 1471checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
1481dependencies = [ 1472dependencies = [
1482 "proc-macro2", 1473 "proc-macro2",
1483 "quote", 1474 "quote",
@@ -1561,9 +1552,9 @@ dependencies = [
1561 1552
1562[[package]] 1553[[package]]
1563name = "syn" 1554name = "syn"
1564version = "1.0.61" 1555version = "1.0.62"
1565source = "registry+https://github.com/rust-lang/crates.io-index" 1556source = "registry+https://github.com/rust-lang/crates.io-index"
1566checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5" 1557checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512"
1567dependencies = [ 1558dependencies = [
1568 "proc-macro2", 1559 "proc-macro2",
1569 "quote", 1560 "quote",
@@ -1919,18 +1910,18 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
1919 1910
1920[[package]] 1911[[package]]
1921name = "xflags" 1912name = "xflags"
1922version = "0.1.4" 1913version = "0.2.1"
1923source = "registry+https://github.com/rust-lang/crates.io-index" 1914source = "registry+https://github.com/rust-lang/crates.io-index"
1924checksum = "222e914b43cec5d7305ac5116d10a14b3a52c50e9062d642c92631f3beabc729" 1915checksum = "59ad6ce6a0b7224130015b4ebac796478ac04e0079f5d222a690efea06a9208a"
1925dependencies = [ 1916dependencies = [
1926 "xflags-macros", 1917 "xflags-macros",
1927] 1918]
1928 1919
1929[[package]] 1920[[package]]
1930name = "xflags-macros" 1921name = "xflags-macros"
1931version = "0.1.4" 1922version = "0.2.1"
1932source = "registry+https://github.com/rust-lang/crates.io-index" 1923source = "registry+https://github.com/rust-lang/crates.io-index"
1933checksum = "52f18f5b4aa7f95e209d5b9274f6164c3938920b4d5c75f97f0dd16daee25ddd" 1924checksum = "c8037d3ca14996158b03c0fa905d0834906ef0fc7044df72c1f5ff690e5e62c9"
1934dependencies = [ 1925dependencies = [
1935 "proc-macro2", 1926 "proc-macro2",
1936] 1927]
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 7656db974..9ee4b3059 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -365,14 +365,14 @@ impl Module {
365 let _p = profile::span("Module::diagnostics").detail(|| { 365 let _p = profile::span("Module::diagnostics").detail(|| {
366 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) 366 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
367 }); 367 });
368 let crate_def_map = self.id.def_map(db.upcast()); 368 let def_map = self.id.def_map(db.upcast());
369 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); 369 def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
370 for decl in self.declarations(db) { 370 for decl in self.declarations(db) {
371 match decl { 371 match decl {
372 crate::ModuleDef::Function(f) => f.diagnostics(db, sink), 372 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
373 crate::ModuleDef::Module(m) => { 373 crate::ModuleDef::Module(m) => {
374 // Only add diagnostics from inline modules 374 // Only add diagnostics from inline modules
375 if crate_def_map[m.id.local_id].origin.is_inline() { 375 if def_map[m.id.local_id].origin.is_inline() {
376 m.diagnostics(db, sink) 376 m.diagnostics(db, sink)
377 } 377 }
378 } 378 }
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index ff4b4a0cf..16e1bac40 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -87,11 +87,11 @@ impl Expander {
87 module: ModuleId, 87 module: ModuleId,
88 ) -> Expander { 88 ) -> Expander {
89 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); 89 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
90 let crate_def_map = module.def_map(db); 90 let def_map = module.def_map(db);
91 let ast_id_map = db.ast_id_map(current_file_id); 91 let ast_id_map = db.ast_id_map(current_file_id);
92 Expander { 92 Expander {
93 cfg_expander, 93 cfg_expander,
94 def_map: crate_def_map, 94 def_map,
95 current_file_id, 95 current_file_id,
96 ast_id_map, 96 ast_id_map,
97 module: module.local_id, 97 module: module.local_id,
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index 65d85c86a..75c2d756b 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -74,8 +74,8 @@ impl ChildBySource for ImplId {
74 74
75impl ChildBySource for ModuleId { 75impl ChildBySource for ModuleId {
76 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 76 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
77 let crate_def_map = self.def_map(db); 77 let def_map = self.def_map(db);
78 let module_data = &crate_def_map[self.local_id]; 78 let module_data = &def_map[self.local_id];
79 module_data.scope.child_by_source(db) 79 module_data.scope.child_by_source(db)
80 } 80 }
81} 81}
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 0a3dc7956..e1c28bc83 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -388,7 +388,7 @@ pub fn search_dependencies<'a>(
388 db: &'a dyn DefDatabase, 388 db: &'a dyn DefDatabase,
389 krate: CrateId, 389 krate: CrateId,
390 query: Query, 390 query: Query,
391) -> Vec<ItemInNs> { 391) -> FxHashSet<ItemInNs> {
392 let _p = profile::span("search_dependencies").detail(|| format!("{:?}", query)); 392 let _p = profile::span("search_dependencies").detail(|| format!("{:?}", query));
393 393
394 let graph = db.crate_graph(); 394 let graph = db.crate_graph();
@@ -403,41 +403,42 @@ pub fn search_dependencies<'a>(
403 } 403 }
404 404
405 let mut stream = op.union(); 405 let mut stream = op.union();
406 let mut res = Vec::new(); 406
407 let mut all_indexed_values = FxHashSet::default();
407 while let Some((_, indexed_values)) = stream.next() { 408 while let Some((_, indexed_values)) = stream.next() {
408 for indexed_value in indexed_values { 409 all_indexed_values.extend(indexed_values.iter().copied());
409 let import_map = &import_maps[indexed_value.index]; 410 }
410 let importables = &import_map.importables[indexed_value.value as usize..];
411 411
412 let common_importable_data = &import_map.map[&importables[0]]; 412 let mut res = FxHashSet::default();
413 if !query.import_matches(common_importable_data, true) { 413 for indexed_value in all_indexed_values {
414 continue; 414 let import_map = &import_maps[indexed_value.index];
415 } 415 let importables = &import_map.importables[indexed_value.value as usize..];
416 416
417 // Path shared by the importable items in this group. 417 let common_importable_data = &import_map.map[&importables[0]];
418 let common_importables_path_fst = fst_path(&common_importable_data.path); 418 if !query.import_matches(common_importable_data, true) {
419 // Add the items from this `ModPath` group. Those are all subsequent items in 419 continue;
420 // `importables` whose paths match `path`. 420 }
421 let iter = importables 421
422 .iter() 422 // Path shared by the importable items in this group.
423 .copied() 423 let common_importables_path_fst = fst_path(&common_importable_data.path);
424 .take_while(|item| { 424 // Add the items from this `ModPath` group. Those are all subsequent items in
425 common_importables_path_fst == fst_path(&import_map.map[item].path) 425 // `importables` whose paths match `path`.
426 }) 426 let iter = importables
427 .filter(|&item| match item_import_kind(item) { 427 .iter()
428 Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), 428 .copied()
429 None => true, 429 .take_while(|item| common_importables_path_fst == fst_path(&import_map.map[item].path))
430 }) 430 .filter(|&item| match item_import_kind(item) {
431 .filter(|item| { 431 Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind),
432 !query.case_sensitive // we've already checked the common importables path case-insensitively 432 None => true,
433 })
434 .filter(|item| {
435 !query.case_sensitive // we've already checked the common importables path case-insensitively
433 || query.import_matches(&import_map.map[item], false) 436 || query.import_matches(&import_map.map[item], false)
434 }); 437 });
435 res.extend(iter); 438 res.extend(iter);
436 439
437 if res.len() >= query.limit { 440 if res.len() >= query.limit {
438 res.truncate(query.limit); 441 return res;
439 return res;
440 }
441 } 442 }
442 } 443 }
443 444
@@ -821,10 +822,10 @@ mod tests {
821 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), 822 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy),
822 expect![[r#" 823 expect![[r#"
823 dep::fmt (t) 824 dep::fmt (t)
825 dep::fmt::Display::format_method (a)
824 dep::fmt::Display (t) 826 dep::fmt::Display (t)
825 dep::fmt::Display::FMT_CONST (a) 827 dep::fmt::Display::FMT_CONST (a)
826 dep::fmt::Display::format_function (a) 828 dep::fmt::Display::format_function (a)
827 dep::fmt::Display::format_method (a)
828 "#]], 829 "#]],
829 ); 830 );
830 } 831 }
@@ -850,9 +851,9 @@ mod tests {
850 "main", 851 "main",
851 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(), 852 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(),
852 expect![[r#" 853 expect![[r#"
854 dep::fmt::Display::format_method (a)
853 dep::fmt::Display::FMT_CONST (a) 855 dep::fmt::Display::FMT_CONST (a)
854 dep::fmt::Display::format_function (a) 856 dep::fmt::Display::format_function (a)
855 dep::fmt::Display::format_method (a)
856 "#]], 857 "#]],
857 ); 858 );
858 859
@@ -911,12 +912,12 @@ mod tests {
911 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), 912 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy),
912 expect![[r#" 913 expect![[r#"
913 dep::fmt (t) 914 dep::fmt (t)
914 dep::Fmt (t) 915 dep::format (f)
915 dep::Fmt (v) 916 dep::Fmt (v)
916 dep::Fmt (m)
917 dep::fmt::Display (t) 917 dep::fmt::Display (t)
918 dep::Fmt (t)
918 dep::fmt::Display::fmt (a) 919 dep::fmt::Display::fmt (a)
919 dep::format (f) 920 dep::Fmt (m)
920 "#]], 921 "#]],
921 ); 922 );
922 923
@@ -926,10 +927,10 @@ mod tests {
926 Query::new("fmt".to_string()).search_mode(SearchMode::Equals), 927 Query::new("fmt".to_string()).search_mode(SearchMode::Equals),
927 expect![[r#" 928 expect![[r#"
928 dep::fmt (t) 929 dep::fmt (t)
929 dep::Fmt (t)
930 dep::Fmt (v) 930 dep::Fmt (v)
931 dep::Fmt (m) 931 dep::Fmt (t)
932 dep::fmt::Display::fmt (a) 932 dep::fmt::Display::fmt (a)
933 dep::Fmt (m)
933 "#]], 934 "#]],
934 ); 935 );
935 936
@@ -939,11 +940,11 @@ mod tests {
939 Query::new("fmt".to_string()).search_mode(SearchMode::Contains), 940 Query::new("fmt".to_string()).search_mode(SearchMode::Contains),
940 expect![[r#" 941 expect![[r#"
941 dep::fmt (t) 942 dep::fmt (t)
942 dep::Fmt (t)
943 dep::Fmt (v) 943 dep::Fmt (v)
944 dep::Fmt (m)
945 dep::fmt::Display (t) 944 dep::fmt::Display (t)
945 dep::Fmt (t)
946 dep::fmt::Display::fmt (a) 946 dep::fmt::Display::fmt (a)
947 dep::Fmt (m)
947 "#]], 948 "#]],
948 ); 949 );
949 } 950 }
@@ -980,11 +981,11 @@ mod tests {
980 Query::new("fmt".to_string()), 981 Query::new("fmt".to_string()),
981 expect![[r#" 982 expect![[r#"
982 dep::fmt (t) 983 dep::fmt (t)
983 dep::Fmt (t)
984 dep::Fmt (v) 984 dep::Fmt (v)
985 dep::Fmt (m)
986 dep::fmt::Display (t) 985 dep::fmt::Display (t)
986 dep::Fmt (t)
987 dep::fmt::Display::fmt (a) 987 dep::fmt::Display::fmt (a)
988 dep::Fmt (m)
988 "#]], 989 "#]],
989 ); 990 );
990 991
@@ -994,10 +995,10 @@ mod tests {
994 Query::new("fmt".to_string()).name_only(), 995 Query::new("fmt".to_string()).name_only(),
995 expect![[r#" 996 expect![[r#"
996 dep::fmt (t) 997 dep::fmt (t)
997 dep::Fmt (t)
998 dep::Fmt (v) 998 dep::Fmt (v)
999 dep::Fmt (m) 999 dep::Fmt (t)
1000 dep::fmt::Display::fmt (a) 1000 dep::fmt::Display::fmt (a)
1001 dep::Fmt (m)
1001 "#]], 1002 "#]],
1002 ); 1003 );
1003 } 1004 }
@@ -1018,9 +1019,9 @@ mod tests {
1018 Query::new("FMT".to_string()), 1019 Query::new("FMT".to_string()),
1019 expect![[r#" 1020 expect![[r#"
1020 dep::fmt (t) 1021 dep::fmt (t)
1022 dep::FMT (v)
1021 dep::fmt (v) 1023 dep::fmt (v)
1022 dep::FMT (t) 1024 dep::FMT (t)
1023 dep::FMT (v)
1024 "#]], 1025 "#]],
1025 ); 1026 );
1026 1027
@@ -1060,6 +1061,8 @@ mod tests {
1060 expect![[r#" 1061 expect![[r#"
1061 dep::fmt (t) 1062 dep::fmt (t)
1062 dep::Fmt (t) 1063 dep::Fmt (t)
1064 dep::Fmt (m)
1065 dep::Fmt (v)
1063 "#]], 1066 "#]],
1064 ); 1067 );
1065 } 1068 }
@@ -1080,9 +1083,9 @@ mod tests {
1080 Query::new("FMT".to_string()), 1083 Query::new("FMT".to_string()),
1081 expect![[r#" 1084 expect![[r#"
1082 dep::fmt (t) 1085 dep::fmt (t)
1086 dep::FMT (v)
1083 dep::fmt (v) 1087 dep::fmt (v)
1084 dep::FMT (t) 1088 dep::FMT (t)
1085 dep::FMT (v)
1086 "#]], 1089 "#]],
1087 ); 1090 );
1088 1091
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index e85f85e49..77ff21739 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -34,7 +34,7 @@ pub struct Resolver {
34// FIXME how to store these best 34// FIXME how to store these best
35#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
36struct ModuleItemMap { 36struct ModuleItemMap {
37 crate_def_map: Arc<DefMap>, 37 def_map: Arc<DefMap>,
38 module_id: LocalModuleId, 38 module_id: LocalModuleId,
39} 39}
40 40
@@ -337,11 +337,11 @@ impl Resolver {
337 let mut traits = FxHashSet::default(); 337 let mut traits = FxHashSet::default();
338 for scope in &self.scopes { 338 for scope in &self.scopes {
339 if let Scope::ModuleScope(m) = scope { 339 if let Scope::ModuleScope(m) = scope {
340 if let Some(prelude) = m.crate_def_map.prelude() { 340 if let Some(prelude) = m.def_map.prelude() {
341 let prelude_def_map = prelude.def_map(db); 341 let prelude_def_map = prelude.def_map(db);
342 traits.extend(prelude_def_map[prelude.local_id].scope.traits()); 342 traits.extend(prelude_def_map[prelude.local_id].scope.traits());
343 } 343 }
344 traits.extend(m.crate_def_map[m.module_id].scope.traits()); 344 traits.extend(m.def_map[m.module_id].scope.traits());
345 } 345 }
346 } 346 }
347 traits 347 traits
@@ -349,7 +349,7 @@ impl Resolver {
349 349
350 fn module_scope(&self) -> Option<(&DefMap, LocalModuleId)> { 350 fn module_scope(&self) -> Option<(&DefMap, LocalModuleId)> {
351 self.scopes.iter().rev().find_map(|scope| match scope { 351 self.scopes.iter().rev().find_map(|scope| match scope {
352 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), 352 Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
353 353
354 _ => None, 354 _ => None,
355 }) 355 })
@@ -413,21 +413,21 @@ impl Scope {
413 // def: m.module.into(), 413 // def: m.module.into(),
414 // }), 414 // }),
415 // ); 415 // );
416 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, def)| { 416 m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
417 f(name.clone(), ScopeDef::PerNs(def)); 417 f(name.clone(), ScopeDef::PerNs(def));
418 }); 418 });
419 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { 419 m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
420 let scope = PerNs::macros(macro_, Visibility::Public); 420 let scope = PerNs::macros(macro_, Visibility::Public);
421 seen.insert((name.clone(), scope)); 421 seen.insert((name.clone(), scope));
422 f(name.clone(), ScopeDef::PerNs(scope)); 422 f(name.clone(), ScopeDef::PerNs(scope));
423 }); 423 });
424 m.crate_def_map.extern_prelude().for_each(|(name, &def)| { 424 m.def_map.extern_prelude().for_each(|(name, &def)| {
425 f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public))); 425 f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public)));
426 }); 426 });
427 BUILTIN_SCOPE.iter().for_each(|(name, &def)| { 427 BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
428 f(name.clone(), ScopeDef::PerNs(def)); 428 f(name.clone(), ScopeDef::PerNs(def));
429 }); 429 });
430 if let Some(prelude) = m.crate_def_map.prelude() { 430 if let Some(prelude) = m.def_map.prelude() {
431 let prelude_def_map = prelude.def_map(db); 431 let prelude_def_map = prelude.def_map(db);
432 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { 432 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| {
433 let seen_tuple = (name.clone(), def); 433 let seen_tuple = (name.clone(), def);
@@ -513,8 +513,8 @@ impl Resolver {
513 self.push_scope(Scope::ImplDefScope(impl_def)) 513 self.push_scope(Scope::ImplDefScope(impl_def))
514 } 514 }
515 515
516 fn push_module_scope(self, crate_def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver { 516 fn push_module_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
517 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) 517 self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id }))
518 } 518 }
519 519
520 fn push_expr_scope( 520 fn push_expr_scope(
@@ -534,7 +534,7 @@ impl ModuleItemMap {
534 path: &ModPath, 534 path: &ModPath,
535 ) -> Option<ResolveValueResult> { 535 ) -> Option<ResolveValueResult> {
536 let (module_def, idx) = 536 let (module_def, idx) =
537 self.crate_def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); 537 self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other);
538 match idx { 538 match idx {
539 None => { 539 None => {
540 let value = to_value_ns(module_def)?; 540 let value = to_value_ns(module_def)?;
@@ -564,7 +564,7 @@ impl ModuleItemMap {
564 path: &ModPath, 564 path: &ModPath,
565 ) -> Option<(TypeNs, Option<usize>)> { 565 ) -> Option<(TypeNs, Option<usize>)> {
566 let (module_def, idx) = 566 let (module_def, idx) =
567 self.crate_def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); 567 self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other);
568 let res = to_type_ns(module_def)?; 568 let res = to_type_ns(module_def)?;
569 Some((res, idx)) 569 Some((res, idx))
570 } 570 }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index d1302d749..1127eef05 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -17,9 +17,9 @@ ena = "0.14.0"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19scoped-tls = "1" 19scoped-tls = "1"
20chalk-solve = { version = "0.59", default-features = false } 20chalk-solve = { version = "0.60", default-features = false }
21chalk-ir = "0.59" 21chalk-ir = "0.60"
22chalk-recursive = "0.59" 22chalk-recursive = "0.60"
23la-arena = { version = "0.2.0", path = "../../lib/arena" } 23la-arena = { version = "0.2.0", path = "../../lib/arena" }
24 24
25stdx = { path = "../stdx", version = "0.0.0" } 25stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index dc38f90e9..1422224ac 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -99,8 +99,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
99 format!("Import `{}`", &import), 99 format!("Import `{}`", &import),
100 range, 100 range,
101 |builder| { 101 |builder| {
102 let rewriter = 102 let rewriter = insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use);
103 insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use.merge);
104 builder.rewrite(rewriter); 103 builder.rewrite(rewriter);
105 }, 104 },
106 ); 105 );
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 5c7678b53..4f0422e96 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -154,7 +154,7 @@ fn insert_import(
154 mod_path.pop_segment(); 154 mod_path.pop_segment();
155 mod_path.push_segment(variant_hir_name.clone()); 155 mod_path.push_segment(variant_hir_name.clone());
156 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?; 156 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
157 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); 157 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use);
158 } 158 }
159 Some(()) 159 Some(())
160} 160}
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
new file mode 100644
index 000000000..fa1254579
--- /dev/null
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -0,0 +1,374 @@
1use crate::{
2 assist_context::{AssistContext, Assists},
3 AssistId,
4};
5use ide_db::helpers::FamousDefs;
6use syntax::{
7 ast::{self, Impl, NameOwner},
8 AstNode,
9};
10use test_utils::mark;
11
12// Assist: generate_default_from_new
13//
14// Generates default implementation from new method.
15//
16// ```
17// struct Example { _inner: () }
18//
19// impl Example {
20// pub fn n$0ew() -> Self {
21// Self { _inner: () }
22// }
23// }
24// ```
25// ->
26// ```
27// struct Example { _inner: () }
28//
29// impl Example {
30// pub fn new() -> Self {
31// Self { _inner: () }
32// }
33// }
34//
35// impl Default for Example {
36// fn default() -> Self {
37// Self::new()
38// }
39// }
40// ```
41pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
42 let fn_node = ctx.find_node_at_offset::<ast::Fn>()?;
43 let fn_name = fn_node.name()?;
44
45 if fn_name.text() != "new" {
46 mark::hit!(other_function_than_new);
47 return None;
48 }
49
50 if fn_node.param_list()?.params().next().is_some() {
51 mark::hit!(new_function_with_parameters);
52 return None;
53 }
54
55 let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?;
56 if is_default_implemented(ctx, &impl_) {
57 mark::hit!(default_block_is_already_present);
58 mark::hit!(struct_in_module_with_default);
59 return None;
60 }
61
62 let insert_location = impl_.syntax().text_range();
63
64 acc.add(
65 AssistId("generate_default_from_new", crate::AssistKind::Generate),
66 "Generate a Default impl from a new fn",
67 insert_location,
68 move |builder| {
69 let code = default_fn_node_for_new(impl_);
70 builder.insert(insert_location.end(), code);
71 },
72 )
73}
74
75fn default_fn_node_for_new(impl_: Impl) -> String {
76 format!(
77 "
78
79impl Default for {} {{
80 fn default() -> Self {{
81 Self::new()
82 }}
83}}",
84 impl_.self_ty().unwrap().syntax().text()
85 )
86}
87
88fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
89 let db = ctx.sema.db;
90 let impl_ = ctx.sema.to_def(impl_);
91 let impl_def = match impl_ {
92 Some(value) => value,
93 None => return false,
94 };
95
96 let ty = impl_def.target_ty(db);
97 let krate = impl_def.module(db).krate();
98 let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default();
99 let default_trait = match default {
100 Some(value) => value,
101 None => return false,
102 };
103
104 ty.impls_trait(db, default_trait, &[])
105}
106
107#[cfg(test)]
108mod tests {
109 use ide_db::helpers::FamousDefs;
110
111 use crate::tests::{check_assist, check_assist_not_applicable};
112
113 use super::*;
114
115 #[test]
116 fn generate_default() {
117 check_pass(
118 r#"
119struct Example { _inner: () }
120
121impl Example {
122 pub fn ne$0w() -> Self {
123 Self { _inner: () }
124 }
125}
126
127fn main() {}
128"#,
129 r#"
130struct Example { _inner: () }
131
132impl Example {
133 pub fn new() -> Self {
134 Self { _inner: () }
135 }
136}
137
138impl Default for Example {
139 fn default() -> Self {
140 Self::new()
141 }
142}
143
144fn main() {}
145"#,
146 );
147 }
148
149 #[test]
150 fn generate_default2() {
151 check_pass(
152 r#"
153struct Test { value: u32 }
154
155impl Test {
156 pub fn ne$0w() -> Self {
157 Self { value: 0 }
158 }
159}
160"#,
161 r#"
162struct Test { value: u32 }
163
164impl Test {
165 pub fn new() -> Self {
166 Self { value: 0 }
167 }
168}
169
170impl Default for Test {
171 fn default() -> Self {
172 Self::new()
173 }
174}
175"#,
176 );
177 }
178
179 #[test]
180 fn new_function_with_parameters() {
181 mark::check!(new_function_with_parameters);
182 check_not_applicable(
183 r#"
184struct Example { _inner: () }
185
186impl Example {
187 pub fn $0new(value: ()) -> Self {
188 Self { _inner: value }
189 }
190}
191"#,
192 );
193 }
194
195 #[test]
196 fn other_function_than_new() {
197 mark::check!(other_function_than_new);
198 check_not_applicable(
199 r#"
200struct Example { _inner: () }
201
202impl Example {
203 pub fn a$0dd() -> Self {
204 Self { _inner: () }
205 }
206}
207
208"#,
209 );
210 }
211
212 #[test]
213 fn default_block_is_already_present() {
214 mark::check!(default_block_is_already_present);
215 check_not_applicable(
216 r#"
217struct Example { _inner: () }
218
219impl Example {
220 pub fn n$0ew() -> Self {
221 Self { _inner: () }
222 }
223}
224
225impl Default for Example {
226 fn default() -> Self {
227 Self::new()
228 }
229}
230"#,
231 );
232 }
233
234 #[test]
235 fn standalone_new_function() {
236 check_not_applicable(
237 r#"
238fn n$0ew() -> u32 {
239 0
240}
241"#,
242 );
243 }
244
245 #[test]
246 fn multiple_struct_blocks() {
247 check_pass(
248 r#"
249struct Example { _inner: () }
250struct Test { value: u32 }
251
252impl Example {
253 pub fn new$0() -> Self {
254 Self { _inner: () }
255 }
256}
257"#,
258 r#"
259struct Example { _inner: () }
260struct Test { value: u32 }
261
262impl Example {
263 pub fn new() -> Self {
264 Self { _inner: () }
265 }
266}
267
268impl Default for Example {
269 fn default() -> Self {
270 Self::new()
271 }
272}
273"#,
274 );
275 }
276
277 #[test]
278 fn when_struct_is_after_impl() {
279 check_pass(
280 r#"
281impl Example {
282 pub fn $0new() -> Self {
283 Self { _inner: () }
284 }
285}
286
287struct Example { _inner: () }
288"#,
289 r#"
290impl Example {
291 pub fn new() -> Self {
292 Self { _inner: () }
293 }
294}
295
296impl Default for Example {
297 fn default() -> Self {
298 Self::new()
299 }
300}
301
302struct Example { _inner: () }
303"#,
304 );
305 }
306
307 #[test]
308 fn struct_in_module() {
309 check_pass(
310 r#"
311mod test {
312 struct Example { _inner: () }
313
314 impl Example {
315 pub fn n$0ew() -> Self {
316 Self { _inner: () }
317 }
318 }
319}
320"#,
321 r#"
322mod test {
323 struct Example { _inner: () }
324
325 impl Example {
326 pub fn new() -> Self {
327 Self { _inner: () }
328 }
329 }
330
331impl Default for Example {
332 fn default() -> Self {
333 Self::new()
334 }
335}
336}
337"#,
338 );
339 }
340
341 #[test]
342 fn struct_in_module_with_default() {
343 mark::check!(struct_in_module_with_default);
344 check_not_applicable(
345 r#"
346mod test {
347 struct Example { _inner: () }
348
349 impl Example {
350 pub fn n$0ew() -> Self {
351 Self { _inner: () }
352 }
353 }
354
355 impl Default for Example {
356 fn default() -> Self {
357 Self::new()
358 }
359 }
360}
361"#,
362 );
363 }
364
365 fn check_pass(before: &str, after: &str) {
366 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
367 check_assist(generate_default_from_new, before, after);
368 }
369
370 fn check_not_applicable(before: &str) {
371 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
372 check_assist_not_applicable(generate_default_from_new, before);
373 }
374}
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 959824981..3870b7e75 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -1,6 +1,7 @@
1use hir::HirDisplay; 1use hir::HirDisplay;
2use ide_db::{base_db::FileId, helpers::SnippetCap}; 2use ide_db::{base_db::FileId, helpers::SnippetCap};
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4use stdx::to_lower_snake_case;
4use syntax::{ 5use syntax::{
5 ast::{ 6 ast::{
6 self, 7 self,
@@ -257,14 +258,15 @@ fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
257fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> { 258fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
258 match fn_arg { 259 match fn_arg {
259 ast::Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?), 260 ast::Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?),
260 _ => Some( 261 _ => {
261 fn_arg 262 let s = fn_arg
262 .syntax() 263 .syntax()
263 .descendants() 264 .descendants()
264 .filter(|d| ast::NameRef::can_cast(d.kind())) 265 .filter(|d| ast::NameRef::can_cast(d.kind()))
265 .last()? 266 .last()?
266 .to_string(), 267 .to_string();
267 ), 268 Some(to_lower_snake_case(&s))
269 }
268 } 270 }
269} 271}
270 272
@@ -448,6 +450,52 @@ mod baz {
448 } 450 }
449 451
450 #[test] 452 #[test]
453 fn add_function_with_upper_camel_case_arg() {
454 check_assist(
455 generate_function,
456 r"
457struct BazBaz;
458fn foo() {
459 bar$0(BazBaz);
460}
461",
462 r"
463struct BazBaz;
464fn foo() {
465 bar(BazBaz);
466}
467
468fn bar(baz_baz: BazBaz) ${0:-> ()} {
469 todo!()
470}
471",
472 );
473 }
474
475 #[test]
476 fn add_function_with_upper_camel_case_arg_as_cast() {
477 check_assist(
478 generate_function,
479 r"
480struct BazBaz;
481fn foo() {
482 bar$0(&BazBaz as *const BazBaz);
483}
484",
485 r"
486struct BazBaz;
487fn foo() {
488 bar(&BazBaz as *const BazBaz);
489}
490
491fn bar(baz_baz: *const BazBaz) ${0:-> ()} {
492 todo!()
493}
494",
495 );
496 }
497
498 #[test]
451 fn add_function_with_function_call_arg() { 499 fn add_function_with_function_call_arg() {
452 check_assist( 500 check_assist(
453 generate_function, 501 generate_function,
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index f3bc6cf39..55481af34 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -44,7 +44,7 @@ pub(crate) fn replace_qualified_name_with_use(
44 let mut rewriter = SyntaxRewriter::default(); 44 let mut rewriter = SyntaxRewriter::default();
45 shorten_paths(&mut rewriter, syntax.clone(), &path); 45 shorten_paths(&mut rewriter, syntax.clone(), &path);
46 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { 46 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) {
47 rewriter += insert_use(import_scope, path, ctx.config.insert_use.merge); 47 rewriter += insert_use(import_scope, path, ctx.config.insert_use);
48 builder.rewrite(rewriter); 48 builder.rewrite(rewriter);
49 } 49 }
50 }, 50 },
diff --git a/crates/ide_assists/src/handlers/replace_string_with_char.rs b/crates/ide_assists/src/handlers/replace_string_with_char.rs
index 317318c24..634b9c0b7 100644
--- a/crates/ide_assists/src/handlers/replace_string_with_char.rs
+++ b/crates/ide_assists/src/handlers/replace_string_with_char.rs
@@ -25,13 +25,16 @@ pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -
25 if value.chars().take(2).count() != 1 { 25 if value.chars().take(2).count() != 1 {
26 return None; 26 return None;
27 } 27 }
28 let quote_offets = token.quote_offsets()?;
28 29
29 acc.add( 30 acc.add(
30 AssistId("replace_string_with_char", AssistKind::RefactorRewrite), 31 AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
31 "Replace string with char", 32 "Replace string with char",
32 target, 33 target,
33 |edit| { 34 |edit| {
34 edit.replace(token.syntax().text_range(), format!("'{}'", value)); 35 let (left, right) = quote_offets.quotes;
36 edit.replace(left, String::from('\''));
37 edit.replace(right, String::from('\''));
35 }, 38 },
36 ) 39 )
37} 40}
@@ -47,10 +50,10 @@ mod tests {
47 check_assist_target( 50 check_assist_target(
48 replace_string_with_char, 51 replace_string_with_char,
49 r#" 52 r#"
50 fn f() { 53fn f() {
51 let s = "$0c"; 54 let s = "$0c";
52 } 55}
53 "#, 56"#,
54 r#""c""#, 57 r#""c""#,
55 ); 58 );
56 } 59 }
@@ -60,15 +63,15 @@ mod tests {
60 check_assist( 63 check_assist(
61 replace_string_with_char, 64 replace_string_with_char,
62 r#" 65 r#"
63 fn f() { 66fn f() {
64 let s = "$0c"; 67 let s = "$0c";
65 } 68}
66 "#, 69"#,
67 r##" 70 r##"
68 fn f() { 71fn f() {
69 let s = 'c'; 72 let s = 'c';
70 } 73}
71 "##, 74"##,
72 ) 75 )
73 } 76 }
74 77
@@ -77,15 +80,15 @@ mod tests {
77 check_assist( 80 check_assist(
78 replace_string_with_char, 81 replace_string_with_char,
79 r#" 82 r#"
80 fn f() { 83fn f() {
81 let s = "$0😀"; 84 let s = "$0😀";
82 } 85}
83 "#, 86"#,
84 r##" 87 r##"
85 fn f() { 88fn f() {
86 let s = '😀'; 89 let s = '😀';
87 } 90}
88 "##, 91"##,
89 ) 92 )
90 } 93 }
91 94
@@ -94,10 +97,10 @@ mod tests {
94 check_assist_not_applicable( 97 check_assist_not_applicable(
95 replace_string_with_char, 98 replace_string_with_char,
96 r#" 99 r#"
97 fn f() { 100fn f() {
98 let s = "$0test"; 101 let s = "$0test";
99 } 102}
100 "#, 103"#,
101 ) 104 )
102 } 105 }
103 106
@@ -106,15 +109,15 @@ mod tests {
106 check_assist( 109 check_assist(
107 replace_string_with_char, 110 replace_string_with_char,
108 r#" 111 r#"
109 fn f() { 112fn f() {
110 format!($0"x", 92) 113 format!($0"x", 92)
111 } 114}
112 "#, 115"#,
113 r##" 116 r##"
114 fn f() { 117fn f() {
115 format!('x', 92) 118 format!('x', 92)
116 } 119}
117 "##, 120"##,
118 ) 121 )
119 } 122 }
120 123
@@ -123,15 +126,66 @@ mod tests {
123 check_assist( 126 check_assist(
124 replace_string_with_char, 127 replace_string_with_char,
125 r#" 128 r#"
126 fn f() { 129fn f() {
127 find($0"x"); 130 find($0"x");
128 } 131}
129 "#, 132"#,
130 r##" 133 r##"
131 fn f() { 134fn f() {
132 find('x'); 135 find('x');
133 } 136}
134 "##, 137"##,
138 )
139 }
140
141 #[test]
142 fn replace_string_with_char_newline() {
143 check_assist(
144 replace_string_with_char,
145 r#"
146fn f() {
147 find($0"\n");
148}
149"#,
150 r##"
151fn f() {
152 find('\n');
153}
154"##,
155 )
156 }
157
158 #[test]
159 fn replace_string_with_char_unicode_escape() {
160 check_assist(
161 replace_string_with_char,
162 r#"
163fn f() {
164 find($0"\u{7FFF}");
165}
166"#,
167 r##"
168fn f() {
169 find('\u{7FFF}');
170}
171"##,
172 )
173 }
174
175 #[test]
176 fn replace_raw_string_with_char() {
177 check_assist(
178 replace_string_with_char,
179 r##"
180fn f() {
181 $0r#"X"#
182}
183"##,
184 r##"
185fn f() {
186 'X'
187}
188"##,
135 ) 189 )
136 } 190 }
137} 191}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 9c8148462..ea62d5f5d 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -127,6 +127,7 @@ mod handlers {
127 mod flip_comma; 127 mod flip_comma;
128 mod flip_trait_bound; 128 mod flip_trait_bound;
129 mod generate_default_from_enum_variant; 129 mod generate_default_from_enum_variant;
130 mod generate_default_from_new;
130 mod generate_derive; 131 mod generate_derive;
131 mod generate_enum_is_method; 132 mod generate_enum_is_method;
132 mod generate_enum_projection_method; 133 mod generate_enum_projection_method;
@@ -189,6 +190,7 @@ mod handlers {
189 flip_comma::flip_comma, 190 flip_comma::flip_comma,
190 flip_trait_bound::flip_trait_bound, 191 flip_trait_bound::flip_trait_bound,
191 generate_default_from_enum_variant::generate_default_from_enum_variant, 192 generate_default_from_enum_variant::generate_default_from_enum_variant,
193 generate_default_from_new::generate_default_from_new,
192 generate_derive::generate_derive, 194 generate_derive::generate_derive,
193 generate_enum_is_method::generate_enum_is_method, 195 generate_enum_is_method::generate_enum_is_method,
194 generate_enum_projection_method::generate_enum_as_method, 196 generate_enum_projection_method::generate_enum_as_method,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index b7f616760..a7a923beb 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -23,6 +23,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
23 insert_use: InsertUseConfig { 23 insert_use: InsertUseConfig {
24 merge: Some(MergeBehavior::Full), 24 merge: Some(MergeBehavior::Full),
25 prefix_kind: hir::PrefixKind::Plain, 25 prefix_kind: hir::PrefixKind::Plain,
26 group: true,
26 }, 27 },
27}; 28};
28 29
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 4f007aa48..304b5798f 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -440,6 +440,37 @@ impl Default for Version {
440} 440}
441 441
442#[test] 442#[test]
443fn doctest_generate_default_from_new() {
444 check_doc_test(
445 "generate_default_from_new",
446 r#####"
447struct Example { _inner: () }
448
449impl Example {
450 pub fn n$0ew() -> Self {
451 Self { _inner: () }
452 }
453}
454"#####,
455 r#####"
456struct Example { _inner: () }
457
458impl Example {
459 pub fn new() -> Self {
460 Self { _inner: () }
461 }
462}
463
464impl Default for Example {
465 fn default() -> Self {
466 Self::new()
467 }
468}
469"#####,
470 )
471}
472
473#[test]
443fn doctest_generate_derive() { 474fn doctest_generate_derive() {
444 check_doc_test( 475 check_doc_test(
445 "generate_derive", 476 "generate_derive",
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 884711f11..9b2435c4b 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -5,7 +5,7 @@ use std::fmt;
5use hir::{Documentation, ModPath, Mutability}; 5use hir::{Documentation, ModPath, Mutability};
6use ide_db::{ 6use ide_db::{
7 helpers::{ 7 helpers::{
8 insert_use::{self, ImportScope, MergeBehavior}, 8 insert_use::{self, ImportScope, InsertUseConfig},
9 mod_path_to_ast, SnippetCap, 9 mod_path_to_ast, SnippetCap,
10 }, 10 },
11 SymbolKind, 11 SymbolKind,
@@ -280,14 +280,11 @@ pub struct ImportEdit {
280impl ImportEdit { 280impl ImportEdit {
281 /// Attempts to insert the import to the given scope, producing a text edit. 281 /// Attempts to insert the import to the given scope, producing a text edit.
282 /// May return no edit in edge cases, such as scope already containing the import. 282 /// May return no edit in edge cases, such as scope already containing the import.
283 pub fn to_text_edit(&self, merge_behavior: Option<MergeBehavior>) -> Option<TextEdit> { 283 pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> {
284 let _p = profile::span("ImportEdit::to_text_edit"); 284 let _p = profile::span("ImportEdit::to_text_edit");
285 285
286 let rewriter = insert_use::insert_use( 286 let rewriter =
287 &self.import_scope, 287 insert_use::insert_use(&self.import_scope, mod_path_to_ast(&self.import_path), cfg);
288 mod_path_to_ast(&self.import_path),
289 merge_behavior,
290 );
291 let old_ast = rewriter.rewrite_root()?; 288 let old_ast = rewriter.rewrite_root()?;
292 let mut import_insert = TextEdit::builder(); 289 let mut import_insert = TextEdit::builder();
293 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert); 290 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 76f31de9e..b0b809791 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -156,7 +156,7 @@ pub fn resolve_completion_edits(
156 .find(|mod_path| mod_path.to_string() == full_import_path)?; 156 .find(|mod_path| mod_path.to_string() == full_import_path)?;
157 157
158 ImportEdit { import_path, import_scope, import_for_trait_assoc_item } 158 ImportEdit { import_path, import_scope, import_for_trait_assoc_item }
159 .to_text_edit(config.insert_use.merge) 159 .to_text_edit(config.insert_use)
160 .map(|edit| vec![edit]) 160 .map(|edit| vec![edit])
161} 161}
162 162
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs
index baff83305..9da844031 100644
--- a/crates/ide_completion/src/test_utils.rs
+++ b/crates/ide_completion/src/test_utils.rs
@@ -25,6 +25,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
25 insert_use: InsertUseConfig { 25 insert_use: InsertUseConfig {
26 merge: Some(MergeBehavior::Full), 26 merge: Some(MergeBehavior::Full),
27 prefix_kind: PrefixKind::Plain, 27 prefix_kind: PrefixKind::Plain,
28 group: true,
28 }, 29 },
29}; 30};
30 31
@@ -119,7 +120,7 @@ pub(crate) fn check_edit_with_config(
119 120
120 let mut combined_edit = completion.text_edit().to_owned(); 121 let mut combined_edit = completion.text_edit().to_owned();
121 if let Some(import_text_edit) = 122 if let Some(import_text_edit) =
122 completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use.merge)) 123 completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use))
123 { 124 {
124 combined_edit.union(import_text_edit).expect( 125 combined_edit.union(import_text_edit).expect(
125 "Failed to apply completion resolve changes: change ranges overlap, but should not", 126 "Failed to apply completion resolve changes: change ranges overlap, but should not",
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index fd4035198..f52aee344 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -19,6 +19,7 @@ use test_utils::mark;
19pub struct InsertUseConfig { 19pub struct InsertUseConfig {
20 pub merge: Option<MergeBehavior>, 20 pub merge: Option<MergeBehavior>,
21 pub prefix_kind: hir::PrefixKind, 21 pub prefix_kind: hir::PrefixKind,
22 pub group: bool,
22} 23}
23 24
24#[derive(Debug, Clone)] 25#[derive(Debug, Clone)]
@@ -99,13 +100,13 @@ fn is_inner_comment(token: SyntaxToken) -> bool {
99pub fn insert_use<'a>( 100pub fn insert_use<'a>(
100 scope: &ImportScope, 101 scope: &ImportScope,
101 path: ast::Path, 102 path: ast::Path,
102 merge: Option<MergeBehavior>, 103 cfg: InsertUseConfig,
103) -> SyntaxRewriter<'a> { 104) -> SyntaxRewriter<'a> {
104 let _p = profile::span("insert_use"); 105 let _p = profile::span("insert_use");
105 let mut rewriter = SyntaxRewriter::default(); 106 let mut rewriter = SyntaxRewriter::default();
106 let use_item = make::use_(None, make::use_tree(path.clone(), None, None, false)); 107 let use_item = make::use_(None, make::use_tree(path.clone(), None, None, false));
107 // merge into existing imports if possible 108 // merge into existing imports if possible
108 if let Some(mb) = merge { 109 if let Some(mb) = cfg.merge {
109 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { 110 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) {
110 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { 111 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
111 rewriter.replace(existing_use.syntax(), merged.syntax()); 112 rewriter.replace(existing_use.syntax(), merged.syntax());
@@ -116,7 +117,7 @@ pub fn insert_use<'a>(
116 117
117 // either we weren't allowed to merge or there is no import that fits the merge conditions 118 // either we weren't allowed to merge or there is no import that fits the merge conditions
118 // so look for the place we have to insert to 119 // so look for the place we have to insert to
119 let (insert_position, add_blank) = find_insert_position(scope, path); 120 let (insert_position, add_blank) = find_insert_position(scope, path, cfg.group);
120 121
121 let indent = if let ident_level @ 1..=usize::MAX = scope.indent_level().0 as usize { 122 let indent = if let ident_level @ 1..=usize::MAX = scope.indent_level().0 as usize {
122 Some(make::tokens::whitespace(&" ".repeat(4 * ident_level)).into()) 123 Some(make::tokens::whitespace(&" ".repeat(4 * ident_level)).into())
@@ -538,6 +539,7 @@ impl AddBlankLine {
538fn find_insert_position( 539fn find_insert_position(
539 scope: &ImportScope, 540 scope: &ImportScope,
540 insert_path: ast::Path, 541 insert_path: ast::Path,
542 group_imports: bool,
541) -> (InsertPosition<SyntaxElement>, AddBlankLine) { 543) -> (InsertPosition<SyntaxElement>, AddBlankLine) {
542 let group = ImportGroup::new(&insert_path); 544 let group = ImportGroup::new(&insert_path);
543 let path_node_iter = scope 545 let path_node_iter = scope
@@ -550,6 +552,14 @@ fn find_insert_position(
550 let has_tl = tree.use_tree_list().is_some(); 552 let has_tl = tree.use_tree_list().is_some();
551 Some((path, has_tl, node)) 553 Some((path, has_tl, node))
552 }); 554 });
555
556 if !group_imports {
557 if let Some((_, _, node)) = path_node_iter.last() {
558 return (InsertPosition::After(node.into()), AddBlankLine::Before);
559 }
560 return (InsertPosition::First, AddBlankLine::AfterTwice);
561 }
562
553 // Iterator that discards anything thats not in the required grouping 563 // Iterator that discards anything thats not in the required grouping
554 // This implementation allows the user to rearrange their import groups as this only takes the first group that fits 564 // This implementation allows the user to rearrange their import groups as this only takes the first group that fits
555 let group_iter = path_node_iter 565 let group_iter = path_node_iter
@@ -565,6 +575,7 @@ fn find_insert_position(
565 use_tree_path_cmp(&insert_path, false, path, has_tl) != Ordering::Greater 575 use_tree_path_cmp(&insert_path, false, path, has_tl) != Ordering::Greater
566 }, 576 },
567 ); 577 );
578
568 match post_insert { 579 match post_insert {
569 // insert our import before that element 580 // insert our import before that element
570 Some((.., node)) => (InsertPosition::Before(node.into()), AddBlankLine::After), 581 Some((.., node)) => (InsertPosition::Before(node.into()), AddBlankLine::After),
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 4bbe66f1f..67d0d6fb6 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -1,8 +1,32 @@
1use super::*; 1use super::*;
2 2
3use hir::PrefixKind;
3use test_utils::assert_eq_text; 4use test_utils::assert_eq_text;
4 5
5#[test] 6#[test]
7fn insert_not_group() {
8 check(
9 "use external_crate2::bar::A",
10 r"
11use std::bar::B;
12use external_crate::bar::A;
13use crate::bar::A;
14use self::bar::A;
15use super::bar::A;",
16 r"
17use std::bar::B;
18use external_crate::bar::A;
19use crate::bar::A;
20use self::bar::A;
21use super::bar::A;
22use external_crate2::bar::A;",
23 None,
24 false,
25 false,
26 );
27}
28
29#[test]
6fn insert_existing() { 30fn insert_existing() {
7 check_full("std::fs", "use std::fs;", "use std::fs;") 31 check_full("std::fs", "use std::fs;", "use std::fs;")
8} 32}
@@ -240,6 +264,7 @@ fn insert_empty_module() {
240}", 264}",
241 None, 265 None,
242 true, 266 true,
267 true,
243 ) 268 )
244} 269}
245 270
@@ -584,6 +609,7 @@ fn check(
584 ra_fixture_after: &str, 609 ra_fixture_after: &str,
585 mb: Option<MergeBehavior>, 610 mb: Option<MergeBehavior>,
586 module: bool, 611 module: bool,
612 group: bool,
587) { 613) {
588 let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(); 614 let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
589 if module { 615 if module {
@@ -597,21 +623,25 @@ fn check(
597 .find_map(ast::Path::cast) 623 .find_map(ast::Path::cast)
598 .unwrap(); 624 .unwrap();
599 625
600 let rewriter = insert_use(&file, path, mb); 626 let rewriter = insert_use(
627 &file,
628 path,
629 InsertUseConfig { merge: mb, prefix_kind: PrefixKind::Plain, group },
630 );
601 let result = rewriter.rewrite(file.as_syntax_node()).to_string(); 631 let result = rewriter.rewrite(file.as_syntax_node()).to_string();
602 assert_eq_text!(ra_fixture_after, &result); 632 assert_eq_text!(ra_fixture_after, &result);
603} 633}
604 634
605fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 635fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
606 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Full), false) 636 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Full), false, true)
607} 637}
608 638
609fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 639fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
610 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Last), false) 640 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Last), false, true)
611} 641}
612 642
613fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 643fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
614 check(path, ra_fixture_before, ra_fixture_after, None, false) 644 check(path, ra_fixture_before, ra_fixture_after, None, false, true)
615} 645}
616 646
617fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { 647fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) {
diff --git a/crates/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs
index 28a6ee547..baf10fea9 100644
--- a/crates/proc_macro_srv/src/dylib.rs
+++ b/crates/proc_macro_srv/src/dylib.rs
@@ -138,7 +138,7 @@ impl Expander {
138 parsed_body, 138 parsed_body,
139 false, 139 false,
140 ); 140 );
141 return res.map(|it| it.subtree); 141 return res.map(|it| it.into_subtree());
142 } 142 }
143 bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { 143 bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
144 let res = client.run( 144 let res = client.run(
@@ -147,7 +147,7 @@ impl Expander {
147 parsed_body, 147 parsed_body,
148 false, 148 false,
149 ); 149 );
150 return res.map(|it| it.subtree); 150 return res.map(|it| it.into_subtree());
151 } 151 }
152 bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { 152 bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
153 let res = client.run( 153 let res = client.run(
@@ -157,7 +157,7 @@ impl Expander {
157 parsed_body, 157 parsed_body,
158 false, 158 false,
159 ); 159 );
160 return res.map(|it| it.subtree); 160 return res.map(|it| it.into_subtree());
161 } 161 }
162 _ => continue, 162 _ => continue,
163 } 163 }
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs b/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
index ca6749b9b..b036d4e20 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
+++ b/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
@@ -238,7 +238,7 @@ macro_rules! define_client_side {
238 $(impl $name { 238 $(impl $name {
239 #[allow(unused)] 239 #[allow(unused)]
240 $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { 240 $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
241 panic!("hello"); 241 panic!("crates should be linked against the sysroot version of proc_macro, not this one from rust-analyzer");
242 // Bridge::with(|bridge| { 242 // Bridge::with(|bridge| {
243 // let mut b = bridge.cached_buffer.take(); 243 // let mut b = bridge.cached_buffer.take();
244 244
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
index 14c853c77..ceefd187d 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -25,27 +25,35 @@ type Span = tt::TokenId;
25 25
26#[derive(Debug, Clone)] 26#[derive(Debug, Clone)]
27pub struct TokenStream { 27pub struct TokenStream {
28 pub subtree: tt::Subtree, 28 pub token_trees: Vec<TokenTree>,
29} 29}
30 30
31impl TokenStream { 31impl TokenStream {
32 pub fn new() -> Self { 32 pub fn new() -> Self {
33 TokenStream { subtree: Default::default() } 33 TokenStream { token_trees: Default::default() }
34 } 34 }
35 35
36 pub fn with_subtree(subtree: tt::Subtree) -> Self { 36 pub fn with_subtree(subtree: tt::Subtree) -> Self {
37 TokenStream { subtree } 37 if subtree.delimiter.is_some() {
38 TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
39 } else {
40 TokenStream { token_trees: subtree.token_trees }
41 }
42 }
43
44 pub fn into_subtree(self) -> tt::Subtree {
45 tt::Subtree { delimiter: None, token_trees: self.token_trees }
38 } 46 }
39 47
40 pub fn is_empty(&self) -> bool { 48 pub fn is_empty(&self) -> bool {
41 self.subtree.token_trees.is_empty() 49 self.token_trees.is_empty()
42 } 50 }
43} 51}
44 52
45/// Creates a token stream containing a single token tree. 53/// Creates a token stream containing a single token tree.
46impl From<TokenTree> for TokenStream { 54impl From<TokenTree> for TokenStream {
47 fn from(tree: TokenTree) -> TokenStream { 55 fn from(tree: TokenTree) -> TokenStream {
48 TokenStream { subtree: tt::Subtree { delimiter: None, token_trees: vec![tree] } } 56 TokenStream { token_trees: vec![tree] }
49 } 57 }
50} 58}
51 59
@@ -78,10 +86,10 @@ impl Extend<TokenStream> for TokenStream {
78 for tkn in item { 86 for tkn in item {
79 match tkn { 87 match tkn {
80 tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { 88 tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => {
81 self.subtree.token_trees.extend(subtree.token_trees); 89 self.token_trees.extend(subtree.token_trees);
82 } 90 }
83 _ => { 91 _ => {
84 self.subtree.token_trees.push(tkn); 92 self.token_trees.push(tkn);
85 } 93 }
86 } 94 }
87 } 95 }
@@ -164,7 +172,7 @@ pub mod token_stream {
164 type IntoIter = super::IntoIter<TokenTree>; 172 type IntoIter = super::IntoIter<TokenTree>;
165 173
166 fn into_iter(self) -> Self::IntoIter { 174 fn into_iter(self) -> Self::IntoIter {
167 self.subtree.token_trees.into_iter() 175 self.token_trees.into_iter()
168 } 176 }
169 } 177 }
170 178
@@ -185,28 +193,22 @@ pub mod token_stream {
185 mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; 193 mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
186 194
187 let subtree = subtree_replace_token_ids_with_unspecified(subtree); 195 let subtree = subtree_replace_token_ids_with_unspecified(subtree);
188 Ok(TokenStream { subtree }) 196 Ok(TokenStream::with_subtree(subtree))
189 } 197 }
190 } 198 }
191 199
192 impl ToString for TokenStream { 200 impl ToString for TokenStream {
193 fn to_string(&self) -> String { 201 fn to_string(&self) -> String {
194 let tt = self.subtree.clone().into(); 202 return tokentrees_to_text(&self.token_trees[..]);
195 to_text(&tt)
196 }
197 }
198 203
199 fn to_text(tkn: &tt::TokenTree) -> String { 204 fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
200 match tkn { 205 tkns.iter()
201 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
202 tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
203 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
204 tt::TokenTree::Subtree(subtree) => {
205 let content = subtree
206 .token_trees
207 .iter()
208 .fold((String::new(), true), |(last, last_to_joint), tkn| { 206 .fold((String::new(), true), |(last, last_to_joint), tkn| {
209 let s = [last, to_text(tkn)].join(if last_to_joint { "" } else { " " }); 207 let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
208 ""
209 } else {
210 " "
211 });
210 let mut is_joint = false; 212 let mut is_joint = false;
211 if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { 213 if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
212 if punct.spacing == tt::Spacing::Joint { 214 if punct.spacing == tt::Spacing::Joint {
@@ -215,15 +217,25 @@ pub mod token_stream {
215 } 217 }
216 (s, is_joint) 218 (s, is_joint)
217 }) 219 })
218 .0; 220 .0
219 221 }
220 let (open, close) = match subtree.delimiter.map(|it| it.kind) { 222
221 None => ("", ""), 223 fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
222 Some(tt::DelimiterKind::Brace) => ("{", "}"), 224 match tkn {
223 Some(tt::DelimiterKind::Parenthesis) => ("(", ")"), 225 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
224 Some(tt::DelimiterKind::Bracket) => ("[", "]"), 226 tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
225 }; 227 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
226 format!("{}{}{}", open, content, close) 228 tt::TokenTree::Subtree(subtree) => {
229 let content = tokentrees_to_text(&subtree.token_trees);
230 let (open, close) = match subtree.delimiter.map(|it| it.kind) {
231 None => ("", ""),
232 Some(tt::DelimiterKind::Brace) => ("{", "}"),
233 Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
234 Some(tt::DelimiterKind::Bracket) => ("[", "]"),
235 };
236 format!("{}{}{}", open, content, close)
237 }
238 }
227 } 239 }
228 } 240 }
229 } 241 }
@@ -433,10 +445,7 @@ fn spacing_to_external(spacing: Spacing) -> bridge::Spacing {
433 445
434impl server::Group for Rustc { 446impl server::Group for Rustc {
435 fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group { 447 fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group {
436 Self::Group { 448 Self::Group { delimiter: delim_to_internal(delimiter), token_trees: stream.token_trees }
437 delimiter: delim_to_internal(delimiter),
438 token_trees: stream.subtree.token_trees,
439 }
440 } 449 }
441 fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { 450 fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter {
442 delim_to_external(group.delimiter) 451 delim_to_external(group.delimiter)
@@ -444,9 +453,7 @@ impl server::Group for Rustc {
444 453
445 // NOTE: Return value of do not include delimiter 454 // NOTE: Return value of do not include delimiter
446 fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { 455 fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
447 TokenStream { 456 TokenStream { token_trees: group.token_trees.clone() }
448 subtree: tt::Subtree { delimiter: None, token_trees: group.token_trees.clone() },
449 }
450 } 457 }
451 458
452 fn span(&mut self, group: &Self::Group) -> Self::Span { 459 fn span(&mut self, group: &Self::Group) -> Self::Span {
@@ -755,28 +762,48 @@ mod tests {
755 #[test] 762 #[test]
756 fn test_rustc_server_to_string() { 763 fn test_rustc_server_to_string() {
757 let s = TokenStream { 764 let s = TokenStream {
758 subtree: tt::Subtree { 765 token_trees: vec![
759 delimiter: None, 766 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
760 token_trees: vec![ 767 text: "struct".into(),
761 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { 768 id: tt::TokenId::unspecified(),
762 text: "struct".into(), 769 })),
763 id: tt::TokenId::unspecified(), 770 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
764 })), 771 text: "T".into(),
765 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { 772 id: tt::TokenId::unspecified(),
766 text: "T".into(), 773 })),
774 tt::TokenTree::Subtree(tt::Subtree {
775 delimiter: Some(tt::Delimiter {
767 id: tt::TokenId::unspecified(), 776 id: tt::TokenId::unspecified(),
768 })), 777 kind: tt::DelimiterKind::Brace,
769 tt::TokenTree::Subtree(tt::Subtree {
770 delimiter: Some(tt::Delimiter {
771 id: tt::TokenId::unspecified(),
772 kind: tt::DelimiterKind::Brace,
773 }),
774 token_trees: vec![],
775 }), 778 }),
776 ], 779 token_trees: vec![],
777 }, 780 }),
781 ],
778 }; 782 };
779 783
780 assert_eq!(s.to_string(), "struct T {}"); 784 assert_eq!(s.to_string(), "struct T {}");
781 } 785 }
786
787 #[test]
788 fn test_rustc_server_from_str() {
789 use std::str::FromStr;
790 let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
791 delimiter: Some(tt::Delimiter {
792 id: tt::TokenId::unspecified(),
793 kind: tt::DelimiterKind::Parenthesis,
794 }),
795 token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
796 text: "a".into(),
797 id: tt::TokenId::unspecified(),
798 }))],
799 });
800
801 let t1 = TokenStream::from_str("(a)").unwrap();
802 assert_eq!(t1.token_trees.len(), 1);
803 assert_eq!(t1.token_trees[0], subtree_paren_a);
804
805 let t2 = TokenStream::from_str("(a);").unwrap();
806 assert_eq!(t2.token_trees.len(), 2);
807 assert_eq!(t2.token_trees[0], subtree_paren_a);
808 }
782} 809}
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs
index 22813052d..0484c3af4 100644
--- a/crates/proc_macro_srv/src/tests/utils.rs
+++ b/crates/proc_macro_srv/src/tests/utils.rs
@@ -52,7 +52,7 @@ pub fn assert_expand(
52 let expander = dylib::Expander::new(&path).unwrap(); 52 let expander = dylib::Expander::new(&path).unwrap();
53 let fixture = parse_string(ra_fixture).unwrap(); 53 let fixture = parse_string(ra_fixture).unwrap();
54 54
55 let res = expander.expand(macro_name, &fixture.subtree, None).unwrap(); 55 let res = expander.expand(macro_name, &fixture.into_subtree(), None).unwrap();
56 assert_eq_text!(&expect.trim(), &format!("{:?}", res)); 56 assert_eq_text!(&expect.trim(), &format!("{:?}", res));
57} 57}
58 58
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 8789f0852..3130785cc 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -24,7 +24,7 @@ jod-thread = "0.1.0"
24log = "0.4.8" 24log = "0.4.8"
25lsp-types = { version = "0.88.0", features = ["proposed"] } 25lsp-types = { version = "0.88.0", features = ["proposed"] }
26parking_lot = "0.11.0" 26parking_lot = "0.11.0"
27xflags = "0.1.2" 27xflags = "0.2.1"
28oorandom = "11.1.2" 28oorandom = "11.1.2"
29rustc-hash = "1.1.0" 29rustc-hash = "1.1.0"
30serde = { version = "1.0.106", features = ["derive"] } 30serde = { version = "1.0.106", features = ["derive"] }
diff --git a/crates/rust-analyzer/src/bin/flags.rs b/crates/rust-analyzer/src/bin/flags.rs
index 244912d26..3a7caaf3f 100644
--- a/crates/rust-analyzer/src/bin/flags.rs
+++ b/crates/rust-analyzer/src/bin/flags.rs
@@ -6,7 +6,9 @@ use ide_ssr::{SsrPattern, SsrRule};
6use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; 6use rust_analyzer::cli::{BenchWhat, Position, Verbosity};
7use vfs::AbsPathBuf; 7use vfs::AbsPathBuf;
8 8
9xflags::args_parser! { 9xflags::xflags! {
10 src "./src/bin/flags.rs"
11
10 /// LSP server for the Rust programming language. 12 /// LSP server for the Rust programming language.
11 cmd rust-analyzer { 13 cmd rust-analyzer {
12 /// Verbosity level, can be repeated multiple times. 14 /// Verbosity level, can be repeated multiple times.
@@ -120,7 +122,7 @@ xflags::args_parser! {
120 122
121// generated start 123// generated start
122// The following code is generated by `xflags` macro. 124// The following code is generated by `xflags` macro.
123// Run `env XFLAGS_DUMP= cargo build` to regenerate. 125// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate.
124#[derive(Debug)] 126#[derive(Debug)]
125pub struct RustAnalyzer { 127pub struct RustAnalyzer {
126 pub verbose: u32, 128 pub verbose: u32,
@@ -158,7 +160,7 @@ pub struct Parse {
158} 160}
159 161
160#[derive(Debug)] 162#[derive(Debug)]
161pub struct Symbols {} 163pub struct Symbols;
162 164
163#[derive(Debug)] 165#[derive(Debug)]
164pub struct Highlight { 166pub struct Highlight {
@@ -211,14 +213,13 @@ pub struct Search {
211} 213}
212 214
213#[derive(Debug)] 215#[derive(Debug)]
214pub struct ProcMacro {} 216pub struct ProcMacro;
215 217
216impl RustAnalyzer { 218impl RustAnalyzer {
217 pub const HELP: &'static str = Self::_HELP; 219 pub const HELP: &'static str = Self::HELP_;
218 220
219 pub fn from_env() -> xflags::Result<Self> { 221 pub fn from_env() -> xflags::Result<Self> {
220 let mut p = xflags::rt::Parser::new_from_env(); 222 Self::from_env_()
221 Self::_parse(&mut p)
222 } 223 }
223} 224}
224// generated end 225// generated end
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 3bd7e678d..49994824f 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -108,7 +108,11 @@ impl BenchCmd {
108 add_call_parenthesis: true, 108 add_call_parenthesis: true,
109 add_call_argument_snippets: true, 109 add_call_argument_snippets: true,
110 snippet_cap: SnippetCap::new(true), 110 snippet_cap: SnippetCap::new(true),
111 insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain }, 111 insert_use: InsertUseConfig {
112 merge: None,
113 prefix_kind: PrefixKind::Plain,
114 group: true,
115 },
112 }; 116 };
113 let res = do_work(&mut host, file_id, |analysis| { 117 let res = do_work(&mut host, file_id, |analysis| {
114 analysis.completions(&options, file_position) 118 analysis.completions(&options, file_position)
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 4417c8d13..4dbabdba7 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -35,7 +35,8 @@ config_data! {
35 assist_importMergeBehaviour: MergeBehaviorDef = "\"full\"", 35 assist_importMergeBehaviour: MergeBehaviorDef = "\"full\"",
36 /// The path structure for newly inserted paths to use. 36 /// The path structure for newly inserted paths to use.
37 assist_importPrefix: ImportPrefixDef = "\"plain\"", 37 assist_importPrefix: ImportPrefixDef = "\"plain\"",
38 38 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
39 assist_importGroup: bool = "true",
39 /// Show function name and docs in parameter hints. 40 /// Show function name and docs in parameter hints.
40 callInfo_full: bool = "true", 41 callInfo_full: bool = "true",
41 42
@@ -48,7 +49,7 @@ config_data! {
48 cargo_features: Vec<String> = "[]", 49 cargo_features: Vec<String> = "[]",
49 /// Run build scripts (`build.rs`) for more precise code analysis. 50 /// Run build scripts (`build.rs`) for more precise code analysis.
50 cargo_runBuildScripts | 51 cargo_runBuildScripts |
51 cargo_loadOutDirsFromCheck: bool = "false", 52 cargo_loadOutDirsFromCheck: bool = "true",
52 /// Do not activate the `default` feature. 53 /// Do not activate the `default` feature.
53 cargo_noDefaultFeatures: bool = "false", 54 cargo_noDefaultFeatures: bool = "false",
54 /// Compilation target (target triple). 55 /// Compilation target (target triple).
@@ -575,6 +576,7 @@ impl Config {
575 ImportPrefixDef::ByCrate => PrefixKind::ByCrate, 576 ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
576 ImportPrefixDef::BySelf => PrefixKind::BySelf, 577 ImportPrefixDef::BySelf => PrefixKind::BySelf,
577 }, 578 },
579 group: self.data.assist_importGroup,
578 } 580 }
579 } 581 }
580 pub fn completion(&self) -> CompletionConfig { 582 pub fn completion(&self) -> CompletionConfig {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index c1ca88df6..4235eb6dd 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1087,7 +1087,11 @@ mod tests {
1087 add_call_parenthesis: true, 1087 add_call_parenthesis: true,
1088 add_call_argument_snippets: true, 1088 add_call_argument_snippets: true,
1089 snippet_cap: SnippetCap::new(true), 1089 snippet_cap: SnippetCap::new(true),
1090 insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain }, 1090 insert_use: InsertUseConfig {
1091 merge: None,
1092 prefix_kind: PrefixKind::Plain,
1093 group: true,
1094 },
1091 }, 1095 },
1092 ide_db::base_db::FilePosition { file_id, offset }, 1096 ide_db::base_db::FilePosition { file_id, offset },
1093 ) 1097 )
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 504133070..5243bcbf6 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -2,6 +2,8 @@
2 The strategy to use when inserting new imports or merging imports. 2 The strategy to use when inserting new imports or merging imports.
3[[rust-analyzer.assist.importPrefix]]rust-analyzer.assist.importPrefix (default: `"plain"`):: 3[[rust-analyzer.assist.importPrefix]]rust-analyzer.assist.importPrefix (default: `"plain"`)::
4 The path structure for newly inserted paths to use. 4 The path structure for newly inserted paths to use.
5[[rust-analyzer.assist.importGroup]]rust-analyzer.assist.importGroup (default: `true`)::
6 Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
5[[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`):: 7[[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`)::
6 Show function name and docs in parameter hints. 8 Show function name and docs in parameter hints.
7[[rust-analyzer.cargo.autoreload]]rust-analyzer.cargo.autoreload (default: `true`):: 9[[rust-analyzer.cargo.autoreload]]rust-analyzer.cargo.autoreload (default: `true`)::
@@ -10,7 +12,7 @@
10 Activate all available features (`--all-features`). 12 Activate all available features (`--all-features`).
11[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: 13[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`)::
12 List of features to activate. 14 List of features to activate.
13[[rust-analyzer.cargo.runBuildScripts]]rust-analyzer.cargo.runBuildScripts (default: `false`):: 15[[rust-analyzer.cargo.runBuildScripts]]rust-analyzer.cargo.runBuildScripts (default: `true`)::
14 Run build scripts (`build.rs`) for more precise code analysis. 16 Run build scripts (`build.rs`) for more precise code analysis.
15[[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`):: 17[[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`)::
16 Do not activate the `default` feature. 18 Do not activate the `default` feature.
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 9d0d1d4ec..198c17556 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -9,6 +9,7 @@
9 "version": "0.4.0-dev", 9 "version": "0.4.0-dev",
10 "license": "MIT OR Apache-2.0", 10 "license": "MIT OR Apache-2.0",
11 "dependencies": { 11 "dependencies": {
12 "https-proxy-agent": "^5.0.0",
12 "node-fetch": "^2.6.1", 13 "node-fetch": "^2.6.1",
13 "vscode-languageclient": "^7.1.0-next.4" 14 "vscode-languageclient": "^7.1.0-next.4"
14 }, 15 },
@@ -515,7 +516,6 @@
515 "version": "6.0.2", 516 "version": "6.0.2",
516 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 517 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
517 "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 518 "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
518 "dev": true,
519 "dependencies": { 519 "dependencies": {
520 "debug": "4" 520 "debug": "4"
521 }, 521 },
@@ -830,6 +830,7 @@
830 "dependencies": { 830 "dependencies": {
831 "anymatch": "~3.1.1", 831 "anymatch": "~3.1.1",
832 "braces": "~3.0.2", 832 "braces": "~3.0.2",
833 "fsevents": "~2.3.1",
833 "glob-parent": "~5.1.0", 834 "glob-parent": "~5.1.0",
834 "is-binary-path": "~2.1.0", 835 "is-binary-path": "~2.1.0",
835 "is-glob": "~4.0.1", 836 "is-glob": "~4.0.1",
@@ -959,7 +960,6 @@
959 "version": "4.3.1", 960 "version": "4.3.1",
960 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 961 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
961 "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 962 "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
962 "dev": true,
963 "dependencies": { 963 "dependencies": {
964 "ms": "2.1.2" 964 "ms": "2.1.2"
965 }, 965 },
@@ -1759,7 +1759,6 @@
1759 "version": "5.0.0", 1759 "version": "5.0.0",
1760 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", 1760 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
1761 "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", 1761 "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
1762 "dev": true,
1763 "dependencies": { 1762 "dependencies": {
1764 "agent-base": "6", 1763 "agent-base": "6",
1765 "debug": "4" 1764 "debug": "4"
@@ -2236,8 +2235,7 @@
2236 "node_modules/ms": { 2235 "node_modules/ms": {
2237 "version": "2.1.2", 2236 "version": "2.1.2",
2238 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2237 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
2239 "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 2238 "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
2240 "dev": true
2241 }, 2239 },
2242 "node_modules/mute-stream": { 2240 "node_modules/mute-stream": {
2243 "version": "0.0.8", 2241 "version": "0.0.8",
@@ -2682,6 +2680,9 @@
2682 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.39.1.tgz", 2680 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.39.1.tgz",
2683 "integrity": "sha512-9rfr0Z6j+vE+eayfNVFr1KZ+k+jiUl2+0e4quZafy1x6SFCjzFspfRSO2ZZQeWeX9noeDTUDgg6eCENiEPFvQg==", 2681 "integrity": "sha512-9rfr0Z6j+vE+eayfNVFr1KZ+k+jiUl2+0e4quZafy1x6SFCjzFspfRSO2ZZQeWeX9noeDTUDgg6eCENiEPFvQg==",
2684 "dev": true, 2682 "dev": true,
2683 "dependencies": {
2684 "fsevents": "~2.3.1"
2685 },
2685 "bin": { 2686 "bin": {
2686 "rollup": "dist/bin/rollup" 2687 "rollup": "dist/bin/rollup"
2687 }, 2688 },
@@ -3843,7 +3844,6 @@
3843 "version": "6.0.2", 3844 "version": "6.0.2",
3844 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 3845 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
3845 "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 3846 "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
3846 "dev": true,
3847 "requires": { 3847 "requires": {
3848 "debug": "4" 3848 "debug": "4"
3849 } 3849 }
@@ -4190,7 +4190,6 @@
4190 "version": "4.3.1", 4190 "version": "4.3.1",
4191 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 4191 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
4192 "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 4192 "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
4193 "dev": true,
4194 "requires": { 4193 "requires": {
4195 "ms": "2.1.2" 4194 "ms": "2.1.2"
4196 } 4195 }
@@ -4798,7 +4797,6 @@
4798 "version": "5.0.0", 4797 "version": "5.0.0",
4799 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", 4798 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
4800 "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", 4799 "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
4801 "dev": true,
4802 "requires": { 4800 "requires": {
4803 "agent-base": "6", 4801 "agent-base": "6",
4804 "debug": "4" 4802 "debug": "4"
@@ -5175,8 +5173,7 @@
5175 "ms": { 5173 "ms": {
5176 "version": "2.1.2", 5174 "version": "2.1.2",
5177 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 5175 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
5178 "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 5176 "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
5179 "dev": true
5180 }, 5177 },
5181 "mute-stream": { 5178 "mute-stream": {
5182 "version": "0.0.8", 5179 "version": "0.0.8",
diff --git a/editors/code/package.json b/editors/code/package.json
index b39e8fbe3..856f1c94e 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -35,6 +35,7 @@
35 "test": "node ./out/tests/runTests.js" 35 "test": "node ./out/tests/runTests.js"
36 }, 36 },
37 "dependencies": { 37 "dependencies": {
38 "https-proxy-agent": "^5.0.0",
38 "node-fetch": "^2.6.1", 39 "node-fetch": "^2.6.1",
39 "vscode-languageclient": "^7.1.0-next.4" 40 "vscode-languageclient": "^7.1.0-next.4"
40 }, 41 },
@@ -385,6 +386,11 @@
385 "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." 386 "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to."
386 ] 387 ]
387 }, 388 },
389 "rust-analyzer.assist.importGroup": {
390 "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
391 "default": true,
392 "type": "boolean"
393 },
388 "rust-analyzer.callInfo.full": { 394 "rust-analyzer.callInfo.full": {
389 "markdownDescription": "Show function name and docs in parameter hints.", 395 "markdownDescription": "Show function name and docs in parameter hints.",
390 "default": true, 396 "default": true,
@@ -410,7 +416,7 @@
410 }, 416 },
411 "rust-analyzer.cargo.runBuildScripts": { 417 "rust-analyzer.cargo.runBuildScripts": {
412 "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.", 418 "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.",
413 "default": false, 419 "default": true,
414 "type": "boolean" 420 "type": "boolean"
415 }, 421 },
416 "rust-analyzer.cargo.noDefaultFeatures": { 422 "rust-analyzer.cargo.noDefaultFeatures": {
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index ddb5cfbd3..82f0a0566 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -100,6 +100,14 @@ export class Config {
100 get channel() { return this.get<UpdatesChannel>("updates.channel"); } 100 get channel() { return this.get<UpdatesChannel>("updates.channel"); }
101 get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); } 101 get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); }
102 get traceExtension() { return this.get<boolean>("trace.extension"); } 102 get traceExtension() { return this.get<boolean>("trace.extension"); }
103 get httpProxy() {
104 const httpProxy = vscode
105 .workspace
106 .getConfiguration('http')
107 .get<null | string>("proxy")!;
108
109 return httpProxy || process.env["https_proxy"] || process.env["HTTPS_PROXY"];
110 }
103 111
104 get inlayHints() { 112 get inlayHints() {
105 return { 113 return {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 00393d6e8..1be4f1758 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -183,7 +183,7 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
183 } 183 }
184 184
185 const release = await downloadWithRetryDialog(state, async () => { 185 const release = await downloadWithRetryDialog(state, async () => {
186 return await fetchRelease("nightly", state.githubToken); 186 return await fetchRelease("nightly", state.githubToken, config.httpProxy);
187 }).catch(async (e) => { 187 }).catch(async (e) => {
188 log.error(e); 188 log.error(e);
189 if (state.releaseId === undefined) { // Show error only for the initial download 189 if (state.releaseId === undefined) { // Show error only for the initial download
@@ -209,6 +209,7 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
209 url: artifact.browser_download_url, 209 url: artifact.browser_download_url,
210 dest, 210 dest,
211 progressTitle: "Downloading rust-analyzer extension", 211 progressTitle: "Downloading rust-analyzer extension",
212 httpProxy: config.httpProxy,
212 }); 213 });
213 }); 214 });
214 215
@@ -331,7 +332,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
331 332
332 const releaseTag = config.package.releaseTag; 333 const releaseTag = config.package.releaseTag;
333 const release = await downloadWithRetryDialog(state, async () => { 334 const release = await downloadWithRetryDialog(state, async () => {
334 return await fetchRelease(releaseTag, state.githubToken); 335 return await fetchRelease(releaseTag, state.githubToken, config.httpProxy);
335 }); 336 });
336 const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`); 337 const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`);
337 assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); 338 assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
@@ -343,6 +344,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
343 progressTitle: "Downloading rust-analyzer server", 344 progressTitle: "Downloading rust-analyzer server",
344 gunzip: true, 345 gunzip: true,
345 mode: 0o755, 346 mode: 0o755,
347 httpProxy: config.httpProxy,
346 }); 348 });
347 }); 349 });
348 350
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts
index d39dc1baf..07ebc615c 100644
--- a/editors/code/src/net.ts
+++ b/editors/code/src/net.ts
@@ -1,4 +1,6 @@
1import fetch from "node-fetch"; 1import fetch from "node-fetch";
2var HttpsProxyAgent = require('https-proxy-agent');
3
2import * as vscode from "vscode"; 4import * as vscode from "vscode";
3import * as stream from "stream"; 5import * as stream from "stream";
4import * as crypto from "crypto"; 6import * as crypto from "crypto";
@@ -17,6 +19,7 @@ const REPO = "rust-analyzer";
17export async function fetchRelease( 19export async function fetchRelease(
18 releaseTag: string, 20 releaseTag: string,
19 githubToken: string | null | undefined, 21 githubToken: string | null | undefined,
22 httpProxy: string | null | undefined,
20): Promise<GithubRelease> { 23): Promise<GithubRelease> {
21 24
22 const apiEndpointPath = `/repos/${OWNER}/${REPO}/releases/tags/${releaseTag}`; 25 const apiEndpointPath = `/repos/${OWNER}/${REPO}/releases/tags/${releaseTag}`;
@@ -30,7 +33,14 @@ export async function fetchRelease(
30 headers.Authorization = "token " + githubToken; 33 headers.Authorization = "token " + githubToken;
31 } 34 }
32 35
33 const response = await fetch(requestUrl, { headers: headers }); 36 const response = await (() => {
37 if (httpProxy) {
38 log.debug(`Fetching release metadata via proxy: ${httpProxy}`);
39 return fetch(requestUrl, { headers: headers, agent: new HttpsProxyAgent(httpProxy) });
40 }
41
42 return fetch(requestUrl, { headers: headers });
43 })();
34 44
35 if (!response.ok) { 45 if (!response.ok) {
36 log.error("Error fetching artifact release info", { 46 log.error("Error fetching artifact release info", {
@@ -73,6 +83,7 @@ interface DownloadOpts {
73 dest: string; 83 dest: string;
74 mode?: number; 84 mode?: number;
75 gunzip?: boolean; 85 gunzip?: boolean;
86 httpProxy?: string;
76} 87}
77 88
78export async function download(opts: DownloadOpts) { 89export async function download(opts: DownloadOpts) {
@@ -91,7 +102,7 @@ export async function download(opts: DownloadOpts) {
91 }, 102 },
92 async (progress, _cancellationToken) => { 103 async (progress, _cancellationToken) => {
93 let lastPercentage = 0; 104 let lastPercentage = 0;
94 await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, (readBytes, totalBytes) => { 105 await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, opts.httpProxy, (readBytes, totalBytes) => {
95 const newPercentage = Math.round((readBytes / totalBytes) * 100); 106 const newPercentage = Math.round((readBytes / totalBytes) * 100);
96 if (newPercentage !== lastPercentage) { 107 if (newPercentage !== lastPercentage) {
97 progress.report({ 108 progress.report({
@@ -113,9 +124,17 @@ async function downloadFile(
113 destFilePath: fs.PathLike, 124 destFilePath: fs.PathLike,
114 mode: number | undefined, 125 mode: number | undefined,
115 gunzip: boolean, 126 gunzip: boolean,
127 httpProxy: string | null | undefined,
116 onProgress: (readBytes: number, totalBytes: number) => void 128 onProgress: (readBytes: number, totalBytes: number) => void
117): Promise<void> { 129): Promise<void> {
118 const res = await fetch(url); 130 const res = await (() => {
131 if (httpProxy) {
132 log.debug(`Downloading ${url} via proxy: ${httpProxy}`);
133 return fetch(url, { agent: new HttpsProxyAgent(httpProxy) });
134 }
135
136 return fetch(url);
137 })();
119 138
120 if (!res.ok) { 139 if (!res.ok) {
121 log.error("Error", res.status, "while downloading file from", url); 140 log.error("Error", res.status, "while downloading file from", url);
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index b17dde598..e084f0df6 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -15,5 +15,5 @@ ungrammar = "=1.11"
15walkdir = "2.3.1" 15walkdir = "2.3.1"
16write-json = "0.1.0" 16write-json = "0.1.0"
17xshell = "0.1" 17xshell = "0.1"
18xflags = "0.1.2" 18xflags = "0.2.1"
19# Avoid adding more dependencies to this crate 19# Avoid adding more dependencies to this crate
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 56eda5b1e..b39d937ca 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -2,7 +2,9 @@
2 2
3use crate::install::{ClientOpt, Malloc, ServerOpt}; 3use crate::install::{ClientOpt, Malloc, ServerOpt};
4 4
5xflags::args_parser! { 5xflags::xflags! {
6 src "./src/flags.rs"
7
6 /// Run custom build command. 8 /// Run custom build command.
7 cmd xtask { 9 cmd xtask {
8 default cmd help { 10 default cmd help {
@@ -55,7 +57,7 @@ xflags::args_parser! {
55 57
56// generated start 58// generated start
57// The following code is generated by `xflags` macro. 59// The following code is generated by `xflags` macro.
58// Run `env XFLAGS_DUMP= cargo build` to regenerate. 60// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate.
59#[derive(Debug)] 61#[derive(Debug)]
60pub struct Xtask { 62pub struct Xtask {
61 pub subcommand: XtaskCmd, 63 pub subcommand: XtaskCmd,
@@ -96,13 +98,13 @@ pub struct Codegen {
96} 98}
97 99
98#[derive(Debug)] 100#[derive(Debug)]
99pub struct Lint {} 101pub struct Lint;
100 102
101#[derive(Debug)] 103#[derive(Debug)]
102pub struct FuzzTests {} 104pub struct FuzzTests;
103 105
104#[derive(Debug)] 106#[derive(Debug)]
105pub struct PreCache {} 107pub struct PreCache;
106 108
107#[derive(Debug)] 109#[derive(Debug)]
108pub struct Release { 110pub struct Release {
@@ -131,11 +133,10 @@ pub struct Bb {
131} 133}
132 134
133impl Xtask { 135impl Xtask {
134 pub const HELP: &'static str = Self::_HELP; 136 pub const HELP: &'static str = Self::HELP_;
135 137
136 pub fn from_env() -> xflags::Result<Self> { 138 pub fn from_env() -> xflags::Result<Self> {
137 let mut p = xflags::rt::Parser::new_from_env(); 139 Self::from_env_()
138 Self::_parse(&mut p)
139 } 140 }
140} 141}
141// generated end 142// generated end