aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yaml1
-rw-r--r--Cargo.lock133
-rw-r--r--bors.toml2
-rw-r--r--crates/ra_assists/src/assist_ctx.rs2
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs26
-rw-r--r--crates/ra_assists/src/assists/auto_import.rs222
-rw-r--r--crates/ra_assists/src/assists/inline_local_variable.rs65
-rw-r--r--crates/ra_assists/src/doc_tests.rs4
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs19
-rw-r--r--crates/ra_assists/src/lib.rs179
-rw-r--r--crates/ra_cargo_watch/Cargo.toml4
-rw-r--r--crates/ra_cargo_watch/src/conv.rs2
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/test__snap_clippy_pass_by_ref.snap)0
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/test__snap_handles_macro_location.snap)0
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/test__snap_macro_compiler_error.snap)0
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_incompatible_type_for_trait.snap)0
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_mismatched_type.snap)0
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_unused_variable.snap)0
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_wrong_number_of_parameters.snap)0
-rw-r--r--crates/ra_cargo_watch/src/lib.rs9
-rw-r--r--crates/ra_cli/Cargo.toml2
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir_def/Cargo.toml2
-rw-r--r--crates/ra_hir_ty/Cargo.toml2
-rw-r--r--crates/ra_hir_ty/src/display.rs2
-rw-r--r--crates/ra_hir_ty/src/lib.rs7
-rw-r--r--crates/ra_ide/Cargo.toml2
-rw-r--r--crates/ra_ide/src/assists.rs7
-rw-r--r--crates/ra_ide/src/change.rs10
-rw-r--r--crates/ra_ide/src/imports_locator.rs76
-rw-r--r--crates/ra_ide/src/inlay_hints.rs14
-rw-r--r--crates/ra_ide/src/lib.rs4
-rw-r--r--crates/ra_ide/src/runnables.rs16
-rw-r--r--crates/ra_lsp_server/Cargo.toml7
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs43
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs5
-rw-r--r--crates/ra_lsp_server/src/world.rs4
-rw-r--r--crates/ra_parser/src/lib.rs4
-rw-r--r--crates/ra_prof/src/lib.rs15
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs49
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs4
-rw-r--r--docs/dev/syntax.md535
-rw-r--r--docs/user/assists.md18
-rw-r--r--editors/code/package-lock.json22
-rw-r--r--editors/code/package.json2
45 files changed, 1323 insertions, 198 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 9c81dd97e..2605bc6ae 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -12,6 +12,7 @@ jobs:
12 name: Rust 12 name: Rust
13 runs-on: ${{ matrix.os }} 13 runs-on: ${{ matrix.os }}
14 strategy: 14 strategy:
15 fail-fast: false
15 matrix: 16 matrix:
16 os: [ubuntu-latest, windows-latest, macos-latest] 17 os: [ubuntu-latest, windows-latest, macos-latest]
17 env: 18 env:
diff --git a/Cargo.lock b/Cargo.lock
index 67822cb8a..c51bc26a6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
88 88
89[[package]] 89[[package]]
90name = "bstr" 90name = "bstr"
91version = "0.2.9" 91version = "0.2.10"
92source = "registry+https://github.com/rust-lang/crates.io-index" 92source = "registry+https://github.com/rust-lang/crates.io-index"
93dependencies = [ 93dependencies = [
94 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 94 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -115,7 +115,7 @@ dependencies = [
115 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 115 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
116 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 116 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
117 "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 117 "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
118 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 118 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
119] 119]
120 120
121[[package]] 121[[package]]
@@ -133,9 +133,9 @@ name = "chalk-derive"
133version = "0.1.0" 133version = "0.1.0"
134source = "git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5#ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" 134source = "git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5#ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5"
135dependencies = [ 135dependencies = [
136 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 136 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
137 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 137 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
138 "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", 138 "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
139] 139]
140 140
141[[package]] 141[[package]]
@@ -214,7 +214,7 @@ dependencies = [
214 214
215[[package]] 215[[package]]
216name = "console" 216name = "console"
217version = "0.9.1" 217version = "0.9.2"
218source = "registry+https://github.com/rust-lang/crates.io-index" 218source = "registry+https://github.com/rust-lang/crates.io-index"
219dependencies = [ 219dependencies = [
220 "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 220 "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -326,7 +326,6 @@ name = "env_logger"
326version = "0.7.1" 326version = "0.7.1"
327source = "registry+https://github.com/rust-lang/crates.io-index" 327source = "registry+https://github.com/rust-lang/crates.io-index"
328dependencies = [ 328dependencies = [
329 "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
330 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 329 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
331] 330]
332 331
@@ -421,7 +420,7 @@ version = "0.4.4"
421source = "registry+https://github.com/rust-lang/crates.io-index" 420source = "registry+https://github.com/rust-lang/crates.io-index"
422dependencies = [ 421dependencies = [
423 "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", 422 "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
424 "bstr 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 423 "bstr 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
425 "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 424 "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
426 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 425 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
427 "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 426 "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -444,21 +443,13 @@ dependencies = [
444] 443]
445 444
446[[package]] 445[[package]]
447name = "humantime"
448version = "1.3.0"
449source = "registry+https://github.com/rust-lang/crates.io-index"
450dependencies = [
451 "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
452]
453
454[[package]]
455name = "idna" 446name = "idna"
456version = "0.2.0" 447version = "0.2.0"
457source = "registry+https://github.com/rust-lang/crates.io-index" 448source = "registry+https://github.com/rust-lang/crates.io-index"
458dependencies = [ 449dependencies = [
459 "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 450 "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
460 "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 451 "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
461 "unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", 452 "unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
462] 453]
463 454
464[[package]] 455[[package]]
@@ -489,14 +480,14 @@ dependencies = [
489 480
490[[package]] 481[[package]]
491name = "insta" 482name = "insta"
492version = "0.12.0" 483version = "0.13.0"
493source = "registry+https://github.com/rust-lang/crates.io-index" 484source = "registry+https://github.com/rust-lang/crates.io-index"
494dependencies = [ 485dependencies = [
495 "console 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 486 "console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
496 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 487 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
497 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 488 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
498 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 489 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
499 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 490 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
500 "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", 491 "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
501 "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 492 "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
502] 493]
@@ -519,7 +510,7 @@ dependencies = [
519 510
520[[package]] 511[[package]]
521name = "itoa" 512name = "itoa"
522version = "0.4.4" 513version = "0.4.5"
523source = "registry+https://github.com/rust-lang/crates.io-index" 514source = "registry+https://github.com/rust-lang/crates.io-index"
524 515
525[[package]] 516[[package]]
@@ -619,18 +610,18 @@ dependencies = [
619 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 610 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
620 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 611 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
621 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 612 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
622 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 613 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
623] 614]
624 615
625[[package]] 616[[package]]
626name = "lsp-types" 617name = "lsp-types"
627version = "0.69.0" 618version = "0.70.0"
628source = "registry+https://github.com/rust-lang/crates.io-index" 619source = "registry+https://github.com/rust-lang/crates.io-index"
629dependencies = [ 620dependencies = [
630 "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 621 "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
631 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 622 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
632 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 623 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
633 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 624 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
634 "serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 625 "serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
635 "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 626 "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
636] 627]
@@ -739,7 +730,7 @@ dependencies = [
739 730
740[[package]] 731[[package]]
741name = "once_cell" 732name = "once_cell"
742version = "1.3.0" 733version = "1.3.1"
743source = "registry+https://github.com/rust-lang/crates.io-index" 734source = "registry+https://github.com/rust-lang/crates.io-index"
744 735
745[[package]] 736[[package]]
@@ -784,9 +775,9 @@ version = "0.1.6"
784source = "registry+https://github.com/rust-lang/crates.io-index" 775source = "registry+https://github.com/rust-lang/crates.io-index"
785dependencies = [ 776dependencies = [
786 "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", 777 "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
787 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 778 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
788 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 779 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
789 "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", 780 "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
790] 781]
791 782
792[[package]] 783[[package]]
@@ -818,14 +809,14 @@ name = "proc-macro-hack"
818version = "0.5.11" 809version = "0.5.11"
819source = "registry+https://github.com/rust-lang/crates.io-index" 810source = "registry+https://github.com/rust-lang/crates.io-index"
820dependencies = [ 811dependencies = [
821 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 812 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
822 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 813 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
823 "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", 814 "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
824] 815]
825 816
826[[package]] 817[[package]]
827name = "proc-macro2" 818name = "proc-macro2"
828version = "1.0.7" 819version = "1.0.8"
829source = "registry+https://github.com/rust-lang/crates.io-index" 820source = "registry+https://github.com/rust-lang/crates.io-index"
830dependencies = [ 821dependencies = [
831 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 822 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -833,7 +824,7 @@ dependencies = [
833 824
834[[package]] 825[[package]]
835name = "proptest" 826name = "proptest"
836version = "0.9.4" 827version = "0.9.5"
837source = "registry+https://github.com/rust-lang/crates.io-index" 828source = "registry+https://github.com/rust-lang/crates.io-index"
838dependencies = [ 829dependencies = [
839 "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 830 "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -858,7 +849,7 @@ name = "quote"
858version = "1.0.2" 849version = "1.0.2"
859source = "registry+https://github.com/rust-lang/crates.io-index" 850source = "registry+https://github.com/rust-lang/crates.io-index"
860dependencies = [ 851dependencies = [
861 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 852 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
862] 853]
863 854
864[[package]] 855[[package]]
@@ -902,12 +893,12 @@ version = "0.1.0"
902dependencies = [ 893dependencies = [
903 "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 894 "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
904 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 895 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
905 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 896 "insta 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
906 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 897 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
907 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 898 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
908 "lsp-types 0.69.0 (registry+https://github.com/rust-lang/crates.io-index)", 899 "lsp-types 0.70.0 (registry+https://github.com/rust-lang/crates.io-index)",
909 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 900 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
910 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 901 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
911] 902]
912 903
913[[package]] 904[[package]]
@@ -979,9 +970,9 @@ dependencies = [
979 "anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", 970 "anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
980 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 971 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
981 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 972 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
982 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 973 "insta 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
983 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 974 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
984 "once_cell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 975 "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
985 "ra_arena 0.1.0", 976 "ra_arena 0.1.0",
986 "ra_cfg 0.1.0", 977 "ra_cfg 0.1.0",
987 "ra_db 0.1.0", 978 "ra_db 0.1.0",
@@ -1018,7 +1009,7 @@ dependencies = [
1018 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)", 1009 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
1019 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)", 1010 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
1020 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 1011 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
1021 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 1012 "insta 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
1022 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
1023 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1014 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1024 "ra_arena 0.1.0", 1015 "ra_arena 0.1.0",
@@ -1039,12 +1030,12 @@ dependencies = [
1039 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1030 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1040 "fst 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 1031 "fst 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
1041 "indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1032 "indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1042 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 1033 "insta 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
1043 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 1034 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
1044 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 1035 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
1045 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1036 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1046 "once_cell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1037 "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1047 "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", 1038 "proptest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
1048 "ra_assists 0.1.0", 1039 "ra_assists 0.1.0",
1049 "ra_cfg 0.1.0", 1040 "ra_cfg 0.1.0",
1050 "ra_db 0.1.0", 1041 "ra_db 0.1.0",
@@ -1071,7 +1062,7 @@ dependencies = [
1071 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1062 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1072 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1063 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1073 "lsp-server 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1064 "lsp-server 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1074 "lsp-types 0.69.0 (registry+https://github.com/rust-lang/crates.io-index)", 1065 "lsp-types 0.70.0 (registry+https://github.com/rust-lang/crates.io-index)",
1075 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 1066 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
1076 "ra_cargo_watch 0.1.0", 1067 "ra_cargo_watch 0.1.0",
1077 "ra_ide 0.1.0", 1068 "ra_ide 0.1.0",
@@ -1084,10 +1075,11 @@ dependencies = [
1084 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1075 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1085 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1076 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1086 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 1077 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1087 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 1078 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
1088 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1079 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1089 "test_utils 0.1.0", 1080 "test_utils 0.1.0",
1090 "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1081 "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1082 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1091] 1083]
1092 1084
1093[[package]] 1085[[package]]
@@ -1118,7 +1110,7 @@ dependencies = [
1118 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 1110 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
1119 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 1111 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
1120 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 1112 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
1121 "once_cell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1113 "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1122] 1114]
1123 1115
1124[[package]] 1116[[package]]
@@ -1132,7 +1124,7 @@ dependencies = [
1132 "ra_db 0.1.0", 1124 "ra_db 0.1.0",
1133 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1125 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1134 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 1126 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1135 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 1127 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
1136] 1128]
1137 1129
1138[[package]] 1130[[package]]
@@ -1141,7 +1133,7 @@ version = "0.1.0"
1141dependencies = [ 1133dependencies = [
1142 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1134 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1143 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 1135 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
1144 "once_cell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1136 "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1145 "ra_parser 0.1.0", 1137 "ra_parser 0.1.0",
1146 "ra_text_edit 0.1.0", 1138 "ra_text_edit 0.1.0",
1147 "rowan 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1139 "rowan 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1157,7 +1149,7 @@ dependencies = [
1157name = "ra_text_edit" 1149name = "ra_text_edit"
1158version = "0.1.0" 1150version = "0.1.0"
1159dependencies = [ 1151dependencies = [
1160 "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", 1152 "proptest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
1161 "test_utils 0.1.0", 1153 "test_utils 0.1.0",
1162 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1154 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
1163] 1155]
@@ -1464,9 +1456,9 @@ version = "0.14.1"
1464source = "registry+https://github.com/rust-lang/crates.io-index" 1456source = "registry+https://github.com/rust-lang/crates.io-index"
1465dependencies = [ 1457dependencies = [
1466 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1458 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1467 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 1459 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
1468 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1460 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1469 "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", 1461 "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
1470] 1462]
1471 1463
1472[[package]] 1464[[package]]
@@ -1509,17 +1501,17 @@ name = "serde_derive"
1509version = "1.0.104" 1501version = "1.0.104"
1510source = "registry+https://github.com/rust-lang/crates.io-index" 1502source = "registry+https://github.com/rust-lang/crates.io-index"
1511dependencies = [ 1503dependencies = [
1512 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 1504 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
1513 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1505 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1514 "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", 1506 "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
1515] 1507]
1516 1508
1517[[package]] 1509[[package]]
1518name = "serde_json" 1510name = "serde_json"
1519version = "1.0.44" 1511version = "1.0.45"
1520source = "registry+https://github.com/rust-lang/crates.io-index" 1512source = "registry+https://github.com/rust-lang/crates.io-index"
1521dependencies = [ 1513dependencies = [
1522 "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 1514 "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
1523 "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1515 "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1524 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 1516 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1525] 1517]
@@ -1529,9 +1521,9 @@ name = "serde_repr"
1529version = "0.1.5" 1521version = "0.1.5"
1530source = "registry+https://github.com/rust-lang/crates.io-index" 1522source = "registry+https://github.com/rust-lang/crates.io-index"
1531dependencies = [ 1523dependencies = [
1532 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 1524 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
1533 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1525 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1534 "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", 1526 "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
1535] 1527]
1536 1528
1537[[package]] 1529[[package]]
@@ -1570,10 +1562,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1570 1562
1571[[package]] 1563[[package]]
1572name = "syn" 1564name = "syn"
1573version = "1.0.13" 1565version = "1.0.14"
1574source = "registry+https://github.com/rust-lang/crates.io-index" 1566source = "registry+https://github.com/rust-lang/crates.io-index"
1575dependencies = [ 1567dependencies = [
1576 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 1568 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
1577 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1569 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1578 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1570 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1579] 1571]
@@ -1604,7 +1596,7 @@ name = "test_utils"
1604version = "0.1.0" 1596version = "0.1.0"
1605dependencies = [ 1597dependencies = [
1606 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1598 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1607 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 1599 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
1608 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1600 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
1609] 1601]
1610 1602
@@ -1652,7 +1644,7 @@ dependencies = [
1652 1644
1653[[package]] 1645[[package]]
1654name = "unicode-normalization" 1646name = "unicode-normalization"
1655version = "0.1.11" 1647version = "0.1.12"
1656source = "registry+https://github.com/rust-lang/crates.io-index" 1648source = "registry+https://github.com/rust-lang/crates.io-index"
1657dependencies = [ 1649dependencies = [
1658 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1650 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1760,7 +1752,7 @@ version = "0.1.0"
1760dependencies = [ 1752dependencies = [
1761 "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", 1753 "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
1762 "pico-args 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1754 "pico-args 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1763 "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 1755 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
1764 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1756 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1765 "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1757 "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1766] 1758]
@@ -1787,7 +1779,7 @@ dependencies = [
1787"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" 1779"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
1788"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" 1780"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
1789"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 1781"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
1790"checksum bstr 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3ede750122d9d1f87919570cb2cccee38c84fbc8c5599b25c289af40625b7030" 1782"checksum bstr 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8a65814ca90dfc9705af76bb6ba3c6e2534489a72270e797e603783bb4990b"
1791"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 1783"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
1792"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" 1784"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
1793"checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" 1785"checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202"
@@ -1801,7 +1793,7 @@ dependencies = [
1801"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)" = "<none>" 1793"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)" = "<none>"
1802"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 1794"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
1803"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1795"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
1804"checksum console 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5d540c2d34ac9dd0deb5f3b5f54c36c79efa78f6b3ad19106a554d07a7b5d9f" 1796"checksum console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45e0f3986890b3acbc782009e2629dfe2baa430ac091519ce3be26164a2ae6c0"
1805"checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" 1797"checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
1806"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" 1798"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
1807"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" 1799"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
@@ -1830,15 +1822,14 @@ dependencies = [
1830"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2" 1822"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
1831"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 1823"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
1832"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" 1824"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
1833"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
1834"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 1825"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
1835"checksum indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b54058f0a6ff80b6803da8faf8997cde53872b38f4023728f6830b06cd3c0dc" 1826"checksum indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b54058f0a6ff80b6803da8faf8997cde53872b38f4023728f6830b06cd3c0dc"
1836"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8" 1827"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8"
1837"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" 1828"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
1838"checksum insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d499dc062e841590a67230d853bce62d0abeb91304927871670b7c55c461349" 1829"checksum insta 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d07d2003a61f1eae49feeb2aea003d0da6c80587c20ac505d695805c744d4847"
1839"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 1830"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
1840"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" 1831"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
1841"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 1832"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
1842"checksum jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7" 1833"checksum jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7"
1843"checksum jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45" 1834"checksum jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45"
1844"checksum jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69" 1835"checksum jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69"
@@ -1853,7 +1844,7 @@ dependencies = [
1853"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" 1844"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b"
1854"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 1845"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
1855"checksum lsp-server 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5383e043329615624bbf45e1ba27bd75c176762b2592855c659bc28ac580a06b" 1846"checksum lsp-server 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5383e043329615624bbf45e1ba27bd75c176762b2592855c659bc28ac580a06b"
1856"checksum lsp-types 0.69.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd78b254376c0734bb75c200616e256adbf2c3685497fcc1124db9daf5958630" 1847"checksum lsp-types 0.70.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef197b24cb3f12fc3984667a505691fec9d683204ddff56f12b2d1940e09a988"
1857"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1848"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
1858"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" 1849"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
1859"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" 1850"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
@@ -1864,7 +1855,7 @@ dependencies = [
1864"checksum notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd" 1855"checksum notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
1865"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" 1856"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
1866"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" 1857"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
1867"checksum once_cell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5941ec2d5ee5916c709580d71553b81a633df245bcc73c04dcbd62152ceefc4" 1858"checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
1868"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" 1859"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
1869"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" 1860"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc"
1870"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" 1861"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1"
@@ -1875,8 +1866,8 @@ dependencies = [
1875"checksum pico-args 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ad1f1b834a05d42dae330066e9699a173b28185b3bdc3dbf14ca239585de8cc" 1866"checksum pico-args 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ad1f1b834a05d42dae330066e9699a173b28185b3bdc3dbf14ca239585de8cc"
1876"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" 1867"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
1877"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" 1868"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
1878"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" 1869"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
1879"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" 1870"checksum proptest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bf6147d103a7c9d7598f4105cf049b15c99e2ecd93179bf024f0fd349be5ada4"
1880"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1871"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
1881"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 1872"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
1882"checksum ra_vfs 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc898f237e4b4498959ae0100c688793a23e77624d44ef710ba70094217f98e0" 1873"checksum ra_vfs 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc898f237e4b4498959ae0100c688793a23e77624d44ef710ba70094217f98e0"
@@ -1917,14 +1908,14 @@ dependencies = [
1917"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1908"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1918"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" 1909"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
1919"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" 1910"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
1920"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" 1911"checksum serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "eab8f15f15d6c41a154c1b128a22f2dfabe350ef53c40953d84e36155c91192b"
1921"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" 1912"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573"
1922"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" 1913"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
1923"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1914"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1924"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" 1915"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4"
1925"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" 1916"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b"
1926"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1917"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
1927"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" 1918"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
1928"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 1919"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
1929"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" 1920"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
1930"checksum text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e08bbcb7a3adbda0eb23431206b653bdad3d8dea311e72d36bf2215e27a42579" 1921"checksum text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e08bbcb7a3adbda0eb23431206b653bdad3d8dea311e72d36bf2215e27a42579"
@@ -1933,7 +1924,7 @@ dependencies = [
1933"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" 1924"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
1934"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1925"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
1935"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1926"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
1936"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" 1927"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
1937"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" 1928"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
1938"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 1929"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
1939"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" 1930"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
diff --git a/bors.toml b/bors.toml
index bf5553df4..0bc71860f 100644
--- a/bors.toml
+++ b/bors.toml
@@ -1,6 +1,6 @@
1status = [ 1status = [
2 "Rust (ubuntu-latest)", 2 "Rust (ubuntu-latest)",
3 # "Rust (windows-latest)", 3 "Rust (windows-latest)",
4 "Rust (macos-latest)", 4 "Rust (macos-latest)",
5 "TypeScript" 5 "TypeScript"
6] 6]
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 43f0d664b..2ab65ab99 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -101,7 +101,6 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
101 Some(assist) 101 Some(assist)
102 } 102 }
103 103
104 #[allow(dead_code)] // will be used for auto import assist with multiple actions
105 pub(crate) fn add_assist_group( 104 pub(crate) fn add_assist_group(
106 self, 105 self,
107 id: AssistId, 106 id: AssistId,
@@ -168,7 +167,6 @@ pub(crate) struct ActionBuilder {
168} 167}
169 168
170impl ActionBuilder { 169impl ActionBuilder {
171 #[allow(dead_code)]
172 /// Adds a custom label to the action, if it needs to be different from the assist label 170 /// Adds a custom label to the action, if it needs to be different from the assist label
173 pub(crate) fn label(&mut self, label: impl Into<String>) { 171 pub(crate) fn label(&mut self, label: impl Into<String>) {
174 self.label = Some(label.into()) 172 self.label = Some(label.into())
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs
index f9f826b88..38a351a54 100644
--- a/crates/ra_assists/src/assists/add_explicit_type.rs
+++ b/crates/ra_assists/src/assists/add_explicit_type.rs
@@ -1,7 +1,7 @@
1use hir::{db::HirDatabase, HirDisplay}; 1use hir::{db::HirDatabase, HirDisplay};
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, AstNode, LetStmt, NameOwner}, 3 ast::{self, AstNode, LetStmt, NameOwner},
4 T, 4 TextRange, T,
5}; 5};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{Assist, AssistCtx, AssistId};
@@ -34,6 +34,14 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
34 // The binding must have a name 34 // The binding must have a name
35 let name = pat.name()?; 35 let name = pat.name()?;
36 let name_range = name.syntax().text_range(); 36 let name_range = name.syntax().text_range();
37 // Assist should only be applicable if cursor is between 'let' and '='
38 let stmt_range = stmt.syntax().text_range();
39 let eq_range = stmt.eq_token()?.text_range();
40 let let_range = TextRange::from_to(stmt_range.start(), eq_range.start());
41 let cursor_in_range = ctx.frange.range.is_subrange(&let_range);
42 if !cursor_in_range {
43 return None;
44 }
37 // Assist not applicable if the type has already been specified 45 // Assist not applicable if the type has already been specified
38 if stmt.syntax().children_with_tokens().any(|child| child.kind() == T![:]) { 46 if stmt.syntax().children_with_tokens().any(|child| child.kind() == T![:]) {
39 return None; 47 return None;
@@ -109,4 +117,20 @@ mod tests {
109 fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() { 117 fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() {
110 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: (i32, i32) = (3, 4); }"); 118 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: (i32, i32) = (3, 4); }");
111 } 119 }
120
121 #[test]
122 fn add_explicit_type_not_applicable_if_cursor_after_equals() {
123 check_assist_not_applicable(
124 add_explicit_type,
125 "fn f() {let a =<|> match 1 {2 => 3, 3 => 5};}",
126 )
127 }
128
129 #[test]
130 fn add_explicit_type_not_applicable_if_cursor_before_let() {
131 check_assist_not_applicable(
132 add_explicit_type,
133 "fn f() <|>{let a = match 1 {2 => 3, 3 => 5};}",
134 )
135 }
112} 136}
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs
new file mode 100644
index 000000000..9163cc662
--- /dev/null
+++ b/crates/ra_assists/src/assists/auto_import.rs
@@ -0,0 +1,222 @@
1use hir::db::HirDatabase;
2use ra_syntax::{
3 ast::{self, AstNode},
4 SmolStr, SyntaxElement,
5 SyntaxKind::{NAME_REF, USE_ITEM},
6 SyntaxNode,
7};
8
9use crate::{
10 assist_ctx::{ActionBuilder, Assist, AssistCtx},
11 auto_import_text_edit, AssistId, ImportsLocator,
12};
13
14// Assist: auto_import
15//
16// If the name is unresolved, provides all possible imports for it.
17//
18// ```
19// fn main() {
20// let map = HashMap<|>::new();
21// }
22// ```
23// ->
24// ```
25// use std::collections::HashMap;
26//
27// fn main() {
28// let map = HashMap<|>::new();
29// }
30// ```
31pub(crate) fn auto_import<F: ImportsLocator>(
32 ctx: AssistCtx<impl HirDatabase>,
33 imports_locator: &mut F,
34) -> Option<Assist> {
35 let path: ast::Path = ctx.find_node_at_offset()?;
36 let module = path.syntax().ancestors().find_map(ast::Module::cast);
37 let position = match module.and_then(|it| it.item_list()) {
38 Some(item_list) => item_list.syntax().clone(),
39 None => {
40 let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?;
41 current_file.syntax().clone()
42 }
43 };
44 let source_analyzer = ctx.source_analyzer(&position, None);
45 let module_with_name_to_import = source_analyzer.module()?;
46 let path_to_import = ctx.covering_element().ancestors().find_map(ast::Path::cast)?;
47 if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() {
48 return None;
49 }
50
51 let name_to_import = &find_applicable_name_ref(ctx.covering_element())?.syntax().to_string();
52 let proposed_imports = imports_locator
53 .find_imports(&name_to_import.to_string())
54 .into_iter()
55 .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def))
56 .filter(|use_path| !use_path.segments.is_empty())
57 .take(20)
58 .map(|import| import.to_string())
59 .collect::<std::collections::BTreeSet<_>>();
60 if proposed_imports.is_empty() {
61 return None;
62 }
63
64 ctx.add_assist_group(AssistId("auto_import"), "auto import", || {
65 proposed_imports
66 .into_iter()
67 .map(|import| import_to_action(import, &position, &path_to_import.syntax()))
68 .collect()
69 })
70}
71
72fn find_applicable_name_ref(element: SyntaxElement) -> Option<ast::NameRef> {
73 if element.ancestors().find(|ancestor| ancestor.kind() == USE_ITEM).is_some() {
74 None
75 } else if element.kind() == NAME_REF {
76 Some(element.as_node().cloned().and_then(ast::NameRef::cast)?)
77 } else {
78 let parent = element.parent()?;
79 if parent.kind() == NAME_REF {
80 Some(ast::NameRef::cast(parent)?)
81 } else {
82 None
83 }
84 }
85}
86
87fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder {
88 let mut action_builder = ActionBuilder::default();
89 action_builder.label(format!("Import `{}`", &import));
90 auto_import_text_edit(
91 position,
92 anchor,
93 &[SmolStr::new(import)],
94 action_builder.text_edit_builder(),
95 );
96 action_builder
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::helpers::{
103 check_assist_with_imports_locator, check_assist_with_imports_locator_not_applicable,
104 TestImportsLocator,
105 };
106
107 #[test]
108 fn applicable_when_found_an_import() {
109 check_assist_with_imports_locator(
110 auto_import,
111 TestImportsLocator::new,
112 r"
113 PubStruct<|>
114
115 pub mod PubMod {
116 pub struct PubStruct;
117 }
118 ",
119 r"
120 use PubMod::PubStruct;
121
122 PubStruct<|>
123
124 pub mod PubMod {
125 pub struct PubStruct;
126 }
127 ",
128 );
129 }
130
131 #[test]
132 fn applicable_when_found_multiple_imports() {
133 check_assist_with_imports_locator(
134 auto_import,
135 TestImportsLocator::new,
136 r"
137 PubStruct<|>
138
139 pub mod PubMod1 {
140 pub struct PubStruct;
141 }
142 pub mod PubMod2 {
143 pub struct PubStruct;
144 }
145 pub mod PubMod3 {
146 pub struct PubStruct;
147 }
148 ",
149 r"
150 use PubMod1::PubStruct;
151
152 PubStruct<|>
153
154 pub mod PubMod1 {
155 pub struct PubStruct;
156 }
157 pub mod PubMod2 {
158 pub struct PubStruct;
159 }
160 pub mod PubMod3 {
161 pub struct PubStruct;
162 }
163 ",
164 );
165 }
166
167 #[test]
168 fn not_applicable_for_already_imported_types() {
169 check_assist_with_imports_locator_not_applicable(
170 auto_import,
171 TestImportsLocator::new,
172 r"
173 use PubMod::PubStruct;
174
175 PubStruct<|>
176
177 pub mod PubMod {
178 pub struct PubStruct;
179 }
180 ",
181 );
182 }
183
184 #[test]
185 fn not_applicable_for_types_with_private_paths() {
186 check_assist_with_imports_locator_not_applicable(
187 auto_import,
188 TestImportsLocator::new,
189 r"
190 PrivateStruct<|>
191
192 pub mod PubMod {
193 struct PrivateStruct;
194 }
195 ",
196 );
197 }
198
199 #[test]
200 fn not_applicable_when_no_imports_found() {
201 check_assist_with_imports_locator_not_applicable(
202 auto_import,
203 TestImportsLocator::new,
204 "
205 PubStruct<|>",
206 );
207 }
208
209 #[test]
210 fn not_applicable_in_import_statements() {
211 check_assist_with_imports_locator_not_applicable(
212 auto_import,
213 TestImportsLocator::new,
214 r"
215 use PubStruct<|>;
216
217 pub mod PubMod {
218 pub struct PubStruct;
219 }",
220 );
221 }
222}
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs
index 45e0f983f..83527d904 100644
--- a/crates/ra_assists/src/assists/inline_local_variable.rs
+++ b/crates/ra_assists/src/assists/inline_local_variable.rs
@@ -23,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId};
23// (1 + 2) * 4; 23// (1 + 2) * 4;
24// } 24// }
25// ``` 25// ```
26pub(crate) fn inline_local_varialbe(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 26pub(crate) fn inline_local_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
27 let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; 27 let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
28 let bind_pat = match let_stmt.pat()? { 28 let bind_pat = match let_stmt.pat()? {
29 ast::Pat::BindPat(pat) => pat, 29 ast::Pat::BindPat(pat) => pat,
@@ -47,6 +47,9 @@ pub(crate) fn inline_local_varialbe(ctx: AssistCtx<impl HirDatabase>) -> Option<
47 }; 47 };
48 let analyzer = ctx.source_analyzer(bind_pat.syntax(), None); 48 let analyzer = ctx.source_analyzer(bind_pat.syntax(), None);
49 let refs = analyzer.find_all_refs(&bind_pat); 49 let refs = analyzer.find_all_refs(&bind_pat);
50 if refs.is_empty() {
51 return None;
52 };
50 53
51 let mut wrap_in_parens = vec![true; refs.len()]; 54 let mut wrap_in_parens = vec![true; refs.len()];
52 55
@@ -117,7 +120,7 @@ mod tests {
117 #[test] 120 #[test]
118 fn test_inline_let_bind_literal_expr() { 121 fn test_inline_let_bind_literal_expr() {
119 check_assist( 122 check_assist(
120 inline_local_varialbe, 123 inline_local_variable,
121 " 124 "
122fn bar(a: usize) {} 125fn bar(a: usize) {}
123fn foo() { 126fn foo() {
@@ -151,7 +154,7 @@ fn foo() {
151 #[test] 154 #[test]
152 fn test_inline_let_bind_bin_expr() { 155 fn test_inline_let_bind_bin_expr() {
153 check_assist( 156 check_assist(
154 inline_local_varialbe, 157 inline_local_variable,
155 " 158 "
156fn bar(a: usize) {} 159fn bar(a: usize) {}
157fn foo() { 160fn foo() {
@@ -185,7 +188,7 @@ fn foo() {
185 #[test] 188 #[test]
186 fn test_inline_let_bind_function_call_expr() { 189 fn test_inline_let_bind_function_call_expr() {
187 check_assist( 190 check_assist(
188 inline_local_varialbe, 191 inline_local_variable,
189 " 192 "
190fn bar(a: usize) {} 193fn bar(a: usize) {}
191fn foo() { 194fn foo() {
@@ -219,7 +222,7 @@ fn foo() {
219 #[test] 222 #[test]
220 fn test_inline_let_bind_cast_expr() { 223 fn test_inline_let_bind_cast_expr() {
221 check_assist( 224 check_assist(
222 inline_local_varialbe, 225 inline_local_variable,
223 " 226 "
224fn bar(a: usize): usize { a } 227fn bar(a: usize): usize { a }
225fn foo() { 228fn foo() {
@@ -253,7 +256,7 @@ fn foo() {
253 #[test] 256 #[test]
254 fn test_inline_let_bind_block_expr() { 257 fn test_inline_let_bind_block_expr() {
255 check_assist( 258 check_assist(
256 inline_local_varialbe, 259 inline_local_variable,
257 " 260 "
258fn foo() { 261fn foo() {
259 let a<|> = { 10 + 1 }; 262 let a<|> = { 10 + 1 };
@@ -285,7 +288,7 @@ fn foo() {
285 #[test] 288 #[test]
286 fn test_inline_let_bind_paren_expr() { 289 fn test_inline_let_bind_paren_expr() {
287 check_assist( 290 check_assist(
288 inline_local_varialbe, 291 inline_local_variable,
289 " 292 "
290fn foo() { 293fn foo() {
291 let a<|> = ( 10 + 1 ); 294 let a<|> = ( 10 + 1 );
@@ -317,7 +320,7 @@ fn foo() {
317 #[test] 320 #[test]
318 fn test_not_inline_mut_variable() { 321 fn test_not_inline_mut_variable() {
319 check_assist_not_applicable( 322 check_assist_not_applicable(
320 inline_local_varialbe, 323 inline_local_variable,
321 " 324 "
322fn foo() { 325fn foo() {
323 let mut a<|> = 1 + 1; 326 let mut a<|> = 1 + 1;
@@ -329,7 +332,7 @@ fn foo() {
329 #[test] 332 #[test]
330 fn test_call_expr() { 333 fn test_call_expr() {
331 check_assist( 334 check_assist(
332 inline_local_varialbe, 335 inline_local_variable,
333 " 336 "
334fn foo() { 337fn foo() {
335 let a<|> = bar(10 + 1); 338 let a<|> = bar(10 + 1);
@@ -347,7 +350,7 @@ fn foo() {
347 #[test] 350 #[test]
348 fn test_index_expr() { 351 fn test_index_expr() {
349 check_assist( 352 check_assist(
350 inline_local_varialbe, 353 inline_local_variable,
351 " 354 "
352fn foo() { 355fn foo() {
353 let x = vec![1, 2, 3]; 356 let x = vec![1, 2, 3];
@@ -367,7 +370,7 @@ fn foo() {
367 #[test] 370 #[test]
368 fn test_method_call_expr() { 371 fn test_method_call_expr() {
369 check_assist( 372 check_assist(
370 inline_local_varialbe, 373 inline_local_variable,
371 " 374 "
372fn foo() { 375fn foo() {
373 let bar = vec![1]; 376 let bar = vec![1];
@@ -387,7 +390,7 @@ fn foo() {
387 #[test] 390 #[test]
388 fn test_field_expr() { 391 fn test_field_expr() {
389 check_assist( 392 check_assist(
390 inline_local_varialbe, 393 inline_local_variable,
391 " 394 "
392struct Bar { 395struct Bar {
393 foo: usize 396 foo: usize
@@ -415,7 +418,7 @@ fn foo() {
415 #[test] 418 #[test]
416 fn test_try_expr() { 419 fn test_try_expr() {
417 check_assist( 420 check_assist(
418 inline_local_varialbe, 421 inline_local_variable,
419 " 422 "
420fn foo() -> Option<usize> { 423fn foo() -> Option<usize> {
421 let bar = Some(1); 424 let bar = Some(1);
@@ -437,7 +440,7 @@ fn foo() -> Option<usize> {
437 #[test] 440 #[test]
438 fn test_ref_expr() { 441 fn test_ref_expr() {
439 check_assist( 442 check_assist(
440 inline_local_varialbe, 443 inline_local_variable,
441 " 444 "
442fn foo() { 445fn foo() {
443 let bar = 10; 446 let bar = 10;
@@ -455,7 +458,7 @@ fn foo() {
455 #[test] 458 #[test]
456 fn test_tuple_expr() { 459 fn test_tuple_expr() {
457 check_assist( 460 check_assist(
458 inline_local_varialbe, 461 inline_local_variable,
459 " 462 "
460fn foo() { 463fn foo() {
461 let a<|> = (10, 20); 464 let a<|> = (10, 20);
@@ -471,7 +474,7 @@ fn foo() {
471 #[test] 474 #[test]
472 fn test_array_expr() { 475 fn test_array_expr() {
473 check_assist( 476 check_assist(
474 inline_local_varialbe, 477 inline_local_variable,
475 " 478 "
476fn foo() { 479fn foo() {
477 let a<|> = [1, 2, 3]; 480 let a<|> = [1, 2, 3];
@@ -487,7 +490,7 @@ fn foo() {
487 #[test] 490 #[test]
488 fn test_paren() { 491 fn test_paren() {
489 check_assist( 492 check_assist(
490 inline_local_varialbe, 493 inline_local_variable,
491 " 494 "
492fn foo() { 495fn foo() {
493 let a<|> = (10 + 20); 496 let a<|> = (10 + 20);
@@ -505,7 +508,7 @@ fn foo() {
505 #[test] 508 #[test]
506 fn test_path_expr() { 509 fn test_path_expr() {
507 check_assist( 510 check_assist(
508 inline_local_varialbe, 511 inline_local_variable,
509 " 512 "
510fn foo() { 513fn foo() {
511 let d = 10; 514 let d = 10;
@@ -525,7 +528,7 @@ fn foo() {
525 #[test] 528 #[test]
526 fn test_block_expr() { 529 fn test_block_expr() {
527 check_assist( 530 check_assist(
528 inline_local_varialbe, 531 inline_local_variable,
529 " 532 "
530fn foo() { 533fn foo() {
531 let a<|> = { 10 }; 534 let a<|> = { 10 };
@@ -543,7 +546,7 @@ fn foo() {
543 #[test] 546 #[test]
544 fn test_used_in_different_expr1() { 547 fn test_used_in_different_expr1() {
545 check_assist( 548 check_assist(
546 inline_local_varialbe, 549 inline_local_variable,
547 " 550 "
548fn foo() { 551fn foo() {
549 let a<|> = 10 + 20; 552 let a<|> = 10 + 20;
@@ -565,7 +568,7 @@ fn foo() {
565 #[test] 568 #[test]
566 fn test_used_in_for_expr() { 569 fn test_used_in_for_expr() {
567 check_assist( 570 check_assist(
568 inline_local_varialbe, 571 inline_local_variable,
569 " 572 "
570fn foo() { 573fn foo() {
571 let a<|> = vec![10, 20]; 574 let a<|> = vec![10, 20];
@@ -581,7 +584,7 @@ fn foo() {
581 #[test] 584 #[test]
582 fn test_used_in_while_expr() { 585 fn test_used_in_while_expr() {
583 check_assist( 586 check_assist(
584 inline_local_varialbe, 587 inline_local_variable,
585 " 588 "
586fn foo() { 589fn foo() {
587 let a<|> = 1 > 0; 590 let a<|> = 1 > 0;
@@ -597,7 +600,7 @@ fn foo() {
597 #[test] 600 #[test]
598 fn test_used_in_break_expr() { 601 fn test_used_in_break_expr() {
599 check_assist( 602 check_assist(
600 inline_local_varialbe, 603 inline_local_variable,
601 " 604 "
602fn foo() { 605fn foo() {
603 let a<|> = 1 + 1; 606 let a<|> = 1 + 1;
@@ -617,7 +620,7 @@ fn foo() {
617 #[test] 620 #[test]
618 fn test_used_in_return_expr() { 621 fn test_used_in_return_expr() {
619 check_assist( 622 check_assist(
620 inline_local_varialbe, 623 inline_local_variable,
621 " 624 "
622fn foo() { 625fn foo() {
623 let a<|> = 1 > 0; 626 let a<|> = 1 > 0;
@@ -633,7 +636,7 @@ fn foo() {
633 #[test] 636 #[test]
634 fn test_used_in_match_expr() { 637 fn test_used_in_match_expr() {
635 check_assist( 638 check_assist(
636 inline_local_varialbe, 639 inline_local_variable,
637 " 640 "
638fn foo() { 641fn foo() {
639 let a<|> = 1 > 0; 642 let a<|> = 1 > 0;
@@ -645,4 +648,16 @@ fn foo() {
645}", 648}",
646 ); 649 );
647 } 650 }
651
652 #[test]
653 fn test_not_applicable_if_variable_unused() {
654 check_assist_not_applicable(
655 inline_local_variable,
656 "
657fn foo() {
658 let <|>a = 0;
659}
660 ",
661 )
662 }
648} 663}
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs
index 5dc1ee233..65d51428b 100644
--- a/crates/ra_assists/src/doc_tests.rs
+++ b/crates/ra_assists/src/doc_tests.rs
@@ -11,6 +11,10 @@ use test_utils::{assert_eq_text, extract_range_or_offset};
11use crate::test_db::TestDB; 11use crate::test_db::TestDB;
12 12
13fn check(assist_id: &str, before: &str, after: &str) { 13fn check(assist_id: &str, before: &str, after: &str) {
14 // FIXME we cannot get the imports search functionality here yet, but still need to generate a test and a doc for an assist
15 if assist_id == "auto_import" {
16 return;
17 }
14 let (selection, before) = extract_range_or_offset(before); 18 let (selection, before) = extract_range_or_offset(before);
15 let (db, file_id) = TestDB::with_single_file(&before); 19 let (db, file_id) = TestDB::with_single_file(&before);
16 let frange = FileRange { file_id, range: selection.into() }; 20 let frange = FileRange { file_id, range: selection.into() };
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 7d84dc8fb..ec4587ce7 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -215,6 +215,25 @@ fn main() {
215} 215}
216 216
217#[test] 217#[test]
218fn doctest_auto_import() {
219 check(
220 "auto_import",
221 r#####"
222fn main() {
223 let map = HashMap<|>::new();
224}
225"#####,
226 r#####"
227use std::collections::HashMap;
228
229fn main() {
230 let map = HashMap<|>::new();
231}
232"#####,
233 )
234}
235
236#[test]
218fn doctest_change_visibility() { 237fn doctest_change_visibility() {
219 check( 238 check(
220 "change_visibility", 239 "change_visibility",
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index d45b58966..625ebc4a2 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -14,7 +14,7 @@ mod test_db;
14pub mod ast_transform; 14pub mod ast_transform;
15 15
16use either::Either; 16use either::Either;
17use hir::db::HirDatabase; 17use hir::{db::HirDatabase, ModuleDef};
18use ra_db::FileRange; 18use ra_db::FileRange;
19use ra_syntax::{TextRange, TextUnit}; 19use ra_syntax::{TextRange, TextUnit};
20use ra_text_edit::TextEdit; 20use ra_text_edit::TextEdit;
@@ -77,6 +77,51 @@ where
77 }) 77 })
78} 78}
79 79
80/// A functionality for locating imports for the given name.
81///
82/// Currently has to be a trait with the real implementation provided by the ra_ide_api crate,
83/// due to the search functionality located there.
84/// Later, this trait should be removed completely and the search functionality moved to a separate crate,
85/// accessible from the ra_assists crate.
86pub trait ImportsLocator {
87 /// Finds all imports for the given name and the module that contains this name.
88 fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef>;
89}
90
91/// Return all the assists applicable at the given position
92/// and additional assists that need the imports locator functionality to work.
93///
94/// Assists are returned in the "resolved" state, that is with edit fully
95/// computed.
96pub fn assists_with_imports_locator<H, F>(
97 db: &H,
98 range: FileRange,
99 mut imports_locator: F,
100) -> Vec<ResolvedAssist>
101where
102 H: HirDatabase + 'static,
103 F: ImportsLocator,
104{
105 AssistCtx::with_ctx(db, range, true, |ctx| {
106 let mut assists = assists::all()
107 .iter()
108 .map(|f| f(ctx.clone()))
109 .chain(
110 assists::all_with_imports_locator()
111 .iter()
112 .map(|f| f(ctx.clone(), &mut imports_locator)),
113 )
114 .filter_map(std::convert::identity)
115 .map(|a| match a {
116 Assist::Resolved { assist } => assist,
117 Assist::Unresolved { .. } => unreachable!(),
118 })
119 .collect();
120 sort_assists(&mut assists);
121 assists
122 })
123}
124
80/// Return all the assists applicable at the given position. 125/// Return all the assists applicable at the given position.
81/// 126///
82/// Assists are returned in the "resolved" state, that is with edit fully 127/// Assists are returned in the "resolved" state, that is with edit fully
@@ -85,8 +130,6 @@ pub fn assists<H>(db: &H, range: FileRange) -> Vec<ResolvedAssist>
85where 130where
86 H: HirDatabase + 'static, 131 H: HirDatabase + 'static,
87{ 132{
88 use std::cmp::Ordering;
89
90 AssistCtx::with_ctx(db, range, true, |ctx| { 133 AssistCtx::with_ctx(db, range, true, |ctx| {
91 let mut a = assists::all() 134 let mut a = assists::all()
92 .iter() 135 .iter()
@@ -95,19 +138,24 @@ where
95 Assist::Resolved { assist } => assist, 138 Assist::Resolved { assist } => assist,
96 Assist::Unresolved { .. } => unreachable!(), 139 Assist::Unresolved { .. } => unreachable!(),
97 }) 140 })
98 .collect::<Vec<_>>(); 141 .collect();
99 a.sort_by(|a, b| match (a.get_first_action().target, b.get_first_action().target) { 142 sort_assists(&mut a);
100 (Some(a), Some(b)) => a.len().cmp(&b.len()),
101 (Some(_), None) => Ordering::Less,
102 (None, Some(_)) => Ordering::Greater,
103 (None, None) => Ordering::Equal,
104 });
105 a 143 a
106 }) 144 })
107} 145}
108 146
147fn sort_assists(assists: &mut Vec<ResolvedAssist>) {
148 use std::cmp::Ordering;
149 assists.sort_by(|a, b| match (a.get_first_action().target, b.get_first_action().target) {
150 (Some(a), Some(b)) => a.len().cmp(&b.len()),
151 (Some(_), None) => Ordering::Less,
152 (None, Some(_)) => Ordering::Greater,
153 (None, None) => Ordering::Equal,
154 });
155}
156
109mod assists { 157mod assists {
110 use crate::{Assist, AssistCtx}; 158 use crate::{Assist, AssistCtx, ImportsLocator};
111 use hir::db::HirDatabase; 159 use hir::db::HirDatabase;
112 160
113 mod add_derive; 161 mod add_derive;
@@ -116,6 +164,7 @@ mod assists {
116 mod add_custom_impl; 164 mod add_custom_impl;
117 mod add_new; 165 mod add_new;
118 mod apply_demorgan; 166 mod apply_demorgan;
167 mod auto_import;
119 mod invert_if; 168 mod invert_if;
120 mod flip_comma; 169 mod flip_comma;
121 mod flip_binexpr; 170 mod flip_binexpr;
@@ -157,7 +206,7 @@ mod assists {
157 add_import::add_import, 206 add_import::add_import,
158 add_missing_impl_members::add_missing_impl_members, 207 add_missing_impl_members::add_missing_impl_members,
159 add_missing_impl_members::add_missing_default_members, 208 add_missing_impl_members::add_missing_default_members,
160 inline_local_variable::inline_local_varialbe, 209 inline_local_variable::inline_local_variable,
161 move_guard::move_guard_to_arm_body, 210 move_guard::move_guard_to_arm_body,
162 move_guard::move_arm_cond_to_match_guard, 211 move_guard::move_arm_cond_to_match_guard,
163 move_bounds::move_bounds_to_where_clause, 212 move_bounds::move_bounds_to_where_clause,
@@ -168,15 +217,69 @@ mod assists {
168 early_return::convert_to_guarded_return, 217 early_return::convert_to_guarded_return,
169 ] 218 ]
170 } 219 }
220
221 pub(crate) fn all_with_imports_locator<'a, DB: HirDatabase, F: ImportsLocator>(
222 ) -> &'a [fn(AssistCtx<DB>, &mut F) -> Option<Assist>] {
223 &[auto_import::auto_import]
224 }
171} 225}
172 226
173#[cfg(test)] 227#[cfg(test)]
174mod helpers { 228mod helpers {
175 use ra_db::{fixture::WithFixture, FileRange}; 229 use hir::db::DefDatabase;
230 use ra_db::{fixture::WithFixture, FileId, FileRange};
176 use ra_syntax::TextRange; 231 use ra_syntax::TextRange;
177 use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; 232 use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range};
178 233
179 use crate::{test_db::TestDB, Assist, AssistCtx}; 234 use crate::{test_db::TestDB, Assist, AssistCtx, ImportsLocator};
235 use std::sync::Arc;
236
237 // FIXME remove the `ModuleDefId` reexport from `ra_hir` when this gets removed.
238 pub(crate) struct TestImportsLocator {
239 db: Arc<TestDB>,
240 test_file_id: FileId,
241 }
242
243 impl TestImportsLocator {
244 pub(crate) fn new(db: Arc<TestDB>, test_file_id: FileId) -> Self {
245 TestImportsLocator { db, test_file_id }
246 }
247 }
248
249 impl ImportsLocator for TestImportsLocator {
250 fn find_imports(&mut self, name_to_import: &str) -> Vec<hir::ModuleDef> {
251 let crate_def_map = self.db.crate_def_map(self.db.test_crate());
252 let mut findings = Vec::new();
253
254 let mut module_ids_to_process =
255 crate_def_map.modules_for_file(self.test_file_id).collect::<Vec<_>>();
256
257 while !module_ids_to_process.is_empty() {
258 let mut more_ids_to_process = Vec::new();
259 for local_module_id in module_ids_to_process.drain(..) {
260 for (name, namespace_data) in
261 crate_def_map[local_module_id].scope.entries_without_primitives()
262 {
263 let found_a_match = &name.to_string() == name_to_import;
264 vec![namespace_data.types, namespace_data.values]
265 .into_iter()
266 .filter_map(std::convert::identity)
267 .for_each(|(module_def_id, _)| {
268 if found_a_match {
269 findings.push(module_def_id.into());
270 }
271 if let hir::ModuleDefId::ModuleId(module_id) = module_def_id {
272 more_ids_to_process.push(module_id.local_id);
273 }
274 });
275 }
276 }
277 module_ids_to_process = more_ids_to_process;
278 }
279
280 findings
281 }
282 }
180 283
181 pub(crate) fn check_assist( 284 pub(crate) fn check_assist(
182 assist: fn(AssistCtx<TestDB>) -> Option<Assist>, 285 assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
@@ -206,6 +309,38 @@ mod helpers {
206 assert_eq_text!(after, &actual); 309 assert_eq_text!(after, &actual);
207 } 310 }
208 311
312 pub(crate) fn check_assist_with_imports_locator<F: ImportsLocator>(
313 assist: fn(AssistCtx<TestDB>, &mut F) -> Option<Assist>,
314 imports_locator_provider: fn(db: Arc<TestDB>, file_id: FileId) -> F,
315 before: &str,
316 after: &str,
317 ) {
318 let (before_cursor_pos, before) = extract_offset(before);
319 let (db, file_id) = TestDB::with_single_file(&before);
320 let db = Arc::new(db);
321 let mut imports_locator = imports_locator_provider(Arc::clone(&db), file_id);
322 let frange =
323 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
324 let assist =
325 AssistCtx::with_ctx(db.as_ref(), frange, true, |ctx| assist(ctx, &mut imports_locator))
326 .expect("code action is not applicable");
327 let action = match assist {
328 Assist::Unresolved { .. } => unreachable!(),
329 Assist::Resolved { assist } => assist.get_first_action(),
330 };
331
332 let actual = action.edit.apply(&before);
333 let actual_cursor_pos = match action.cursor_position {
334 None => action
335 .edit
336 .apply_to_offset(before_cursor_pos)
337 .expect("cursor position is affected by the edit"),
338 Some(off) => off,
339 };
340 let actual = add_cursor(&actual, actual_cursor_pos);
341 assert_eq_text!(after, &actual);
342 }
343
209 pub(crate) fn check_assist_range( 344 pub(crate) fn check_assist_range(
210 assist: fn(AssistCtx<TestDB>) -> Option<Assist>, 345 assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
211 before: &str, 346 before: &str,
@@ -279,6 +414,22 @@ mod helpers {
279 assert!(assist.is_none()); 414 assert!(assist.is_none());
280 } 415 }
281 416
417 pub(crate) fn check_assist_with_imports_locator_not_applicable<F: ImportsLocator>(
418 assist: fn(AssistCtx<TestDB>, &mut F) -> Option<Assist>,
419 imports_locator_provider: fn(db: Arc<TestDB>, file_id: FileId) -> F,
420 before: &str,
421 ) {
422 let (before_cursor_pos, before) = extract_offset(before);
423 let (db, file_id) = TestDB::with_single_file(&before);
424 let db = Arc::new(db);
425 let mut imports_locator = imports_locator_provider(Arc::clone(&db), file_id);
426 let frange =
427 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
428 let assist =
429 AssistCtx::with_ctx(db.as_ref(), frange, true, |ctx| assist(ctx, &mut imports_locator));
430 assert!(assist.is_none());
431 }
432
282 pub(crate) fn check_assist_range_not_applicable( 433 pub(crate) fn check_assist_range_not_applicable(
283 assist: fn(AssistCtx<TestDB>) -> Option<Assist>, 434 assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
284 before: &str, 435 before: &str,
diff --git a/crates/ra_cargo_watch/Cargo.toml b/crates/ra_cargo_watch/Cargo.toml
index 9ead48abf..49e06e0d3 100644
--- a/crates/ra_cargo_watch/Cargo.toml
+++ b/crates/ra_cargo_watch/Cargo.toml
@@ -6,12 +6,12 @@ authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8crossbeam-channel = "0.4" 8crossbeam-channel = "0.4"
9lsp-types = { version = "0.69.0", features = ["proposed"] } 9lsp-types = { version = "0.70.0", features = ["proposed"] }
10log = "0.4.3" 10log = "0.4.3"
11cargo_metadata = "0.9.1" 11cargo_metadata = "0.9.1"
12jod-thread = "0.1.0" 12jod-thread = "0.1.0"
13parking_lot = "0.10.0" 13parking_lot = "0.10.0"
14 14
15[dev-dependencies] 15[dev-dependencies]
16insta = "0.12.0" 16insta = "0.13.0"
17serde_json = "1.0" \ No newline at end of file 17serde_json = "1.0" \ No newline at end of file
diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs
index ac0f1d28a..8fba400ae 100644
--- a/crates/ra_cargo_watch/src/conv.rs
+++ b/crates/ra_cargo_watch/src/conv.rs
@@ -117,7 +117,7 @@ fn is_deprecated(rd: &RustDiagnostic) -> bool {
117 } 117 }
118} 118}
119 119
120#[derive(Debug)] 120#[derive(Clone, Debug)]
121pub struct SuggestedFix { 121pub struct SuggestedFix {
122 pub title: String, 122 pub title: String,
123 pub location: Location, 123 pub location: Location,
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_clippy_pass_by_ref.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
index cb0920914..cb0920914 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_clippy_pass_by_ref.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_handles_macro_location.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap
index 19510ecc1..19510ecc1 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_handles_macro_location.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_macro_compiler_error.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap
index 92f7eec05..92f7eec05 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_macro_compiler_error.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_incompatible_type_for_trait.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap
index cf683e4b6..cf683e4b6 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_incompatible_type_for_trait.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_mismatched_type.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap
index 8c1483c74..8c1483c74 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_mismatched_type.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_unused_variable.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap
index eb5a2247b..eb5a2247b 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_unused_variable.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_wrong_number_of_parameters.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap
index 2f4518931..2f4518931 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/test__snap_rustc_wrong_number_of_parameters.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs
index 7f4c9280c..bbe634603 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_cargo_watch/src/lib.rs
@@ -7,7 +7,6 @@ use lsp_types::{
7 Diagnostic, Url, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressEnd, 7 Diagnostic, Url, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressEnd,
8 WorkDoneProgressReport, 8 WorkDoneProgressReport,
9}; 9};
10use parking_lot::RwLock;
11use std::{ 10use std::{
12 collections::HashMap, 11 collections::HashMap,
13 path::PathBuf, 12 path::PathBuf,
@@ -38,7 +37,7 @@ pub struct CheckOptions {
38#[derive(Debug)] 37#[derive(Debug)]
39pub struct CheckWatcher { 38pub struct CheckWatcher {
40 pub task_recv: Receiver<CheckTask>, 39 pub task_recv: Receiver<CheckTask>,
41 pub state: Arc<RwLock<CheckState>>, 40 pub state: Arc<CheckState>,
42 cmd_send: Option<Sender<CheckCommand>>, 41 cmd_send: Option<Sender<CheckCommand>>,
43 handle: Option<JoinHandle<()>>, 42 handle: Option<JoinHandle<()>>,
44} 43}
@@ -46,7 +45,7 @@ pub struct CheckWatcher {
46impl CheckWatcher { 45impl CheckWatcher {
47 pub fn new(options: &CheckOptions, workspace_root: PathBuf) -> CheckWatcher { 46 pub fn new(options: &CheckOptions, workspace_root: PathBuf) -> CheckWatcher {
48 let options = options.clone(); 47 let options = options.clone();
49 let state = Arc::new(RwLock::new(CheckState::new())); 48 let state = Arc::new(CheckState::new());
50 49
51 let (task_send, task_recv) = unbounded::<CheckTask>(); 50 let (task_send, task_recv) = unbounded::<CheckTask>();
52 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); 51 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
@@ -59,7 +58,7 @@ impl CheckWatcher {
59 58
60 /// Returns a CheckWatcher that doesn't actually do anything 59 /// Returns a CheckWatcher that doesn't actually do anything
61 pub fn dummy() -> CheckWatcher { 60 pub fn dummy() -> CheckWatcher {
62 let state = Arc::new(RwLock::new(CheckState::new())); 61 let state = Arc::new(CheckState::new());
63 CheckWatcher { task_recv: never(), cmd_send: None, handle: None, state } 62 CheckWatcher { task_recv: never(), cmd_send: None, handle: None, state }
64 } 63 }
65 64
@@ -87,7 +86,7 @@ impl std::ops::Drop for CheckWatcher {
87 } 86 }
88} 87}
89 88
90#[derive(Debug)] 89#[derive(Clone, Debug)]
91pub struct CheckState { 90pub struct CheckState {
92 diagnostic_collection: HashMap<Url, Vec<Diagnostic>>, 91 diagnostic_collection: HashMap<Url, Vec<Diagnostic>>,
93 suggested_fix_collection: HashMap<Url, Vec<SuggestedFix>>, 92 suggested_fix_collection: HashMap<Url, Vec<SuggestedFix>>,
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index 12af075f7..bcd408421 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
7 7
8[dependencies] 8[dependencies]
9pico-args = "0.3.0" 9pico-args = "0.3.0"
10env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] } 10env_logger = { version = "0.7.1", default-features = false }
11 11
12ra_syntax = { path = "../ra_syntax" } 12ra_syntax = { path = "../ra_syntax" }
13ra_ide = { path = "../ra_ide" } 13ra_ide = { path = "../ra_ide" }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index e1c7b7a20..9e2673d13 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -56,6 +56,7 @@ pub use hir_def::{
56 nameres::ModuleSource, 56 nameres::ModuleSource,
57 path::{ModPath, Path, PathKind}, 57 path::{ModPath, Path, PathKind},
58 type_ref::Mutability, 58 type_ref::Mutability,
59 ModuleDefId, // FIXME this is exposed and should be used for implementing the `TestImportsLocator` in `ra_assists` only, should be removed later along with the trait and the implementation.
59}; 60};
60pub use hir_expand::{ 61pub use hir_expand::{
61 name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, 62 name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin,
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index 2c368f690..1efa00fe0 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -26,4 +26,4 @@ ra_cfg = { path = "../ra_cfg" }
26tt = { path = "../ra_tt", package = "ra_tt" } 26tt = { path = "../ra_tt", package = "ra_tt" }
27 27
28[dev-dependencies] 28[dev-dependencies]
29insta = "0.12.0" 29insta = "0.13.0"
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 60793db44..d229639d9 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -28,4 +28,4 @@ chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5a
28lalrpop-intern = "0.15.1" 28lalrpop-intern = "0.15.1"
29 29
30[dev-dependencies] 30[dev-dependencies]
31insta = "0.12.0" 31insta = "0.13.0"
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index 37def7c03..d1ff85f0f 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -9,7 +9,7 @@ pub struct HirFormatter<'a, 'b, DB> {
9 fmt: &'a mut fmt::Formatter<'b>, 9 fmt: &'a mut fmt::Formatter<'b>,
10 buf: String, 10 buf: String,
11 curr_size: usize, 11 curr_size: usize,
12 max_size: Option<usize>, 12 pub(crate) max_size: Option<usize>,
13 omit_verbose_types: bool, 13 omit_verbose_types: bool,
14} 14}
15 15
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index d63f862dc..908e4862d 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -855,7 +855,12 @@ impl HirDisplay for ApplicationTy {
855 } 855 }
856 TypeCtor::Ref(m) => { 856 TypeCtor::Ref(m) => {
857 let t = self.parameters.as_single(); 857 let t = self.parameters.as_single();
858 write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?; 858 let ty_display = if f.omit_verbose_types() {
859 t.display_truncated(f.db, f.max_size)
860 } else {
861 t.display(f.db)
862 };
863 write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?;
859 } 864 }
860 TypeCtor::Never => write!(f, "!")?, 865 TypeCtor::Never => write!(f, "!")?,
861 TypeCtor::Tuple { .. } => { 866 TypeCtor::Tuple { .. } => {
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index 2c9f9dce0..53817d1f7 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -39,7 +39,7 @@ ra_assists = { path = "../ra_assists" }
39hir = { path = "../ra_hir", package = "ra_hir" } 39hir = { path = "../ra_hir", package = "ra_hir" }
40 40
41[dev-dependencies] 41[dev-dependencies]
42insta = "0.12.0" 42insta = "0.13.0"
43 43
44[dev-dependencies.proptest] 44[dev-dependencies.proptest]
45version = "0.9.0" 45version = "0.9.0"
diff --git a/crates/ra_ide/src/assists.rs b/crates/ra_ide/src/assists.rs
index a936900da..c43c45c65 100644
--- a/crates/ra_ide/src/assists.rs
+++ b/crates/ra_ide/src/assists.rs
@@ -2,8 +2,9 @@
2 2
3use ra_db::{FilePosition, FileRange}; 3use ra_db::{FilePosition, FileRange};
4 4
5use crate::{db::RootDatabase, FileId, SourceChange, SourceFileEdit}; 5use crate::{
6 6 db::RootDatabase, imports_locator::ImportsLocatorIde, FileId, SourceChange, SourceFileEdit,
7};
7use either::Either; 8use either::Either;
8pub use ra_assists::AssistId; 9pub use ra_assists::AssistId;
9use ra_assists::{AssistAction, AssistLabel}; 10use ra_assists::{AssistAction, AssistLabel};
@@ -16,7 +17,7 @@ pub struct Assist {
16} 17}
17 18
18pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { 19pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> {
19 ra_assists::assists(db, frange) 20 ra_assists::assists_with_imports_locator(db, frange, ImportsLocatorIde::new(db))
20 .into_iter() 21 .into_iter()
21 .map(|assist| { 22 .map(|assist| {
22 let file_id = frange.file_id; 23 let file_id = frange.file_id;
diff --git a/crates/ra_ide/src/change.rs b/crates/ra_ide/src/change.rs
index b0aa2c8e0..ce617840c 100644
--- a/crates/ra_ide/src/change.rs
+++ b/crates/ra_ide/src/change.rs
@@ -166,13 +166,15 @@ impl LibraryData {
166const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100); 166const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
167 167
168impl RootDatabase { 168impl RootDatabase {
169 pub(crate) fn request_cancellation(&mut self) {
170 let _p = profile("RootDatabase::request_cancellation");
171 self.salsa_runtime_mut().synthetic_write(Durability::LOW);
172 }
173
169 pub(crate) fn apply_change(&mut self, change: AnalysisChange) { 174 pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
170 let _p = profile("RootDatabase::apply_change"); 175 let _p = profile("RootDatabase::apply_change");
176 self.request_cancellation();
171 log::info!("apply_change {:?}", change); 177 log::info!("apply_change {:?}", change);
172 {
173 let _p = profile("RootDatabase::apply_change/cancellation");
174 self.salsa_runtime_mut().synthetic_write(Durability::LOW);
175 }
176 if !change.new_roots.is_empty() { 178 if !change.new_roots.is_empty() {
177 let mut local_roots = Vec::clone(&self.local_roots()); 179 let mut local_roots = Vec::clone(&self.local_roots());
178 for (root_id, is_local) in change.new_roots { 180 for (root_id, is_local) in change.new_roots {
diff --git a/crates/ra_ide/src/imports_locator.rs b/crates/ra_ide/src/imports_locator.rs
new file mode 100644
index 000000000..48b014c7d
--- /dev/null
+++ b/crates/ra_ide/src/imports_locator.rs
@@ -0,0 +1,76 @@
1//! This module contains an import search funcionality that is provided to the ra_assists module.
2//! Later, this should be moved away to a separate crate that is accessible from the ra_assists module.
3
4use crate::{
5 db::RootDatabase,
6 references::{classify_name, NameDefinition, NameKind},
7 symbol_index::{self, FileSymbol},
8 Query,
9};
10use hir::{db::HirDatabase, ModuleDef, SourceBinder};
11use ra_assists::ImportsLocator;
12use ra_prof::profile;
13use ra_syntax::{ast, AstNode, SyntaxKind::NAME};
14
15pub(crate) struct ImportsLocatorIde<'a> {
16 source_binder: SourceBinder<'a, RootDatabase>,
17}
18
19impl<'a> ImportsLocatorIde<'a> {
20 pub(crate) fn new(db: &'a RootDatabase) -> Self {
21 Self { source_binder: SourceBinder::new(db) }
22 }
23
24 fn get_name_definition(
25 &mut self,
26 db: &impl HirDatabase,
27 import_candidate: &FileSymbol,
28 ) -> Option<NameDefinition> {
29 let _p = profile("get_name_definition");
30 let file_id = import_candidate.file_id.into();
31 let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?);
32 let candidate_name_node = if candidate_node.kind() != NAME {
33 candidate_node.children().find(|it| it.kind() == NAME)?
34 } else {
35 candidate_node
36 };
37 classify_name(
38 &mut self.source_binder,
39 hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? },
40 )
41 }
42}
43
44impl ImportsLocator for ImportsLocatorIde<'_> {
45 fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> {
46 let _p = profile("search_for_imports");
47 let db = self.source_binder.db;
48
49 let project_results = {
50 let mut query = Query::new(name_to_import.to_string());
51 query.exact();
52 query.limit(40);
53 symbol_index::world_symbols(db, query)
54 };
55 let lib_results = {
56 let mut query = Query::new(name_to_import.to_string());
57 query.libs();
58 query.exact();
59 query.limit(40);
60 symbol_index::world_symbols(db, query)
61 };
62
63 project_results
64 .into_iter()
65 .chain(lib_results.into_iter())
66 .filter_map(|import_candidate| self.get_name_definition(db, &import_candidate))
67 .filter_map(|name_definition_to_import| {
68 if let NameKind::Def(module_def) = name_definition_to_import.kind {
69 Some(module_def)
70 } else {
71 None
72 }
73 })
74 .collect()
75 }
76}
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 236557541..393ca9447 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -245,6 +245,7 @@ struct Test<K, T = u8> {
245 245
246fn main() { 246fn main() {
247 let zz = Test { t: 23, k: 33 }; 247 let zz = Test { t: 23, k: 33 };
248 let zz_ref = &zz;
248}"#, 249}"#,
249 ); 250 );
250 251
@@ -255,6 +256,11 @@ fn main() {
255 kind: TypeHint, 256 kind: TypeHint,
256 label: "Test<i32>", 257 label: "Test<i32>",
257 }, 258 },
259 InlayHint {
260 range: [105; 111),
261 kind: TypeHint,
262 label: "&Test<i32>",
263 },
258 ] 264 ]
259 "### 265 "###
260 ); 266 );
@@ -374,6 +380,7 @@ fn main() {
374 380
375 let multiply = |a, b, c, d| a * b * c * d; 381 let multiply = |a, b, c, d| a * b * c * d;
376 let _: i32 = multiply(1, 2, 3, 4); 382 let _: i32 = multiply(1, 2, 3, 4);
383 let multiply_ref = &multiply;
377 384
378 let return_42 = || 42; 385 let return_42 = || 42;
379}"#, 386}"#,
@@ -417,7 +424,12 @@ fn main() {
417 label: "i32", 424 label: "i32",
418 }, 425 },
419 InlayHint { 426 InlayHint {
420 range: [201; 210), 427 range: [200; 212),
428 kind: TypeHint,
429 label: "&|…| -> i32",
430 },
431 InlayHint {
432 range: [235; 244),
421 kind: TypeHint, 433 kind: TypeHint,
422 label: "|| -> i32", 434 label: "|| -> i32",
423 }, 435 },
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 4d8deb21c..03ad6b2c1 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -30,6 +30,7 @@ mod syntax_highlighting;
30mod parent_module; 30mod parent_module;
31mod references; 31mod references;
32mod impls; 32mod impls;
33mod imports_locator;
33mod assists; 34mod assists;
34mod diagnostics; 35mod diagnostics;
35mod syntax_tree; 36mod syntax_tree;
@@ -202,6 +203,9 @@ impl AnalysisHost {
202 pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> { 203 pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> {
203 self.db.per_query_memory_usage() 204 self.db.per_query_memory_usage()
204 } 205 }
206 pub fn request_cancellation(&mut self) {
207 self.db.request_cancellation();
208 }
205 pub fn raw_database( 209 pub fn raw_database(
206 &self, 210 &self,
207 ) -> &(impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) { 211 ) -> &(impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) {
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 7533692f6..8622dd956 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -43,7 +43,7 @@ fn runnable_fn(fn_def: ast::FnDef) -> Option<Runnable> {
43 let name = fn_def.name()?.text().clone(); 43 let name = fn_def.name()?.text().clone();
44 let kind = if name == "main" { 44 let kind = if name == "main" {
45 RunnableKind::Bin 45 RunnableKind::Bin
46 } else if fn_def.has_atom_attr("test") { 46 } else if has_test_related_attribute(&fn_def) {
47 RunnableKind::Test { name: name.to_string() } 47 RunnableKind::Test { name: name.to_string() }
48 } else if fn_def.has_atom_attr("bench") { 48 } else if fn_def.has_atom_attr("bench") {
49 RunnableKind::Bench { name: name.to_string() } 49 RunnableKind::Bench { name: name.to_string() }
@@ -53,6 +53,20 @@ fn runnable_fn(fn_def: ast::FnDef) -> Option<Runnable> {
53 Some(Runnable { range: fn_def.syntax().text_range(), kind }) 53 Some(Runnable { range: fn_def.syntax().text_range(), kind })
54} 54}
55 55
56/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
57/// `#[test_case(...)]`, `#[tokio::test]` and similar.
58/// Also a regular `#[test]` annotation is supported.
59///
60/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
61/// but it's better than not to have the runnables for the tests at all.
62fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
63 fn_def
64 .attrs()
65 .filter_map(|attr| attr.path())
66 .map(|path| path.syntax().to_string().to_lowercase())
67 .any(|attribute_text| attribute_text.contains("test"))
68}
69
56fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> { 70fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> {
57 let has_test_function = module 71 let has_test_function = module
58 .item_list()? 72 .item_list()?
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 579158780..fdf81ed87 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -14,7 +14,7 @@ serde_json = "1.0.34"
14serde = { version = "1.0.83", features = ["derive"] } 14serde = { version = "1.0.83", features = ["derive"] }
15crossbeam-channel = "0.4" 15crossbeam-channel = "0.4"
16log = "0.4.3" 16log = "0.4.3"
17lsp-types = { version = "0.69.0", features = ["proposed"] } 17lsp-types = { version = "0.70.0", features = ["proposed"] }
18rustc-hash = "1.0" 18rustc-hash = "1.0"
19parking_lot = "0.10.0" 19parking_lot = "0.10.0"
20jod-thread = "0.1.0" 20jod-thread = "0.1.0"
@@ -26,10 +26,13 @@ lsp-server = "0.3.0"
26ra_project_model = { path = "../ra_project_model" } 26ra_project_model = { path = "../ra_project_model" }
27ra_prof = { path = "../ra_prof" } 27ra_prof = { path = "../ra_prof" }
28ra_vfs_glob = { path = "../ra_vfs_glob" } 28ra_vfs_glob = { path = "../ra_vfs_glob" }
29env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] } 29env_logger = { version = "0.7.1", default-features = false }
30ra_cargo_watch = { path = "../ra_cargo_watch" } 30ra_cargo_watch = { path = "../ra_cargo_watch" }
31either = "1.5" 31either = "1.5"
32 32
33[target.'cfg(windows)'.dependencies]
34winapi = "0.3"
35
33[dev-dependencies] 36[dev-dependencies]
34tempfile = "3" 37tempfile = "3"
35test_utils = { path = "../test_utils" } 38test_utils = { path = "../test_utils" }
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 7822be2e2..15bf519c9 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -29,9 +29,6 @@ use crate::{
29 Result, ServerConfig, 29 Result, ServerConfig,
30}; 30};
31 31
32const THREADPOOL_SIZE: usize = 8;
33const MAX_IN_FLIGHT_LIBS: usize = THREADPOOL_SIZE - 3;
34
35#[derive(Debug)] 32#[derive(Debug)]
36pub struct LspError { 33pub struct LspError {
37 pub code: i32, 34 pub code: i32,
@@ -60,6 +57,25 @@ pub fn main_loop(
60) -> Result<()> { 57) -> Result<()> {
61 log::info!("server_config: {:#?}", config); 58 log::info!("server_config: {:#?}", config);
62 59
60 // Windows scheduler implements priority boosts: if thread waits for an
61 // event (like a condvar), and event fires, priority of the thread is
62 // temporary bumped. This optimization backfires in our case: each time the
63 // `main_loop` schedules a task to run on a threadpool, the worker threads
64 // gets a higher priority, and (on a machine with fewer cores) displaces the
65 // main loop! We work-around this by marking the main loop as a
66 // higher-priority thread.
67 //
68 // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
69 // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts
70 // https://github.com/rust-analyzer/rust-analyzer/issues/2835
71 #[cfg(windows)]
72 unsafe {
73 use winapi::um::processthreadsapi::*;
74 let thread = GetCurrentThread();
75 let thread_priority_above_normal = 1;
76 SetThreadPriority(thread, thread_priority_above_normal);
77 }
78
63 let mut loop_state = LoopState::default(); 79 let mut loop_state = LoopState::default();
64 let mut world_state = { 80 let mut world_state = {
65 let feature_flags = { 81 let feature_flags = {
@@ -168,7 +184,7 @@ pub fn main_loop(
168 ) 184 )
169 }; 185 };
170 186
171 let pool = ThreadPool::new(THREADPOOL_SIZE); 187 let pool = ThreadPool::default();
172 let (task_sender, task_receiver) = unbounded::<Task>(); 188 let (task_sender, task_receiver) = unbounded::<Task>();
173 let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>(); 189 let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>();
174 190
@@ -210,7 +226,7 @@ pub fn main_loop(
210 )?; 226 )?;
211 } 227 }
212 } 228 }
213 229 world_state.analysis_host.request_cancellation();
214 log::info!("waiting for tasks to finish..."); 230 log::info!("waiting for tasks to finish...");
215 task_receiver.into_iter().for_each(|task| { 231 task_receiver.into_iter().for_each(|task| {
216 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state) 232 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state)
@@ -371,7 +387,8 @@ fn loop_turn(
371 loop_state.pending_libraries.extend(changes); 387 loop_state.pending_libraries.extend(changes);
372 } 388 }
373 389
374 while loop_state.in_flight_libraries < MAX_IN_FLIGHT_LIBS 390 let max_in_flight_libs = pool.max_count().saturating_sub(2).max(1);
391 while loop_state.in_flight_libraries < max_in_flight_libs
375 && !loop_state.pending_libraries.is_empty() 392 && !loop_state.pending_libraries.is_empty()
376 { 393 {
377 let (root, files) = loop_state.pending_libraries.pop().unwrap(); 394 let (root, files) = loop_state.pending_libraries.pop().unwrap();
@@ -586,12 +603,14 @@ fn on_notification(
586 603
587fn on_check_task( 604fn on_check_task(
588 task: CheckTask, 605 task: CheckTask,
589 world_state: &WorldState, 606 world_state: &mut WorldState,
590 task_sender: &Sender<Task>, 607 task_sender: &Sender<Task>,
591) -> Result<()> { 608) -> Result<()> {
592 match task { 609 match task {
593 CheckTask::ClearDiagnostics => { 610 CheckTask::ClearDiagnostics => {
594 let cleared_files = world_state.check_watcher.state.write().clear(); 611 let state = Arc::get_mut(&mut world_state.check_watcher.state)
612 .expect("couldn't get check watcher state as mutable");
613 let cleared_files = state.clear();
595 614
596 // Send updated diagnostics for each cleared file 615 // Send updated diagnostics for each cleared file
597 for url in cleared_files { 616 for url in cleared_files {
@@ -600,11 +619,9 @@ fn on_check_task(
600 } 619 }
601 620
602 CheckTask::AddDiagnostic(url, diagnostic) => { 621 CheckTask::AddDiagnostic(url, diagnostic) => {
603 world_state 622 let state = Arc::get_mut(&mut world_state.check_watcher.state)
604 .check_watcher 623 .expect("couldn't get check watcher state as mutable");
605 .state 624 state.add_diagnostic_with_fixes(url.clone(), diagnostic);
606 .write()
607 .add_diagnostic_with_fixes(url.clone(), diagnostic);
608 625
609 // We manually send a diagnostic update when the watcher asks 626 // We manually send a diagnostic update when the watcher asks
610 // us to, to avoid the issue of having to change the file to 627 // us to, to avoid the issue of having to change the file to
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 8e43f0575..666f2ee29 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -674,8 +674,7 @@ pub fn handle_code_action(
674 res.push(action.into()); 674 res.push(action.into());
675 } 675 }
676 676
677 for fix in world.check_watcher.read().fixes_for(&params.text_document.uri).into_iter().flatten() 677 for fix in world.check_watcher.fixes_for(&params.text_document.uri).into_iter().flatten() {
678 {
679 let fix_range = fix.location.range.conv_with(&line_index); 678 let fix_range = fix.location.range.conv_with(&line_index);
680 if fix_range.intersection(&range).is_none() { 679 if fix_range.intersection(&range).is_none() {
681 continue; 680 continue;
@@ -895,7 +894,7 @@ pub fn publish_diagnostics(
895 tags: None, 894 tags: None,
896 }) 895 })
897 .collect(); 896 .collect();
898 if let Some(check_diags) = world.check_watcher.read().diagnostics_for(&uri) { 897 if let Some(check_diags) = world.check_watcher.diagnostics_for(&uri) {
899 diagnostics.extend(check_diags.iter().cloned()); 898 diagnostics.extend(check_diags.iter().cloned());
900 } 899 }
901 Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None }) 900 Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None })
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index e7a0acfc7..3059ef9ec 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -63,7 +63,7 @@ pub struct WorldSnapshot {
63 pub workspaces: Arc<Vec<ProjectWorkspace>>, 63 pub workspaces: Arc<Vec<ProjectWorkspace>>,
64 pub analysis: Analysis, 64 pub analysis: Analysis,
65 pub latest_requests: Arc<RwLock<LatestRequests>>, 65 pub latest_requests: Arc<RwLock<LatestRequests>>,
66 pub check_watcher: Arc<RwLock<CheckState>>, 66 pub check_watcher: CheckState,
67 vfs: Arc<RwLock<Vfs>>, 67 vfs: Arc<RwLock<Vfs>>,
68} 68}
69 69
@@ -220,7 +220,7 @@ impl WorldState {
220 analysis: self.analysis_host.analysis(), 220 analysis: self.analysis_host.analysis(),
221 vfs: Arc::clone(&self.vfs), 221 vfs: Arc::clone(&self.vfs),
222 latest_requests: Arc::clone(&self.latest_requests), 222 latest_requests: Arc::clone(&self.latest_requests),
223 check_watcher: self.check_watcher.state.clone(), 223 check_watcher: (*self.check_watcher.state).clone(),
224 } 224 }
225 } 225 }
226 226
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs
index 65134277e..81055746b 100644
--- a/crates/ra_parser/src/lib.rs
+++ b/crates/ra_parser/src/lib.rs
@@ -27,7 +27,7 @@ pub use syntax_kind::SyntaxKind;
27#[derive(Debug, Clone, PartialEq, Eq, Hash)] 27#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28pub struct ParseError(pub String); 28pub struct ParseError(pub String);
29 29
30/// `TokenSource` abstracts the source of the tokens parser operates one. 30/// `TokenSource` abstracts the source of the tokens parser operates on.
31/// 31///
32/// Hopefully this will allow us to treat text and token trees in the same way! 32/// Hopefully this will allow us to treat text and token trees in the same way!
33pub trait TokenSource { 33pub trait TokenSource {
@@ -43,7 +43,7 @@ pub trait TokenSource {
43 fn is_keyword(&self, kw: &str) -> bool; 43 fn is_keyword(&self, kw: &str) -> bool;
44} 44}
45 45
46/// `TokenCursor` abstracts the cursor of `TokenSource` operates one. 46/// `Token` abstracts the cursor of `TokenSource` operates on.
47#[derive(Debug, Copy, Clone, Eq, PartialEq)] 47#[derive(Debug, Copy, Clone, Eq, PartialEq)]
48pub struct Token { 48pub struct Token {
49 /// What is the current token? 49 /// What is the current token?
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index da541005a..c7973ddf4 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -106,6 +106,21 @@ pub fn profile(desc: &str) -> Profiler {
106 }) 106 })
107} 107}
108 108
109pub fn print_time(desc: &str) -> impl Drop + '_ {
110 struct Guard<'a> {
111 desc: &'a str,
112 start: Instant,
113 }
114
115 impl Drop for Guard<'_> {
116 fn drop(&mut self) {
117 eprintln!("{}: {:?}", self.desc, self.start.elapsed())
118 }
119 }
120
121 Guard { desc, start: Instant::now() }
122}
123
109pub struct Profiler { 124pub struct Profiler {
110 desc: Option<String>, 125 desc: Option<String>,
111} 126}
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index 6da4b1309..539759450 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -305,44 +305,39 @@ impl ast::Literal {
305 .unwrap() 305 .unwrap()
306 } 306 }
307 307
308 fn find_suffix(text: &str, possible_suffixes: &[&str]) -> Option<SmolStr> {
309 possible_suffixes
310 .iter()
311 .find(|&suffix| text.ends_with(suffix))
312 .map(|&suffix| SmolStr::new(suffix))
313 }
314
308 pub fn kind(&self) -> LiteralKind { 315 pub fn kind(&self) -> LiteralKind {
309 match self.token().kind() { 316 const INT_SUFFIXES: [&'static str; 12] = [
310 INT_NUMBER => { 317 "u64", "u32", "u16", "u8", "usize", "isize", "i64", "i32", "i16", "i8", "u128", "i128",
311 let int_suffix_list = [ 318 ];
312 "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", 319 const FLOAT_SUFFIXES: [&'static str; 2] = ["f32", "f64"];
313 "u16", "u8",
314 ];
315 320
321 let token = self.token();
322
323 match token.kind() {
324 INT_NUMBER => {
325 // FYI: there was a bug here previously, thus an if statement bellow is necessary.
316 // The lexer treats e.g. `1f64` as an integer literal. See 326 // The lexer treats e.g. `1f64` as an integer literal. See
317 // https://github.com/rust-analyzer/rust-analyzer/issues/1592 327 // https://github.com/rust-analyzer/rust-analyzer/issues/1592
318 // and the comments on the linked PR. 328 // and the comments on the linked PR.
319 let float_suffix_list = ["f32", "f64"];
320
321 let text = self.token().text().to_string();
322 329
323 let float_suffix = float_suffix_list 330 let text = token.text();
324 .iter()
325 .find(|&s| text.ends_with(s))
326 .map(|&suf| SmolStr::new(suf));
327 331
328 if float_suffix.is_some() { 332 if let suffix @ Some(_) = Self::find_suffix(&text, &FLOAT_SUFFIXES) {
329 LiteralKind::FloatNumber { suffix: float_suffix } 333 LiteralKind::FloatNumber { suffix }
330 } else { 334 } else {
331 let suffix = int_suffix_list 335 LiteralKind::IntNumber { suffix: Self::find_suffix(&text, &INT_SUFFIXES) }
332 .iter()
333 .find(|&s| text.ends_with(s))
334 .map(|&suf| SmolStr::new(suf));
335 LiteralKind::IntNumber { suffix }
336 } 336 }
337 } 337 }
338 FLOAT_NUMBER => { 338 FLOAT_NUMBER => {
339 let allowed_suffix_list = ["f64", "f32"]; 339 let text = token.text();
340 let text = self.token().text().to_string(); 340 LiteralKind::FloatNumber { suffix: Self::find_suffix(&text, &FLOAT_SUFFIXES) }
341 let suffix = allowed_suffix_list
342 .iter()
343 .find(|&s| text.ends_with(s))
344 .map(|&suf| SmolStr::new(suf));
345 LiteralKind::FloatNumber { suffix }
346 } 341 }
347 STRING | RAW_STRING => LiteralKind::String, 342 STRING | RAW_STRING => LiteralKind::String,
348 T![true] | T![false] => LiteralKind::Bool, 343 T![true] | T![false] => LiteralKind::Bool,
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index d9666cdca..cb0aee422 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -234,6 +234,10 @@ impl ast::LetStmt {
234 Some(node) => node.kind() == T![;], 234 Some(node) => node.kind() == T![;],
235 } 235 }
236 } 236 }
237
238 pub fn eq_token(&self) -> Option<SyntaxToken> {
239 self.syntax().children_with_tokens().find(|t| t.kind() == EQ).and_then(|it| it.into_token())
240 }
237} 241}
238 242
239impl ast::ExprStmt { 243impl ast::ExprStmt {
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md
new file mode 100644
index 000000000..0a4554c55
--- /dev/null
+++ b/docs/dev/syntax.md
@@ -0,0 +1,535 @@
1# Syntax in rust-analyzer
2
3## About the guide
4
5This guide describes the current state of syntax trees and parsing in rust-analyzer as of 2020-01-09 ([link to commit](https://github.com/rust-analyzer/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6)).
6
7## Source Code
8
9The things described are implemented in two places
10
11* [rowan](https://github.com/rust-analyzer/rowan/tree/v0.9.0) -- a generic library for rowan syntax trees.
12* [ra_syntax](https://github.com/rust-analyzer/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API.
13 Nothing in rust-analyzer except this crate knows about `rowan`.
14* [ra_parser](https://github.com/rust-analyzer/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_parser) crate parses input tokens into an `ra_syntax` tree
15
16## Design Goals
17
18* Syntax trees are lossless, or full fidelity. All comments and whitespace are preserved.
19* Syntax trees are semantic-less. They describe *strictly* the structure of a sequence of characters, they don't have hygiene, name resolution or type information attached.
20* Syntax trees are simple value type. It is possible to create trees for a syntax without any external context.
21* Syntax trees have intuitive traversal API (parent, children, siblings, etc).
22* Parsing is lossless (even if the input is invalid, the tree produced by the parser represents it exactly).
23* Parsing is resilient (even if the input is invalid, parser tries to see as much syntax tree fragments in the input as it can).
24* Performance is important, it's OK to use `unsafe` if it means better memory/cpu usage.
25* Keep the parser and the syntax tree isolated from each other, such that they can vary independently.
26
27## Trees
28
29### Overview
30
31The syntax tree consists of three layers:
32
33* GreenNodes
34* SyntaxNodes (aka RedNode)
35* AST
36
37Of these, only GreenNodes store the actual data, the other two layers are (non-trivial) views into green tree.
38Red-green terminology comes from Roslyn ([link](https://docs.microsoft.com/en-ie/archive/blogs/ericlippert/persistence-facades-and-roslyns-red-green-trees)) and gives the name to the `rowan` library. Green and syntax nodes are defined in rowan, ast is defined in rust-analyzer.
39
40Syntax trees are a semi-transient data structure.
41In general, frontend does not keep syntax trees for all files in memory.
42Instead, it *lowers* syntax trees to more compact and rigid representation, which is not full-fidelity, but which can be mapped back to a syntax tree if so desired.
43
44
45### GreenNode
46
47GreenNode is a purely-functional tree with arbitrary arity. Conceptually, it is equivalent to the following run of the mill struct:
48
49```rust
50#[derive(PartialEq, Eq, Clone, Copy)]
51struct SyntaxKind(u16);
52
53#[derive(PartialEq, Eq, Clone)]
54struct Node {
55 kind: SyntaxKind,
56 text_len: usize,
57 children: Vec<Arc<Either<Node, Token>>>,
58}
59
60#[derive(PartialEq, Eq, Clone)]
61struct Token {
62 kind: SyntaxKind,
63 text: String,
64}
65```
66
67All the difference bettwen the above sketch and the real implementation are strictly due to optimizations.
68
69Points of note:
70* The tree is untyped. Each node has a "type tag", `SyntaxKind`.
71* Interior and leaf nodes are distinguished on the type level.
72* Trivia and non-trivia tokens are not distinguished on the type level.
73* Each token carries its full text.
74* The original text can be recovered by concatenating the texts of all tokens in order.
75* Accessing a child of particular type (for example, parameter list of a function) generarly involves linerary traversing the children, looking for a specific `kind`.
76* Modifying the tree is roughly `O(depth)`.
77 We don't make special efforts to guarantree that the depth is not liner, but, in practice, syntax trees are branchy and shallow.
78* If mandatory (grammar wise) node is missing from the input, it's just missing from the tree.
79* If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node.
80* Parser errors are not a part of syntax tree.
81
82An input like `fn f() { 90 + 2 }` might be parsed as
83
84```
85FN_DEF@[0; 17)
86 FN_KW@[0; 2) "fn"
87 WHITESPACE@[2; 3) " "
88 NAME@[3; 4)
89 IDENT@[3; 4) "f"
90 PARAM_LIST@[4; 6)
91 L_PAREN@[4; 5) "("
92 R_PAREN@[5; 6) ")"
93 WHITESPACE@[6; 7) " "
94 BLOCK_EXPR@[7; 17)
95 BLOCK@[7; 17)
96 L_CURLY@[7; 8) "{"
97 WHITESPACE@[8; 9) " "
98 BIN_EXPR@[9; 15)
99 LITERAL@[9; 11)
100 INT_NUMBER@[9; 11) "90"
101 WHITESPACE@[11; 12) " "
102 PLUS@[12; 13) "+"
103 WHITESPACE@[13; 14) " "
104 LITERAL@[14; 15)
105 INT_NUMBER@[14; 15) "2"
106 WHITESPACE@[15; 16) " "
107 R_CURLY@[16; 17) "}"
108```
109
110#### Optimizations
111
112(significant amount of implementation work here was done by [CAD97](https://github.com/cad97)).
113
114To reduce the amount of allocations, the GreenNode is a DST, which uses a single allocation for header and children. Thus, it is only usable behind a pointer
115
116```
117*-----------+------+----------+------------+--------+--------+-----+--------*
118| ref_count | kind | text_len | n_children | child1 | child2 | ... | childn |
119*-----------+------+----------+------------+--------+--------+-----+--------*
120```
121
122To more compactly store the children, we box *both* interior nodes and tokens, and represent
123`Either<Arc<Node>, Arc<Token>>` as a single pointer with a tag in the last bit.
124
125To avoid allocating EVERY SINGLE TOKEN on the heap, syntax trees use interning.
126Because the tree is fully imutable, it's valid to structuraly share subtrees.
127For example, in `1 + 1`, there will be a *single* token for `1` with ref count 2; the same goes for the ` ` whitespace token.
128Interior nodes are shared as well (for example in `(1 + 1) * (1 + 1)`).
129
130Note that, the result of the interning is an `Arc<Node>`.
131That is, it's not an index into interning table, so you don't have to have the table around to do anything with the tree.
132Each tree is fully self-contained (although different trees might share parts).
133Currently, the interner is created per-file, but it will be easy to use a per-thread or per-some-contex one.
134
135We use a `TextUnit`, a newtyped `u32`, to store the length of the text.
136
137We currently use `SmolStr`, an small object optimized string to store text.
138This was mostly relevant *before* we implmented tree interning, to avoid allocating common keywords and identifiers. We should switch to storing text data alongside the interned tokens.
139
140#### Alternative designs
141
142##### Dealing with trivia
143
144In the above model, whitespace is not treated specially.
145Another alternative (used by swift and roslyn) is to explicitly divide the set of tokens into trivia and non-trivia tokens, and represent non-trivia tokens as
146
147```rust
148struct Token {
149 kind: NonTriviaTokenKind
150 text: String,
151 leading_trivia: Vec<TriviaToken>,
152 trailing_trivia: Vec<TriviaToken>,
153}
154```
155
156The tree then contains only non-trivia tokens.
157
158Another approach (from Dart) is to, in addition to a syntax tree, link all the tokens into a bidirectional link list.
159That way, the tree again contains only non-trivia tokens.
160
161Explicit trivia nodes, like in `rowan`, are used by IntelliJ.
162
163##### Accessing Children
164
165As noted before, accesing a specific child in the node requires a linear traversal of the children (though we can skip tokens, beacuse the tag is encoded in the pointer itself).
166It is possible to recover O(1) access with another representation.
167We explicitly store optional and missing (required by the grammar, but not present) nodes.
168That is, we use `Option<Node>` for children.
169We also remove trivia tokens from the tree.
170This way, each child kind genrerally occupies a fixed position in a parent, and we can use index access to fetch it.
171The cost is that we now need to allocate space for all not-present optional nodes.
172So, `fn foo() {}` will have slots for visibility, unsafeness, attributes, abi and return type.
173
174IntelliJ uses linear traversal.
175Roslyn and Swift do `O(1)` access.
176
177##### Mutable Trees
178
179IntelliJ uses mutable trees.
180Overall, it creates a lot of additional complexity.
181However, the API for *editing* syntax trees is nice.
182
183For example the assist to move generic bounds to where clause has this code:
184
185```kotlin
186 for typeBound in typeBounds {
187 typeBound.typeParamBounds?.delete()
188}
189```
190
191Modeling this with immutable trees is possible, but annoying.
192
193### Syntax Nodes
194
195A function green tree is not super-convenient to use.
196The biggest problem is acessing parents (there are no parent pointers!).
197But there are also "identify" issues.
198Let's say you want to write a code which builds a list of expressions in a file: `fn collect_exrepssions(file: GreenNode) -> HashSet<GreenNode>`.
199For the input like
200
201```rust
202fn main() {
203 let x = 90i8;
204 let x = x + 2;
205 let x = 90i64;
206 let x = x + 2;
207}
208```
209
210both copies of the `x + 2` expression are representing by equal (and, with interning in mind, actualy the same) green nodes.
211Green trees just can't differentiate between the two.
212
213`SyntaxNode` adds parent pointers and identify semantics to green nodes.
214They can be called cursors or [zippers](https://en.wikipedia.org/wiki/Zipper_(data_structure)) (fun fact: zipper is a derivative (as in ′) of a data structure).
215
216Conceptually, a `SyntaxNode` looks like this:
217
218```rust
219type SyntaxNode = Arc<SyntaxData>;
220
221struct SyntaxData {
222 offset: usize,
223 parent: Option<SyntaxNode>,
224 green: Arc<GreeNode>,
225}
226
227impl SyntaxNode {
228 fn new_root(root: Arc<GreenNode>) -> SyntaxNode {
229 Arc::new(SyntaxData {
230 offset: 0,
231 parent: None,
232 green: root,
233 })
234 }
235 fn parent(&self) -> Option<SyntaxNode> {
236 self.parent.clone()
237 }
238 fn children(&self) -> impl Iterator<Item = SyntaxNode> {
239 let mut offset = self.offset
240 self.green.children().map(|green_child| {
241 let child_offset = offset;
242 offset += green_child.text_len;
243 Arc::new(SyntaxData {
244 offset: child_offset;
245 parent: Some(Arc::clone(self)),
246 green: Arc::clone(green_child),
247 })
248 })
249 }
250}
251
252impl PartialEq for SyntaxNode {
253 fn eq(&self, other: &SyntaxNode) {
254 self.offset == other.offset
255 && Arc::ptr_eq(&self.green, &other.green)
256 }
257}
258```
259
260Points of note:
261
262* SyntaxNode remembers its parent node (and, transitively, the path to the root of the tree)
263* SyntaxNode knows its *absolute* text offset in the whole file
264* Equality is based on identity. Comparing nodes from different trees does not make sense.
265
266#### Optimization
267
268The reality is different though :-)
269Traversal of trees is a common operation, and it makes sense to optimize it.
270In particular, the above code allocates and does atomic operations during a traversal.
271
272To get rid of atomics, `rowan` uses non thread-safe `Rc`.
273This is OK because trees traversals mostly (always, in case of rust-analyzer) run on a single thread. If you need to send a `SyntaxNode` to another thread, you can send a pair of **root**`GreenNode` (which is thread safe) and a `Range<usize>`.
274The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range.
275You can also use the similar trick to store a `SyntaxNode`.
276That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`.
277However rust-analyzer goes even further.
278It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`.
279The `SyntaxNode` is the restored by reparsing the file and traversing it from root.
280With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage.
281
282Additionally, only the root `SyntaxNode` owns an `Arc` to the (root) `GreenNode`.
283All other `SyntaxNode`s point to corresponding `GreenNode`s with a raw pointer.
284They also point to the parent (and, consequently, to the root) with an owning `Rc`, so this is sound.
285In other words, one needs *one* arc bump when initiating a traversal.
286
287To get rid of allocations, `rowan` takes advantage of `SyntaxNode: !Sync` and uses a thread-local free list of `SyntaxNode`s.
288In a typical traversal, you only directly hold a few `SyntaxNode`s at a time (and their ancesstors indirectly), so a free list proportional to the depth of the tree removes all allocations in a typical case.
289
290So, while traversal is not exactly incrementing a pointer, it's still prety cheep: tls + rc bump!
291
292Traversal also yields (cheap) owned nodes, which improves ergonomics quite a bit.
293
294#### Alternative Designs
295
296##### Memoized RedNodes
297
298C# and Swift follow the design where the red nodes are memoized, which would look roughly like this in Rust:
299
300```rust
301type SyntaxNode = Arc<SyntaxData>;
302
303struct SyntaxData {
304 offset: usize,
305 parent: Option<SyntaxNode>,
306 green: Arc<GreeNode>,
307 children: Vec<OnceCell<SyntaxNode>>,
308}
309```
310
311This allows using true pointer equality for comparision of identities of `SyntaxNodes`.
312rust-analyzer used to have this design as well, but since we've switch to cursors.
313The main problem with memoizing the red nodes is that it more than doubles the memory requirenments for fully realized syntax trees.
314In contrast, cursors generally retain only a path to the root.
315C# combats increased memory usage by using weak references.
316
317### AST
318
319`GreenTree`s are untyped and homogeneous, because it makes accomodating error nodes, arbitrary whitespace and comments natural, and because it makes possible to write generic tree traversals.
320However, when working with a specific node, like a function definition, one would want a strongly typed API.
321
322This is what is provided by the AST layer. AST nodes are transparent wrappers over untyped syntax nodes:
323
324```rust
325pub trait AstNode {
326 fn cast(syntax: SyntaxNode) -> Option<Self>
327 where
328 Self: Sized;
329
330 fn syntax(&self) -> &SyntaxNode;
331}
332```
333
334Concrete nodes are generated (there are 117 of them), and look roughly like this:
335
336```rust
337#[derive(Debug, Clone, PartialEq, Eq, Hash)]
338pub struct FnDef {
339 syntax: SyntaxNode,
340}
341
342impl AstNode for FnDef {
343 fn cast(syntax: SyntaxNode) -> Option<Self> {
344 match kind {
345 FN_DEF => Some(FnDef { syntax }),
346 _ => None,
347 }
348 }
349 fn syntax(&self) -> &SyntaxNode {
350 &self.syntax
351 }
352}
353
354impl FnDef {
355 pub fn param_list(&self) -> Option<ParamList> {
356 self.syntax.children().find_map(ParamList::cast)
357 }
358 pub fn ret_type(&self) -> Option<RetType> {
359 self.syntax.children().find_map(RetType::cast)
360 }
361 pub fn body(&self) -> Option<BlockExpr> {
362 self.syntax.children().find_map(BlockExpr::cast)
363 }
364 // ...
365}
366```
367
368Variants like expressions, patterns or items are modeled with `enum`s, which also implement `AstNode`:
369
370```rust
371#[derive(Debug, Clone, PartialEq, Eq, Hash)]
372pub enum AssocItem {
373 FnDef(FnDef),
374 TypeAliasDef(TypeAliasDef),
375 ConstDef(ConstDef),
376}
377
378impl AstNode for AssocItem {
379 ...
380}
381```
382
383Shared AST substructures are modeled via (object safe) traits:
384
385```rust
386trait HasVisibility: AstNode {
387 fn visibility(&self) -> Option<Visibility>;
388}
389
390impl HasVisbility for FnDef {
391 fn visibility(&self) -> Option<Visibility> {
392 self.syntax.children().find_map(Visibility::cast)
393 }
394}
395```
396
397Points of note:
398
399* Like `SyntaxNode`s, AST nodes are cheap to clone pointer-sized owned values.
400* All "fields" are optional, to accomodate incomplete and/or erroneous source code.
401* It's always possible to go from an ast node to an untyped `SyntaxNode`.
402* It's possible to go in the opposite direction with a checked cast.
403* `enum`s allow modeling of arbitrary intersecting subsets of AST types.
404* Most of rust-analyzer works with the ast layer, with notable exceptions of:
405 * macro expansion, which needs access to raw tokens and works with `SyntaxNode`s
406 * some IDE-specific features like syntax highlighting are more conveniently implemented over a homogeneous `SyntaxNode` tree
407
408#### Alternative Designs
409
410##### Semantic Full AST
411
412In IntelliJ the AST layer (dubbed **P**rogram **S**tructure **I**nterface) can have semantics attached, and is usually backed by either syntax tree, indices, or metadata from compiled libraries.
413The backend for PSI can change dynamically.
414
415### Syntax Tree Recap
416
417At its core, the syntax tree is a purely functional n-ary tree, which stores text at the leaf nodes and node "kinds" at all nodes.
418A cursor layer is added on top, which gives owned, cheap to clone nodes with identity semantics, parent links and absolute offsets.
419An AST layer is added on top, which reifies each node `Kind` as a separate Rust type with the corresponding API.
420
421## Parsing
422
423The (green) tree is constructed by a DFS "traversal" of the desired tree structure:
424
425```rust
426pub struct GreenNodeBuilder { ... }
427
428impl GreenNodeBuilder {
429 pub fn new() -> GreenNodeBuilder { ... }
430
431 pub fn token(&mut self, kind: SyntaxKind, text: &str) { ... }
432
433 pub fn start_node(&mut self, kind: SyntaxKind) { ... }
434 pub fn finish_node(&mut self) { ... }
435
436 pub fn finish(self) -> GreenNode { ... }
437}
438```
439
440The parser, ultimatelly, needs to invoke the `GreenNodeBuilder`.
441There are two principal sources of inputs for the parser:
442 * source text, which contains trivia tokens (whitespace and comments)
443 * token trees from macros, which lack trivia
444
445Additionaly, input tokens do not correspond 1-to-1 with output tokens.
446For example, two consequtive `>` tokens might be glued, by the parser, into a single `>>`.
447
448For these reasons, the parser crate defines a callback interfaces for both input tokens and output trees.
449The explicit glue layer then bridges various gaps.
450
451The parser interface looks like this:
452
453```rust
454pub struct Token {
455 pub kind: SyntaxKind,
456 pub is_joined_to_next: bool,
457}
458
459pub trait TokenSource {
460 fn current(&self) -> Token;
461 fn lookahead_nth(&self, n: usize) -> Token;
462 fn is_keyword(&self, kw: &str) -> bool;
463
464 fn bump(&mut self);
465}
466
467pub trait TreeSink {
468 fn token(&mut self, kind: SyntaxKind, n_tokens: u8);
469
470 fn start_node(&mut self, kind: SyntaxKind);
471 fn finish_node(&mut self);
472
473 fn error(&mut self, error: ParseError);
474}
475
476pub fn parse(
477 token_source: &mut dyn TokenSource,
478 tree_sink: &mut dyn TreeSink,
479) { ... }
480```
481
482Points of note:
483
484* The parser and the syntax tree are independent, they live in different crates neither of which depends on the other.
485* The parser doesn't know anything about textual contents of the tokens, with an isolated hack for checking contextual keywords.
486* For gluing tokens, the `TreeSink::token` might advance further than one atomic token ahead.
487
488### Reporting Syntax Errors
489
490Syntax errors are not stored directly in the tree.
491The primary motivation for this is that syntax tree is not necessary produced by the parser, it may also be assembled manually from pieces (which happens all the time in refactorings).
492Instead, parser reports errors to an error sink, which stores them in a `Vec`.
493If possible, errors are not reported during parsing and are postponed for a separate validation step.
494For example, parser accepts visibility modifiers on trait methods, but then a separate tree traversal flags all such visibilites as erroneous.
495
496### Macros
497
498The primary difficulty with macros is that individual tokens have identities, which need to be preserved in the syntax tree for hygiene purposes.
499This is handled by the `TreeSink` layer.
500Specifically, `TreeSink` constructs the tree in lockstep with draining the original token stream.
501In the process, it records which tokens of the tree correspond to which tokens of the input, by using text ranges to identify syntax tokens.
502The end result is that parsing an expanded code yields a syntax tree and a mapping of text-ranges of the tree to original tokens.
503
504To deal with precedence in cases like `$expr * 1`, we use special invisible parenthesis, which are explicitelly handled by the parser
505
506### Whitespace & Comments
507
508Parser does not see whitespace nodes.
509Instead, they are attached to the tree in the `TreeSink` layer.
510
511For example, in
512
513```rust
514// non doc comment
515fn foo() {}
516```
517
518the comment will be (heuristically) made a child of function node.
519
520### Incremental Reparse
521
522Green trees are cheap to modify, so incremental reparse works by patching a previous tree, without maintaining any additional state.
523The reparse is based on heuristic: we try to contain a change to a single `{}` block, and reparse only this block.
524To do this, we maintain the invariant that, even for invalid code, curly braces are always paired correctly.
525
526In practice, incremental reparsing doesn't actually matter much for IDE use-cases, parsing from scratch seems to be fast enough.
527
528### Parsing Algorithm
529
530We use a boring hand-crafted recursive descent + pratt combination, with a special effort of continuting the parsing if an error is detected.
531
532### Parser Recap
533
534Parser itself defines traits for token sequence input and syntax tree output.
535It doesn't care about where the tokens come from, and how the resulting syntax tree looks like.
diff --git a/docs/user/assists.md b/docs/user/assists.md
index ecf206f71..c36c5df6a 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -209,6 +209,24 @@ fn main() {
209} 209}
210``` 210```
211 211
212## `auto_import`
213
214If the name is unresolved, provides all possible imports for it.
215
216```rust
217// BEFORE
218fn main() {
219 let map = HashMap┃::new();
220}
221
222// AFTER
223use std::collections::HashMap;
224
225fn main() {
226 let map = HashMap┃::new();
227}
228```
229
212## `change_visibility` 230## `change_visibility`
213 231
214Adds or changes existing visibility specifier. 232Adds or changes existing visibility specifier.
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 05c57c7ff..b81cf3820 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -889,25 +889,25 @@
889 } 889 }
890 }, 890 },
891 "vscode-jsonrpc": { 891 "vscode-jsonrpc": {
892 "version": "5.0.0", 892 "version": "5.0.1",
893 "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0.tgz", 893 "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz",
894 "integrity": "sha512-QeAniC/xTWauVQgyNgEqNJ0Qm/Jw8QySGRQhRFPwb8c4FPp9k6QNgJp0ayXWws5qhdaHkiXkGPlzjOPZFQQKLw==" 894 "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A=="
895 }, 895 },
896 "vscode-languageclient": { 896 "vscode-languageclient": {
897 "version": "6.0.0", 897 "version": "6.0.1",
898 "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.0.0.tgz", 898 "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.0.1.tgz",
899 "integrity": "sha512-6MDksAP79GRbcHFsXS6ndo12s0m/h7eNdS/IanRgWxaezqB4a4KzHIHrE0bE+nSFB+snaSToGs1bxnPeKdO5fQ==", 899 "integrity": "sha512-7yZaSHichTJEyOJykI2RLQEECf9MqNLoklzC/1OVi/M8ioIsWQ1+lkN1nTsUhd6+F7p9ar9dNmPiEhL0i5uUBA==",
900 "requires": { 900 "requires": {
901 "semver": "^6.3.0", 901 "semver": "^6.3.0",
902 "vscode-languageserver-protocol": "^3.15.0" 902 "vscode-languageserver-protocol": "^3.15.1"
903 } 903 }
904 }, 904 },
905 "vscode-languageserver-protocol": { 905 "vscode-languageserver-protocol": {
906 "version": "3.15.0", 906 "version": "3.15.1",
907 "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0.tgz", 907 "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.1.tgz",
908 "integrity": "sha512-PZEopQzHR3Lo422HeDxCpGN0sYz+kReO+du3F/AcFT1cCPunoVsDJv7ikEolFRKEn+hEIZiAaIX4yoSZ+ip5Nw==", 908 "integrity": "sha512-wJAo06VM9ZBnRqslplDjfz6Tdive0O7z44yNxBFA3x0/YZkXBIL6I+9rwQ/9Y//0X0eCh12FQrj+KmEXf2L5eA==",
909 "requires": { 909 "requires": {
910 "vscode-jsonrpc": "^5.0.0", 910 "vscode-jsonrpc": "^5.0.1",
911 "vscode-languageserver-types": "3.15.0" 911 "vscode-languageserver-types": "3.15.0"
912 } 912 }
913 }, 913 },
diff --git a/editors/code/package.json b/editors/code/package.json
index d4c310734..cd9c99b35 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -25,7 +25,7 @@
25 "dependencies": { 25 "dependencies": {
26 "jsonc-parser": "^2.1.0", 26 "jsonc-parser": "^2.1.0",
27 "seedrandom": "^3.0.5", 27 "seedrandom": "^3.0.5",
28 "vscode-languageclient": "^6.0.0" 28 "vscode-languageclient": "^6.0.1"
29 }, 29 },
30 "devDependencies": { 30 "devDependencies": {
31 "@rollup/plugin-commonjs": "^11.0.0", 31 "@rollup/plugin-commonjs": "^11.0.0",