aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yaml6
-rw-r--r--Cargo.lock40
-rw-r--r--README.md5
-rw-r--r--crates/ra_assists/src/assists/auto_import.rs46
-rw-r--r--crates/ra_cargo_watch/Cargo.toml1
-rw-r--r--crates/ra_cargo_watch/src/lib.rs44
-rw-r--r--crates/ra_hir/src/db.rs22
-rw-r--r--crates/ra_hir_def/src/find_path.rs99
-rw-r--r--crates/ra_hir_def/src/marks.rs1
-rw-r--r--crates/ra_hir_def/src/nameres.rs40
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs43
-rw-r--r--crates/ra_hir_expand/src/name.rs2
-rw-r--r--crates/ra_hir_ty/src/lib.rs2
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs96
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs8
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs70
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs2
-rw-r--r--crates/ra_ide/src/change.rs51
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs92
-rw-r--r--crates/ra_prof/src/lib.rs117
-rw-r--r--crates/test_utils/src/lib.rs82
-rw-r--r--crates/test_utils/src/marks.rs2
-rw-r--r--docs/dev/README.md88
-rw-r--r--docs/dev/architecture.md79
-rw-r--r--docs/dev/debugging.md2
-rw-r--r--editors/code/package-lock.json82
-rw-r--r--editors/code/package.json12
-rw-r--r--editors/code/src/client.ts8
28 files changed, 668 insertions, 474 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 395ce1ef4..77c92512a 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -1,4 +1,4 @@
1name: CI-Release 1name: release
2on: 2on:
3 push: 3 push:
4 branches: 4 branches:
@@ -132,7 +132,9 @@ jobs:
132 132
133 - name: Create Release 133 - name: Create Release
134 id: create_release 134 id: create_release
135 uses: actions/create-release@v1 135 # uses: actions/create-release@v1
136 # https://github.com/actions/create-release/pull/32
137 uses: fleskesvor/create-release@1a72e235c178bf2ae6c51a8ae36febc24568c5fe
136 env: 138 env:
137 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 139 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
138 with: 140 with:
diff --git a/Cargo.lock b/Cargo.lock
index 01e86ab0e..8c88f46ed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,7 +2,7 @@
2# It is not intended for manual editing. 2# It is not intended for manual editing.
3[[package]] 3[[package]]
4name = "aho-corasick" 4name = "aho-corasick"
5version = "0.7.6" 5version = "0.7.7"
6source = "registry+https://github.com/rust-lang/crates.io-index" 6source = "registry+https://github.com/rust-lang/crates.io-index"
7dependencies = [ 7dependencies = [
8 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 8 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -45,7 +45,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
45 45
46[[package]] 46[[package]]
47name = "backtrace" 47name = "backtrace"
48version = "0.3.42" 48version = "0.3.43"
49source = "registry+https://github.com/rust-lang/crates.io-index" 49source = "registry+https://github.com/rust-lang/crates.io-index"
50dependencies = [ 50dependencies = [
51 "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 51 "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -300,7 +300,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
300 300
301[[package]] 301[[package]]
302name = "dtoa" 302name = "dtoa"
303version = "0.4.4" 303version = "0.4.5"
304source = "registry+https://github.com/rust-lang/crates.io-index" 304source = "registry+https://github.com/rust-lang/crates.io-index"
305 305
306[[package]] 306[[package]]
@@ -419,7 +419,7 @@ name = "globset"
419version = "0.4.4" 419version = "0.4.4"
420source = "registry+https://github.com/rust-lang/crates.io-index" 420source = "registry+https://github.com/rust-lang/crates.io-index"
421dependencies = [ 421dependencies = [
422 "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", 422 "aho-corasick 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
423 "bstr 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", 423 "bstr 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
424 "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)",
425 "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)",
@@ -614,7 +614,7 @@ dependencies = [
614 614
615[[package]] 615[[package]]
616name = "lsp-types" 616name = "lsp-types"
617version = "0.70.0" 617version = "0.70.1"
618source = "registry+https://github.com/rust-lang/crates.io-index" 618source = "registry+https://github.com/rust-lang/crates.io-index"
619dependencies = [ 619dependencies = [
620 "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 620 "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -755,7 +755,7 @@ dependencies = [
755 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 755 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
756 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 756 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
757 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 757 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
758 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 758 "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
759 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 759 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
760] 760]
761 761
@@ -895,7 +895,7 @@ dependencies = [
895 "insta 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 895 "insta 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
896 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 896 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
897 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 897 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
898 "lsp-types 0.70.0 (registry+https://github.com/rust-lang/crates.io-index)", 898 "lsp-types 0.70.1 (registry+https://github.com/rust-lang/crates.io-index)",
899 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 899 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
900 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", 900 "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
901] 901]
@@ -1061,7 +1061,7 @@ dependencies = [
1061 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1061 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1062 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1062 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1063 "lsp-server 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1063 "lsp-server 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1064 "lsp-types 0.70.0 (registry+https://github.com/rust-lang/crates.io-index)", 1064 "lsp-types 0.70.1 (registry+https://github.com/rust-lang/crates.io-index)",
1065 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 1065 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
1066 "ra_cargo_watch 0.1.0", 1066 "ra_cargo_watch 0.1.0",
1067 "ra_ide 0.1.0", 1067 "ra_ide 0.1.0",
@@ -1090,7 +1090,7 @@ dependencies = [
1090 "ra_syntax 0.1.0", 1090 "ra_syntax 0.1.0",
1091 "ra_tt 0.1.0", 1091 "ra_tt 0.1.0",
1092 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1092 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1093 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1093 "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1094 "test_utils 0.1.0", 1094 "test_utils 0.1.0",
1095] 1095]
1096 1096
@@ -1105,7 +1105,7 @@ dependencies = [
1105name = "ra_prof" 1105name = "ra_prof"
1106version = "0.1.0" 1106version = "0.1.0"
1107dependencies = [ 1107dependencies = [
1108 "backtrace 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)", 1108 "backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
1109 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 1109 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
1110 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 1110 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
1111 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 1111 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1365,7 +1365,7 @@ name = "regex"
1365version = "1.3.3" 1365version = "1.3.3"
1366source = "registry+https://github.com/rust-lang/crates.io-index" 1366source = "registry+https://github.com/rust-lang/crates.io-index"
1367dependencies = [ 1367dependencies = [
1368 "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", 1368 "aho-corasick 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
1369 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1369 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
1370 "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 1370 "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
1371 "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1371 "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1446,7 +1446,7 @@ dependencies = [
1446 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 1446 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
1447 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1447 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1448 "salsa-macros 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", 1448 "salsa-macros 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
1449 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1449 "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1450] 1450]
1451 1451
1452[[package]] 1452[[package]]
@@ -1530,7 +1530,7 @@ name = "serde_yaml"
1530version = "0.8.11" 1530version = "0.8.11"
1531source = "registry+https://github.com/rust-lang/crates.io-index" 1531source = "registry+https://github.com/rust-lang/crates.io-index"
1532dependencies = [ 1532dependencies = [
1533 "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 1533 "dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
1534 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1534 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1535 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 1535 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1536 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 1536 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1543,7 +1543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1543 1543
1544[[package]] 1544[[package]]
1545name = "smallvec" 1545name = "smallvec"
1546version = "1.1.0" 1546version = "1.2.0"
1547source = "registry+https://github.com/rust-lang/crates.io-index" 1547source = "registry+https://github.com/rust-lang/crates.io-index"
1548 1548
1549[[package]] 1549[[package]]
@@ -1646,7 +1646,7 @@ name = "unicode-normalization"
1646version = "0.1.12" 1646version = "0.1.12"
1647source = "registry+https://github.com/rust-lang/crates.io-index" 1647source = "registry+https://github.com/rust-lang/crates.io-index"
1648dependencies = [ 1648dependencies = [
1649 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1649 "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1650] 1650]
1651 1651
1652[[package]] 1652[[package]]
@@ -1756,14 +1756,14 @@ dependencies = [
1756] 1756]
1757 1757
1758[metadata] 1758[metadata]
1759"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" 1759"checksum aho-corasick 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5f56c476256dc249def911d6f7580b5fc7e875895b5d7ee88f5d602208035744"
1760"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" 1760"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
1761"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" 1761"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
1762"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 1762"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
1763"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 1763"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
1764"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 1764"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
1765"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 1765"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
1766"checksum backtrace 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b4b1549d804b6c73f4817df2ba073709e96e426f12987127c48e6745568c350b" 1766"checksum backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "7f80256bc78f67e7df7e36d77366f636ed976895d91fe2ab9efa3973e8fe8c4f"
1767"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" 1767"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
1768"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" 1768"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
1769"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" 1769"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
@@ -1792,7 +1792,7 @@ dependencies = [
1792"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" 1792"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
1793"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 1793"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
1794"checksum drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f" 1794"checksum drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f"
1795"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" 1795"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
1796"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" 1796"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
1797"checksum ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36" 1797"checksum ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36"
1798"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 1798"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
@@ -1834,7 +1834,7 @@ dependencies = [
1834"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" 1834"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b"
1835"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 1835"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
1836"checksum lsp-server 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5383e043329615624bbf45e1ba27bd75c176762b2592855c659bc28ac580a06b" 1836"checksum lsp-server 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5383e043329615624bbf45e1ba27bd75c176762b2592855c659bc28ac580a06b"
1837"checksum lsp-types 0.70.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef197b24cb3f12fc3984667a505691fec9d683204ddff56f12b2d1940e09a988" 1837"checksum lsp-types 0.70.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d267f222864db3db63cf7e18493a2a5c84edab1f4e3c7211c9390ce033365210"
1838"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1838"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
1839"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" 1839"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
1840"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" 1840"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
@@ -1902,7 +1902,7 @@ dependencies = [
1902"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" 1902"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573"
1903"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" 1903"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
1904"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1904"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1905"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" 1905"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
1906"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" 1906"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b"
1907"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1907"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
1908"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" 1908"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
diff --git a/README.md b/README.md
index 4a76ea6e3..2f6ed1e05 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,9 @@
4 4
5Rust Analyzer is an **experimental** modular compiler frontend for the Rust 5Rust Analyzer is an **experimental** modular compiler frontend for the Rust
6language. It is a part of a larger rls-2.0 effort to create excellent IDE 6language. It is a part of a larger rls-2.0 effort to create excellent IDE
7support for Rust. If you want to get involved, check the rls-2.0 working group 7support for Rust. If you want to get involved, check the rls-2.0 working group:
8in the compiler-team repository:
9 8
10https://github.com/rust-lang/compiler-team/tree/master/content/working-groups/rls-2.0 9https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0
11 10
12Work on the Rust Analyzer is sponsored by 11Work on the Rust Analyzer is sponsored by
13 12
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs
index 9163cc662..69126a1c9 100644
--- a/crates/ra_assists/src/assists/auto_import.rs
+++ b/crates/ra_assists/src/assists/auto_import.rs
@@ -1,8 +1,8 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, AstNode}, 3 ast::{self, AstNode},
4 SmolStr, SyntaxElement, 4 SmolStr,
5 SyntaxKind::{NAME_REF, USE_ITEM}, 5 SyntaxKind::USE_ITEM,
6 SyntaxNode, 6 SyntaxNode,
7}; 7};
8 8
@@ -32,25 +32,28 @@ pub(crate) fn auto_import<F: ImportsLocator>(
32 ctx: AssistCtx<impl HirDatabase>, 32 ctx: AssistCtx<impl HirDatabase>,
33 imports_locator: &mut F, 33 imports_locator: &mut F,
34) -> Option<Assist> { 34) -> Option<Assist> {
35 let path: ast::Path = ctx.find_node_at_offset()?; 35 let path_to_import: ast::Path = ctx.find_node_at_offset()?;
36 let module = path.syntax().ancestors().find_map(ast::Module::cast); 36 let path_to_import_syntax = path_to_import.syntax();
37 if path_to_import_syntax.ancestors().find(|ancestor| ancestor.kind() == USE_ITEM).is_some() {
38 return None;
39 }
40
41 let module = path_to_import_syntax.ancestors().find_map(ast::Module::cast);
37 let position = match module.and_then(|it| it.item_list()) { 42 let position = match module.and_then(|it| it.item_list()) {
38 Some(item_list) => item_list.syntax().clone(), 43 Some(item_list) => item_list.syntax().clone(),
39 None => { 44 None => {
40 let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; 45 let current_file = path_to_import_syntax.ancestors().find_map(ast::SourceFile::cast)?;
41 current_file.syntax().clone() 46 current_file.syntax().clone()
42 } 47 }
43 }; 48 };
44 let source_analyzer = ctx.source_analyzer(&position, None); 49 let source_analyzer = ctx.source_analyzer(&position, None);
45 let module_with_name_to_import = source_analyzer.module()?; 50 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() { 51 if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() {
48 return None; 52 return None;
49 } 53 }
50 54
51 let name_to_import = &find_applicable_name_ref(ctx.covering_element())?.syntax().to_string();
52 let proposed_imports = imports_locator 55 let proposed_imports = imports_locator
53 .find_imports(&name_to_import.to_string()) 56 .find_imports(&path_to_import_syntax.to_string())
54 .into_iter() 57 .into_iter()
55 .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def)) 58 .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()) 59 .filter(|use_path| !use_path.segments.is_empty())
@@ -64,26 +67,11 @@ pub(crate) fn auto_import<F: ImportsLocator>(
64 ctx.add_assist_group(AssistId("auto_import"), "auto import", || { 67 ctx.add_assist_group(AssistId("auto_import"), "auto import", || {
65 proposed_imports 68 proposed_imports
66 .into_iter() 69 .into_iter()
67 .map(|import| import_to_action(import, &position, &path_to_import.syntax())) 70 .map(|import| import_to_action(import, &position, &path_to_import_syntax))
68 .collect() 71 .collect()
69 }) 72 })
70} 73}
71 74
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 { 75fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder {
88 let mut action_builder = ActionBuilder::default(); 76 let mut action_builder = ActionBuilder::default();
89 action_builder.label(format!("Import `{}`", &import)); 77 action_builder.label(format!("Import `{}`", &import));
@@ -110,16 +98,16 @@ mod tests {
110 auto_import, 98 auto_import,
111 TestImportsLocator::new, 99 TestImportsLocator::new,
112 r" 100 r"
113 PubStruct<|> 101 <|>PubStruct
114 102
115 pub mod PubMod { 103 pub mod PubMod {
116 pub struct PubStruct; 104 pub struct PubStruct;
117 } 105 }
118 ", 106 ",
119 r" 107 r"
120 use PubMod::PubStruct; 108 <|>use PubMod::PubStruct;
121 109
122 PubStruct<|> 110 PubStruct
123 111
124 pub mod PubMod { 112 pub mod PubMod {
125 pub struct PubStruct; 113 pub struct PubStruct;
@@ -134,7 +122,7 @@ mod tests {
134 auto_import, 122 auto_import,
135 TestImportsLocator::new, 123 TestImportsLocator::new,
136 r" 124 r"
137 PubStruct<|> 125 PubSt<|>ruct
138 126
139 pub mod PubMod1 { 127 pub mod PubMod1 {
140 pub struct PubStruct; 128 pub struct PubStruct;
@@ -149,7 +137,7 @@ mod tests {
149 r" 137 r"
150 use PubMod1::PubStruct; 138 use PubMod1::PubStruct;
151 139
152 PubStruct<|> 140 PubSt<|>ruct
153 141
154 pub mod PubMod1 { 142 pub mod PubMod1 {
155 pub struct PubStruct; 143 pub struct PubStruct;
diff --git a/crates/ra_cargo_watch/Cargo.toml b/crates/ra_cargo_watch/Cargo.toml
index 49e06e0d3..dd814fc9d 100644
--- a/crates/ra_cargo_watch/Cargo.toml
+++ b/crates/ra_cargo_watch/Cargo.toml
@@ -11,6 +11,7 @@ log = "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"
14serde_json = "1.0.45"
14 15
15[dev-dependencies] 16[dev-dependencies]
16insta = "0.13.0" 17insta = "0.13.0"
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs
index e7b700c10..ea7ddc86b 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_cargo_watch/src/lib.rs
@@ -9,7 +9,7 @@ use lsp_types::{
9}; 9};
10use std::{ 10use std::{
11 collections::HashMap, 11 collections::HashMap,
12 io::BufReader, 12 io::{BufRead, BufReader},
13 path::PathBuf, 13 path::PathBuf,
14 process::{Command, Stdio}, 14 process::{Command, Stdio},
15 sync::Arc, 15 sync::Arc,
@@ -216,8 +216,10 @@ impl CheckWatcherThread {
216 self.last_update_req.take(); 216 self.last_update_req.take();
217 task_send.send(CheckTask::ClearDiagnostics).unwrap(); 217 task_send.send(CheckTask::ClearDiagnostics).unwrap();
218 218
219 // By replacing the watcher, we drop the previous one which 219 // Replace with a dummy watcher first so we drop the original and wait for completion
220 // causes it to shut down automatically. 220 std::mem::replace(&mut self.watcher, WatchThread::dummy());
221
222 // Then create the actual new watcher
221 self.watcher = WatchThread::new(&self.options, &self.workspace_root); 223 self.watcher = WatchThread::new(&self.options, &self.workspace_root);
222 } 224 }
223 } 225 }
@@ -348,17 +350,45 @@ impl WatchThread {
348 // which will break out of the loop, and continue the shutdown 350 // which will break out of the loop, and continue the shutdown
349 let _ = message_send.send(CheckEvent::Begin); 351 let _ = message_send.send(CheckEvent::Begin);
350 352
351 for message in 353 // We manually read a line at a time, instead of using serde's
352 cargo_metadata::parse_messages(BufReader::new(command.stdout.take().unwrap())) 354 // stream deserializers, because the deserializer cannot recover
353 { 355 // from an error, resulting in it getting stuck, because we try to
356 // be resillient against failures.
357 //
358 // Because cargo only outputs one JSON object per line, we can
359 // simply skip a line if it doesn't parse, which just ignores any
360 // erroneus output.
361 let stdout = BufReader::new(command.stdout.take().unwrap());
362 for line in stdout.lines() {
363 let line = match line {
364 Ok(line) => line,
365 Err(err) => {
366 log::error!("Couldn't read line from cargo: {}", err);
367 continue;
368 }
369 };
370
371 let message = serde_json::from_str::<cargo_metadata::Message>(&line);
354 let message = match message { 372 let message = match message {
355 Ok(message) => message, 373 Ok(message) => message,
356 Err(err) => { 374 Err(err) => {
357 log::error!("Invalid json from cargo check, ignoring: {}", err); 375 log::error!(
376 "Invalid json from cargo check, ignoring ({}): {:?} ",
377 err,
378 line
379 );
358 continue; 380 continue;
359 } 381 }
360 }; 382 };
361 383
384 // Skip certain kinds of messages to only spend time on what's useful
385 match &message {
386 Message::CompilerArtifact(artifact) if artifact.fresh => continue,
387 Message::BuildScriptExecuted(_) => continue,
388 Message::Unknown => continue,
389 _ => {}
390 }
391
362 match message_send.send(CheckEvent::Msg(message)) { 392 match message_send.send(CheckEvent::Msg(message)) {
363 Ok(()) => {} 393 Ok(()) => {}
364 Err(_err) => { 394 Err(_err) => {
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index e6079b88d..a77bf6de6 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,20 +1,24 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3pub use hir_def::db::{ 3pub use hir_def::db::{
4 BodyQuery, BodyWithSourceMapQuery, ComputeCrateDefMapQuery, ConstDataQuery, 4 AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ComputeCrateDefMapQuery, ConstDataQuery,
5 CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, 5 CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery,
6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, 6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternConstQuery,
7 InternDatabaseStorage, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, 7 InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery,
8 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, 8 InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery,
9 LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, StructDataQuery,
10 TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
9}; 11};
10pub use hir_expand::db::{ 12pub use hir_expand::db::{
11 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternMacroQuery, MacroArgQuery, MacroDefQuery,
12 ParseMacroQuery, 14 MacroExpandQuery, ParseMacroQuery,
13}; 15};
14pub use hir_ty::db::{ 16pub use hir_ty::db::{
15 AssociatedTyDataQuery, CallableItemSignatureQuery, DoInferQuery, FieldTypesQuery, 17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, DoInferQuery,
16 GenericDefaultsQuery, GenericPredicatesQuery, HirDatabase, HirDatabaseStorage, ImplDatumQuery, 18 FieldTypesQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery,
17 ImplsForTraitQuery, ImplsInCrateQuery, StructDatumQuery, TraitDatumQuery, TraitSolveQuery, 19 HirDatabase, HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery,
20 ImplsForTraitQuery, ImplsInCrateQuery, InternAssocTyValueQuery, InternChalkImplQuery,
21 InternTypeCtorQuery, StructDatumQuery, TraitDatumQuery, TraitSolveQuery, TraitSolverQuery,
18 TyQuery, ValueTyQuery, 22 TyQuery, ValueTyQuery,
19}; 23};
20 24
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs
index 8cc2fb160..43b9b124a 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -7,10 +7,39 @@ use crate::{
7 visibility::Visibility, 7 visibility::Visibility,
8 CrateId, ModuleDefId, ModuleId, 8 CrateId, ModuleDefId, ModuleId,
9}; 9};
10use hir_expand::name::Name; 10use hir_expand::name::{known, Name};
11use test_utils::tested_by;
11 12
12const MAX_PATH_LEN: usize = 15; 13const MAX_PATH_LEN: usize = 15;
13 14
15impl ModPath {
16 fn starts_with_std(&self) -> bool {
17 self.segments.first().filter(|&first_segment| first_segment == &known::std).is_some()
18 }
19
20 // When std library is present, paths starting with `std::`
21 // should be preferred over paths starting with `core::` and `alloc::`
22 fn should_start_with_std(&self) -> bool {
23 self.segments
24 .first()
25 .filter(|&first_segment| {
26 first_segment == &known::alloc || first_segment == &known::core
27 })
28 .is_some()
29 }
30
31 fn len(&self) -> usize {
32 self.segments.len()
33 + match self.kind {
34 PathKind::Plain => 0,
35 PathKind::Super(i) => i as usize,
36 PathKind::Crate => 1,
37 PathKind::Abs => 0,
38 PathKind::DollarCrate(_) => 1,
39 }
40 }
41}
42
14// FIXME: handle local items 43// FIXME: handle local items
15 44
16/// Find a path that can be used to refer to a certain item. This can depend on 45/// Find a path that can be used to refer to a certain item. This can depend on
@@ -112,23 +141,27 @@ fn find_path_inner(
112 Some(path) => path, 141 Some(path) => path,
113 }; 142 };
114 path.segments.push(name); 143 path.segments.push(name);
115 if path_len(&path) < best_path_len { 144
116 best_path_len = path_len(&path); 145 let new_path =
117 best_path = Some(path); 146 if let Some(best_path) = best_path { select_best_path(best_path, path) } else { path };
118 } 147 best_path_len = new_path.len();
148 best_path = Some(new_path);
119 } 149 }
120 best_path 150 best_path
121} 151}
122 152
123fn path_len(path: &ModPath) -> usize { 153fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath {
124 path.segments.len() 154 if old_path.starts_with_std() && new_path.should_start_with_std() {
125 + match path.kind { 155 tested_by!(prefer_std_paths);
126 PathKind::Plain => 0, 156 old_path
127 PathKind::Super(i) => i as usize, 157 } else if new_path.starts_with_std() && old_path.should_start_with_std() {
128 PathKind::Crate => 1, 158 tested_by!(prefer_std_paths);
129 PathKind::Abs => 0, 159 new_path
130 PathKind::DollarCrate(_) => 1, 160 } else if new_path.len() < old_path.len() {
131 } 161 new_path
162 } else {
163 old_path
164 }
132} 165}
133 166
134fn find_importable_locations( 167fn find_importable_locations(
@@ -201,6 +234,7 @@ mod tests {
201 use hir_expand::hygiene::Hygiene; 234 use hir_expand::hygiene::Hygiene;
202 use ra_db::fixture::WithFixture; 235 use ra_db::fixture::WithFixture;
203 use ra_syntax::ast::AstNode; 236 use ra_syntax::ast::AstNode;
237 use test_utils::covers;
204 238
205 /// `code` needs to contain a cursor marker; checks that `find_path` for the 239 /// `code` needs to contain a cursor marker; checks that `find_path` for the
206 /// item the `path` refers to returns that same path when called from the 240 /// item the `path` refers to returns that same path when called from the
@@ -452,4 +486,41 @@ mod tests {
452 "#; 486 "#;
453 check_found_path(code, "crate::foo::S"); 487 check_found_path(code, "crate::foo::S");
454 } 488 }
489
490 #[test]
491 fn prefer_std_paths_over_alloc() {
492 covers!(prefer_std_paths);
493 let code = r#"
494 //- /main.rs crate:main deps:alloc,std
495 <|>
496
497 //- /std.rs crate:std deps:alloc
498 pub mod sync {
499 pub use alloc::sync::Arc;
500 }
501
502 //- /zzz.rs crate:alloc
503 pub mod sync {
504 pub struct Arc;
505 }
506 "#;
507 check_found_path(code, "std::sync::Arc");
508 }
509
510 #[test]
511 fn prefer_shorter_paths_if_not_alloc() {
512 let code = r#"
513 //- /main.rs crate:main deps:megaalloc,std
514 <|>
515
516 //- /std.rs crate:std deps:megaalloc
517 pub mod sync {
518 pub use megaalloc::sync::Arc;
519 }
520
521 //- /zzz.rs crate:megaalloc
522 pub struct Arc;
523 "#;
524 check_found_path(code, "megaalloc::Arc");
525 }
455} 526}
diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs
index 457ba4abe..daa49d5f1 100644
--- a/crates/ra_hir_def/src/marks.rs
+++ b/crates/ra_hir_def/src/marks.rs
@@ -13,4 +13,5 @@ test_utils::marks!(
13 macro_dollar_crate_self 13 macro_dollar_crate_self
14 macro_dollar_crate_other 14 macro_dollar_crate_other
15 infer_resolve_while_let 15 infer_resolve_while_let
16 prefer_std_paths
16); 17);
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 27c12e46c..852304dd0 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -229,6 +229,46 @@ impl CrateDefMap {
229 self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow); 229 self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
230 (res.resolved_def, res.segment_index) 230 (res.resolved_def, res.segment_index)
231 } 231 }
232
233 // FIXME: this can use some more human-readable format (ideally, an IR
234 // even), as this should be a great debugging aid.
235 pub fn dump(&self) -> String {
236 let mut buf = String::new();
237 go(&mut buf, self, "\ncrate", self.root);
238 return buf.trim().to_string();
239
240 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) {
241 *buf += path;
242 *buf += "\n";
243
244 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect();
245 entries.sort_by_key(|(name, _)| name.clone());
246
247 for (name, def) in entries {
248 *buf += &format!("{}:", name);
249
250 if def.types.is_some() {
251 *buf += " t";
252 }
253 if def.values.is_some() {
254 *buf += " v";
255 }
256 if def.macros.is_some() {
257 *buf += " m";
258 }
259 if def.is_none() {
260 *buf += " _";
261 }
262
263 *buf += "\n";
264 }
265
266 for (name, child) in map.modules[module].children.iter() {
267 let path = path.to_string() + &format!("::{}", name);
268 go(buf, map, &path, *child);
269 }
270 }
271 }
232} 272}
233 273
234impl ModuleData { 274impl ModuleData {
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 78bcdc850..82f0f835c 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -10,11 +10,10 @@ use insta::assert_snapshot;
10use ra_db::{fixture::WithFixture, SourceDatabase}; 10use ra_db::{fixture::WithFixture, SourceDatabase};
11use test_utils::covers; 11use test_utils::covers;
12 12
13use crate::{db::DefDatabase, nameres::*, test_db::TestDB, LocalModuleId}; 13use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
14 14
15fn def_map(fixture: &str) -> String { 15fn def_map(fixture: &str) -> String {
16 let dm = compute_crate_def_map(fixture); 16 compute_crate_def_map(fixture).dump()
17 render_crate_def_map(&dm)
18} 17}
19 18
20fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> { 19fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
@@ -23,44 +22,6 @@ fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
23 db.crate_def_map(krate) 22 db.crate_def_map(krate)
24} 23}
25 24
26fn render_crate_def_map(map: &CrateDefMap) -> String {
27 let mut buf = String::new();
28 go(&mut buf, map, "\ncrate", map.root);
29 return buf.trim().to_string();
30
31 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) {
32 *buf += path;
33 *buf += "\n";
34
35 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect();
36 entries.sort_by_key(|(name, _)| name.clone());
37
38 for (name, def) in entries {
39 *buf += &format!("{}:", name);
40
41 if def.types.is_some() {
42 *buf += " t";
43 }
44 if def.values.is_some() {
45 *buf += " v";
46 }
47 if def.macros.is_some() {
48 *buf += " m";
49 }
50 if def.is_none() {
51 *buf += " _";
52 }
53
54 *buf += "\n";
55 }
56
57 for (name, child) in map.modules[module].children.iter() {
58 let path = path.to_string() + &format!("::{}", name);
59 go(buf, map, &path, *child);
60 }
61 }
62}
63
64#[test] 25#[test]
65fn crate_def_map_smoke_test() { 26fn crate_def_map_smoke_test() {
66 let map = def_map( 27 let map = def_map(
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index b3fa1efba..b2e10f445 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -141,6 +141,8 @@ pub mod known {
141 macro_rules, 141 macro_rules,
142 // Components of known path (value or mod name) 142 // Components of known path (value or mod name)
143 std, 143 std,
144 core,
145 alloc,
144 iter, 146 iter,
145 ops, 147 ops,
146 future, 148 future,
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 908e4862d..08d501ccd 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -847,7 +847,7 @@ impl HirDisplay for ApplicationTy {
847 } 847 }
848 TypeCtor::Array => { 848 TypeCtor::Array => {
849 let t = self.parameters.as_single(); 849 let t = self.parameters.as_single();
850 write!(f, "[{};_]", t.display(f.db))?; 850 write!(f, "[{}; _]", t.display(f.db))?;
851 } 851 }
852 TypeCtor::RawPtr(m) => { 852 TypeCtor::RawPtr(m) => {
853 let t = self.parameters.as_single(); 853 let t = self.parameters.as_single();
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 7e99a42ed..76a1b46c0 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -71,42 +71,42 @@ fn test2() {
71 [82; 93) '{ loop {} }': T 71 [82; 93) '{ loop {} }': T
72 [84; 91) 'loop {}': ! 72 [84; 91) 'loop {}': !
73 [89; 91) '{}': () 73 [89; 91) '{}': ()
74 [122; 133) '{ loop {} }': *mut [T;_] 74 [122; 133) '{ loop {} }': *mut [T; _]
75 [124; 131) 'loop {}': ! 75 [124; 131) 'loop {}': !
76 [129; 131) '{}': () 76 [129; 131) '{}': ()
77 [160; 173) '{ gen() }': *mut [U] 77 [160; 173) '{ gen() }': *mut [U]
78 [166; 169) 'gen': fn gen<U>() -> *mut [T;_] 78 [166; 169) 'gen': fn gen<U>() -> *mut [T; _]
79 [166; 171) 'gen()': *mut [U;_] 79 [166; 171) 'gen()': *mut [U; _]
80 [186; 420) '{ ...rr); }': () 80 [186; 420) '{ ...rr); }': ()
81 [196; 199) 'arr': &[u8;_] 81 [196; 199) 'arr': &[u8; _]
82 [212; 216) '&[1]': &[u8;_] 82 [212; 216) '&[1]': &[u8; _]
83 [213; 216) '[1]': [u8;_] 83 [213; 216) '[1]': [u8; _]
84 [214; 215) '1': u8 84 [214; 215) '1': u8
85 [227; 228) 'a': &[u8] 85 [227; 228) 'a': &[u8]
86 [237; 240) 'arr': &[u8;_] 86 [237; 240) 'arr': &[u8; _]
87 [250; 251) 'b': u8 87 [250; 251) 'b': u8
88 [254; 255) 'f': fn f<u8>(&[T]) -> T 88 [254; 255) 'f': fn f<u8>(&[T]) -> T
89 [254; 260) 'f(arr)': u8 89 [254; 260) 'f(arr)': u8
90 [256; 259) 'arr': &[u8;_] 90 [256; 259) 'arr': &[u8; _]
91 [270; 271) 'c': &[u8] 91 [270; 271) 'c': &[u8]
92 [280; 287) '{ arr }': &[u8] 92 [280; 287) '{ arr }': &[u8]
93 [282; 285) 'arr': &[u8;_] 93 [282; 285) 'arr': &[u8; _]
94 [297; 298) 'd': u8 94 [297; 298) 'd': u8
95 [301; 302) 'g': fn g<u8>(S<&[T]>) -> T 95 [301; 302) 'g': fn g<u8>(S<&[T]>) -> T
96 [301; 316) 'g(S { a: arr })': u8 96 [301; 316) 'g(S { a: arr })': u8
97 [303; 315) 'S { a: arr }': S<&[u8]> 97 [303; 315) 'S { a: arr }': S<&[u8]>
98 [310; 313) 'arr': &[u8;_] 98 [310; 313) 'arr': &[u8; _]
99 [326; 327) 'e': [&[u8];_] 99 [326; 327) 'e': [&[u8]; _]
100 [341; 346) '[arr]': [&[u8];_] 100 [341; 346) '[arr]': [&[u8]; _]
101 [342; 345) 'arr': &[u8;_] 101 [342; 345) 'arr': &[u8; _]
102 [356; 357) 'f': [&[u8];_] 102 [356; 357) 'f': [&[u8]; _]
103 [371; 379) '[arr; 2]': [&[u8];_] 103 [371; 379) '[arr; 2]': [&[u8]; _]
104 [372; 375) 'arr': &[u8;_] 104 [372; 375) 'arr': &[u8; _]
105 [377; 378) '2': usize 105 [377; 378) '2': usize
106 [389; 390) 'g': (&[u8], &[u8]) 106 [389; 390) 'g': (&[u8], &[u8])
107 [407; 417) '(arr, arr)': (&[u8], &[u8]) 107 [407; 417) '(arr, arr)': (&[u8], &[u8])
108 [408; 411) 'arr': &[u8;_] 108 [408; 411) 'arr': &[u8; _]
109 [413; 416) 'arr': &[u8;_] 109 [413; 416) 'arr': &[u8; _]
110 "### 110 "###
111 ); 111 );
112} 112}
@@ -122,8 +122,8 @@ fn test() {
122 @r###" 122 @r###"
123 [11; 40) '{ ...[1]; }': () 123 [11; 40) '{ ...[1]; }': ()
124 [21; 22) 'x': &[i32] 124 [21; 22) 'x': &[i32]
125 [33; 37) '&[1]': &[i32;_] 125 [33; 37) '&[1]': &[i32; _]
126 [34; 37) '[1]': [i32;_] 126 [34; 37) '[1]': [i32; _]
127 [35; 36) '1': i32 127 [35; 36) '1': i32
128 "###); 128 "###);
129} 129}
@@ -159,22 +159,22 @@ fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) {
159 [334; 335) 'x': C<[T]> 159 [334; 335) 'x': C<[T]>
160 [355; 360) '{ x }': C<[T]> 160 [355; 360) '{ x }': C<[T]>
161 [357; 358) 'x': C<[T]> 161 [357; 358) 'x': C<[T]>
162 [370; 371) 'a': A<[u8;_]> 162 [370; 371) 'a': A<[u8; _]>
163 [385; 386) 'b': B<[u8;_]> 163 [385; 386) 'b': B<[u8; _]>
164 [400; 401) 'c': C<[u8;_]> 164 [400; 401) 'c': C<[u8; _]>
165 [415; 481) '{ ...(c); }': () 165 [415; 481) '{ ...(c); }': ()
166 [425; 426) 'd': A<[{unknown}]> 166 [425; 426) 'd': A<[{unknown}]>
167 [429; 433) 'foo1': fn foo1<{unknown}>(A<[T]>) -> A<[T]> 167 [429; 433) 'foo1': fn foo1<{unknown}>(A<[T]>) -> A<[T]>
168 [429; 436) 'foo1(a)': A<[{unknown}]> 168 [429; 436) 'foo1(a)': A<[{unknown}]>
169 [434; 435) 'a': A<[u8;_]> 169 [434; 435) 'a': A<[u8; _]>
170 [446; 447) 'e': B<[u8]> 170 [446; 447) 'e': B<[u8]>
171 [450; 454) 'foo2': fn foo2<u8>(B<[T]>) -> B<[T]> 171 [450; 454) 'foo2': fn foo2<u8>(B<[T]>) -> B<[T]>
172 [450; 457) 'foo2(b)': B<[u8]> 172 [450; 457) 'foo2(b)': B<[u8]>
173 [455; 456) 'b': B<[u8;_]> 173 [455; 456) 'b': B<[u8; _]>
174 [467; 468) 'f': C<[u8]> 174 [467; 468) 'f': C<[u8]>
175 [471; 475) 'foo3': fn foo3<u8>(C<[T]>) -> C<[T]> 175 [471; 475) 'foo3': fn foo3<u8>(C<[T]>) -> C<[T]>
176 [471; 478) 'foo3(c)': C<[u8]> 176 [471; 478) 'foo3(c)': C<[u8]>
177 [476; 477) 'c': C<[u8;_]> 177 [476; 477) 'c': C<[u8; _]>
178 "### 178 "###
179 ); 179 );
180} 180}
@@ -204,12 +204,12 @@ fn test() {
204 [72; 97) '{ ... }': &[i32] 204 [72; 97) '{ ... }': &[i32]
205 [82; 85) 'foo': fn foo<i32>(&[T]) -> &[T] 205 [82; 85) 'foo': fn foo<i32>(&[T]) -> &[T]
206 [82; 91) 'foo(&[1])': &[i32] 206 [82; 91) 'foo(&[1])': &[i32]
207 [86; 90) '&[1]': &[i32;_] 207 [86; 90) '&[1]': &[i32; _]
208 [87; 90) '[1]': [i32;_] 208 [87; 90) '[1]': [i32; _]
209 [88; 89) '1': i32 209 [88; 89) '1': i32
210 [103; 123) '{ ... }': &[i32;_] 210 [103; 123) '{ ... }': &[i32; _]
211 [113; 117) '&[1]': &[i32;_] 211 [113; 117) '&[1]': &[i32; _]
212 [114; 117) '[1]': [i32;_] 212 [114; 117) '[1]': [i32; _]
213 [115; 116) '1': i32 213 [115; 116) '1': i32
214 "### 214 "###
215 ); 215 );
@@ -237,15 +237,15 @@ fn test() {
237 [60; 61) 'x': &[i32] 237 [60; 61) 'x': &[i32]
238 [64; 123) 'if tru... }': &[i32] 238 [64; 123) 'if tru... }': &[i32]
239 [67; 71) 'true': bool 239 [67; 71) 'true': bool
240 [72; 92) '{ ... }': &[i32;_] 240 [72; 92) '{ ... }': &[i32; _]
241 [82; 86) '&[1]': &[i32;_] 241 [82; 86) '&[1]': &[i32; _]
242 [83; 86) '[1]': [i32;_] 242 [83; 86) '[1]': [i32; _]
243 [84; 85) '1': i32 243 [84; 85) '1': i32
244 [98; 123) '{ ... }': &[i32] 244 [98; 123) '{ ... }': &[i32]
245 [108; 111) 'foo': fn foo<i32>(&[T]) -> &[T] 245 [108; 111) 'foo': fn foo<i32>(&[T]) -> &[T]
246 [108; 117) 'foo(&[1])': &[i32] 246 [108; 117) 'foo(&[1])': &[i32]
247 [112; 116) '&[1]': &[i32;_] 247 [112; 116) '&[1]': &[i32; _]
248 [113; 116) '[1]': [i32;_] 248 [113; 116) '[1]': [i32; _]
249 [114; 115) '1': i32 249 [114; 115) '1': i32
250 "### 250 "###
251 ); 251 );
@@ -277,16 +277,16 @@ fn test(i: i32) {
277 [88; 89) '2': i32 277 [88; 89) '2': i32
278 [93; 96) 'foo': fn foo<i32>(&[T]) -> &[T] 278 [93; 96) 'foo': fn foo<i32>(&[T]) -> &[T]
279 [93; 102) 'foo(&[2])': &[i32] 279 [93; 102) 'foo(&[2])': &[i32]
280 [97; 101) '&[2]': &[i32;_] 280 [97; 101) '&[2]': &[i32; _]
281 [98; 101) '[2]': [i32;_] 281 [98; 101) '[2]': [i32; _]
282 [99; 100) '2': i32 282 [99; 100) '2': i32
283 [112; 113) '1': i32 283 [112; 113) '1': i32
284 [117; 121) '&[1]': &[i32;_] 284 [117; 121) '&[1]': &[i32; _]
285 [118; 121) '[1]': [i32;_] 285 [118; 121) '[1]': [i32; _]
286 [119; 120) '1': i32 286 [119; 120) '1': i32
287 [131; 132) '_': i32 287 [131; 132) '_': i32
288 [136; 140) '&[3]': &[i32;_] 288 [136; 140) '&[3]': &[i32; _]
289 [137; 140) '[3]': [i32;_] 289 [137; 140) '[3]': [i32; _]
290 [138; 139) '3': i32 290 [138; 139) '3': i32
291 "### 291 "###
292 ); 292 );
@@ -316,18 +316,18 @@ fn test(i: i32) {
316 [70; 147) 'match ... }': &[i32] 316 [70; 147) 'match ... }': &[i32]
317 [76; 77) 'i': i32 317 [76; 77) 'i': i32
318 [88; 89) '1': i32 318 [88; 89) '1': i32
319 [93; 97) '&[1]': &[i32;_] 319 [93; 97) '&[1]': &[i32; _]
320 [94; 97) '[1]': [i32;_] 320 [94; 97) '[1]': [i32; _]
321 [95; 96) '1': i32 321 [95; 96) '1': i32
322 [107; 108) '2': i32 322 [107; 108) '2': i32
323 [112; 115) 'foo': fn foo<i32>(&[T]) -> &[T] 323 [112; 115) 'foo': fn foo<i32>(&[T]) -> &[T]
324 [112; 121) 'foo(&[2])': &[i32] 324 [112; 121) 'foo(&[2])': &[i32]
325 [116; 120) '&[2]': &[i32;_] 325 [116; 120) '&[2]': &[i32; _]
326 [117; 120) '[2]': [i32;_] 326 [117; 120) '[2]': [i32; _]
327 [118; 119) '2': i32 327 [118; 119) '2': i32
328 [131; 132) '_': i32 328 [131; 132) '_': i32
329 [136; 140) '&[3]': &[i32;_] 329 [136; 140) '&[3]': &[i32; _]
330 [137; 140) '[3]': [i32;_] 330 [137; 140) '[3]': [i32; _]
331 [138; 139) '3': i32 331 [138; 139) '3': i32
332 "### 332 "###
333 ); 333 );
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index aa948dcbf..02bab6dbe 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -102,7 +102,7 @@ fn test() {
102 [11; 48) '{ ...&y]; }': () 102 [11; 48) '{ ...&y]; }': ()
103 [21; 22) 'y': &{unknown} 103 [21; 22) 'y': &{unknown}
104 [25; 32) 'unknown': &{unknown} 104 [25; 32) 'unknown': &{unknown}
105 [38; 45) '[y, &y]': [&&{unknown};_] 105 [38; 45) '[y, &y]': [&&{unknown}; _]
106 [39; 40) 'y': &{unknown} 106 [39; 40) 'y': &{unknown}
107 [42; 44) '&y': &&{unknown} 107 [42; 44) '&y': &&{unknown}
108 [43; 44) 'y': &{unknown} 108 [43; 44) 'y': &{unknown}
@@ -128,7 +128,7 @@ fn test() {
128 [25; 32) 'unknown': &&{unknown} 128 [25; 32) 'unknown': &&{unknown}
129 [42; 43) 'y': &&{unknown} 129 [42; 43) 'y': &&{unknown}
130 [46; 53) 'unknown': &&{unknown} 130 [46; 53) 'unknown': &&{unknown}
131 [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown});_] 131 [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); _]
132 [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown}) 132 [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown})
133 [61; 62) 'x': &&{unknown} 133 [61; 62) 'x': &&{unknown}
134 [64; 65) 'y': &&{unknown} 134 [64; 65) 'y': &&{unknown}
@@ -180,8 +180,8 @@ fn test_line_buffer() {
180"#), 180"#),
181 @r###" 181 @r###"
182 [23; 53) '{ ...n']; }': () 182 [23; 53) '{ ...n']; }': ()
183 [29; 50) '&[0, b...b'\n']': &[u8;_] 183 [29; 50) '&[0, b...b'\n']': &[u8; _]
184 [30; 50) '[0, b'...b'\n']': [u8;_] 184 [30; 50) '[0, b'...b'\n']': [u8; _]
185 [31; 32) '0': u8 185 [31; 32) '0': u8
186 [34; 39) 'b'\n'': u8 186 [34; 39) 'b'\n'': u8
187 [41; 42) '1': u8 187 [41; 42) '1': u8
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index b7204ec00..fdab9c187 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -28,7 +28,7 @@ mod boxed {
28 28
29"#, 29"#,
30 ); 30 );
31 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos)); 31 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)", type_at_pos(&db, pos));
32} 32}
33 33
34#[test] 34#[test]
@@ -1061,55 +1061,55 @@ fn test(x: &str, y: isize) {
1061 [9; 10) 'x': &str 1061 [9; 10) 'x': &str
1062 [18; 19) 'y': isize 1062 [18; 19) 'y': isize
1063 [28; 293) '{ ... []; }': () 1063 [28; 293) '{ ... []; }': ()
1064 [38; 39) 'a': [&str;_] 1064 [38; 39) 'a': [&str; _]
1065 [42; 45) '[x]': [&str;_] 1065 [42; 45) '[x]': [&str; _]
1066 [43; 44) 'x': &str 1066 [43; 44) 'x': &str
1067 [55; 56) 'b': [[&str;_];_] 1067 [55; 56) 'b': [[&str; _]; _]
1068 [59; 65) '[a, a]': [[&str;_];_] 1068 [59; 65) '[a, a]': [[&str; _]; _]
1069 [60; 61) 'a': [&str;_] 1069 [60; 61) 'a': [&str; _]
1070 [63; 64) 'a': [&str;_] 1070 [63; 64) 'a': [&str; _]
1071 [75; 76) 'c': [[[&str;_];_];_] 1071 [75; 76) 'c': [[[&str; _]; _]; _]
1072 [79; 85) '[b, b]': [[[&str;_];_];_] 1072 [79; 85) '[b, b]': [[[&str; _]; _]; _]
1073 [80; 81) 'b': [[&str;_];_] 1073 [80; 81) 'b': [[&str; _]; _]
1074 [83; 84) 'b': [[&str;_];_] 1074 [83; 84) 'b': [[&str; _]; _]
1075 [96; 97) 'd': [isize;_] 1075 [96; 97) 'd': [isize; _]
1076 [100; 112) '[y, 1, 2, 3]': [isize;_] 1076 [100; 112) '[y, 1, 2, 3]': [isize; _]
1077 [101; 102) 'y': isize 1077 [101; 102) 'y': isize
1078 [104; 105) '1': isize 1078 [104; 105) '1': isize
1079 [107; 108) '2': isize 1079 [107; 108) '2': isize
1080 [110; 111) '3': isize 1080 [110; 111) '3': isize
1081 [122; 123) 'd': [isize;_] 1081 [122; 123) 'd': [isize; _]
1082 [126; 138) '[1, y, 2, 3]': [isize;_] 1082 [126; 138) '[1, y, 2, 3]': [isize; _]
1083 [127; 128) '1': isize 1083 [127; 128) '1': isize
1084 [130; 131) 'y': isize 1084 [130; 131) 'y': isize
1085 [133; 134) '2': isize 1085 [133; 134) '2': isize
1086 [136; 137) '3': isize 1086 [136; 137) '3': isize
1087 [148; 149) 'e': [isize;_] 1087 [148; 149) 'e': [isize; _]
1088 [152; 155) '[y]': [isize;_] 1088 [152; 155) '[y]': [isize; _]
1089 [153; 154) 'y': isize 1089 [153; 154) 'y': isize
1090 [165; 166) 'f': [[isize;_];_] 1090 [165; 166) 'f': [[isize; _]; _]
1091 [169; 175) '[d, d]': [[isize;_];_] 1091 [169; 175) '[d, d]': [[isize; _]; _]
1092 [170; 171) 'd': [isize;_] 1092 [170; 171) 'd': [isize; _]
1093 [173; 174) 'd': [isize;_] 1093 [173; 174) 'd': [isize; _]
1094 [185; 186) 'g': [[isize;_];_] 1094 [185; 186) 'g': [[isize; _]; _]
1095 [189; 195) '[e, e]': [[isize;_];_] 1095 [189; 195) '[e, e]': [[isize; _]; _]
1096 [190; 191) 'e': [isize;_] 1096 [190; 191) 'e': [isize; _]
1097 [193; 194) 'e': [isize;_] 1097 [193; 194) 'e': [isize; _]
1098 [206; 207) 'h': [i32;_] 1098 [206; 207) 'h': [i32; _]
1099 [210; 216) '[1, 2]': [i32;_] 1099 [210; 216) '[1, 2]': [i32; _]
1100 [211; 212) '1': i32 1100 [211; 212) '1': i32
1101 [214; 215) '2': i32 1101 [214; 215) '2': i32
1102 [226; 227) 'i': [&str;_] 1102 [226; 227) 'i': [&str; _]
1103 [230; 240) '["a", "b"]': [&str;_] 1103 [230; 240) '["a", "b"]': [&str; _]
1104 [231; 234) '"a"': &str 1104 [231; 234) '"a"': &str
1105 [236; 239) '"b"': &str 1105 [236; 239) '"b"': &str
1106 [251; 252) 'b': [[&str;_];_] 1106 [251; 252) 'b': [[&str; _]; _]
1107 [255; 265) '[a, ["b"]]': [[&str;_];_] 1107 [255; 265) '[a, ["b"]]': [[&str; _]; _]
1108 [256; 257) 'a': [&str;_] 1108 [256; 257) 'a': [&str; _]
1109 [259; 264) '["b"]': [&str;_] 1109 [259; 264) '["b"]': [&str; _]
1110 [260; 263) '"b"': &str 1110 [260; 263) '"b"': &str
1111 [275; 276) 'x': [u8;_] 1111 [275; 276) 'x': [u8; _]
1112 [288; 290) '[]': [u8;_] 1112 [288; 290) '[]': [u8; _]
1113 "### 1113 "###
1114 ); 1114 );
1115} 1115}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index bc20a49cc..a6ac18f86 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -479,7 +479,7 @@ fn indexing_arrays() {
479 @r###" 479 @r###"
480 [10; 26) '{ &mut...[2]; }': () 480 [10; 26) '{ &mut...[2]; }': ()
481 [12; 23) '&mut [9][2]': &mut {unknown} 481 [12; 23) '&mut [9][2]': &mut {unknown}
482 [17; 20) '[9]': [i32;_] 482 [17; 20) '[9]': [i32; _]
483 [17; 23) '[9][2]': {unknown} 483 [17; 23) '[9][2]': {unknown}
484 [18; 19) '9': i32 484 [18; 19) '9': i32
485 [21; 22) '2': i32 485 [21; 22) '2': i32
diff --git a/crates/ra_ide/src/change.rs b/crates/ra_ide/src/change.rs
index ce617840c..45a58690b 100644
--- a/crates/ra_ide/src/change.rs
+++ b/crates/ra_ide/src/change.rs
@@ -301,45 +301,74 @@ impl RootDatabase {
301 )*} 301 )*}
302 } 302 }
303 sweep_each_query![ 303 sweep_each_query![
304 // SourceDatabase
304 ra_db::ParseQuery 305 ra_db::ParseQuery
305 ra_db::SourceRootCratesQuery 306 ra_db::SourceRootCratesQuery
307
308 // AstDatabase
306 hir::db::AstIdMapQuery 309 hir::db::AstIdMapQuery
307 hir::db::ParseMacroQuery 310 hir::db::InternMacroQuery
308 hir::db::MacroDefQuery
309 hir::db::MacroArgQuery 311 hir::db::MacroArgQuery
312 hir::db::MacroDefQuery
313 hir::db::ParseMacroQuery
310 hir::db::MacroExpandQuery 314 hir::db::MacroExpandQuery
315
316 // DefDatabase
317 hir::db::RawItemsQuery
318 hir::db::ComputeCrateDefMapQuery
311 hir::db::StructDataQuery 319 hir::db::StructDataQuery
320 hir::db::UnionDataQuery
312 hir::db::EnumDataQuery 321 hir::db::EnumDataQuery
322 hir::db::ImplDataQuery
313 hir::db::TraitDataQuery 323 hir::db::TraitDataQuery
314 hir::db::RawItemsQuery
315 hir::db::ComputeCrateDefMapQuery
316 hir::db::GenericParamsQuery
317 hir::db::FunctionDataQuery
318 hir::db::TypeAliasDataQuery 324 hir::db::TypeAliasDataQuery
325 hir::db::FunctionDataQuery
319 hir::db::ConstDataQuery 326 hir::db::ConstDataQuery
320 hir::db::StaticDataQuery 327 hir::db::StaticDataQuery
328 hir::db::BodyWithSourceMapQuery
329 hir::db::BodyQuery
330 hir::db::ExprScopesQuery
331 hir::db::GenericParamsQuery
332 hir::db::AttrsQuery
321 hir::db::ModuleLangItemsQuery 333 hir::db::ModuleLangItemsQuery
322 hir::db::CrateLangItemsQuery 334 hir::db::CrateLangItemsQuery
323 hir::db::LangItemQuery 335 hir::db::LangItemQuery
324 hir::db::DocumentationQuery 336 hir::db::DocumentationQuery
325 hir::db::ExprScopesQuery 337
338 // InternDatabase
339 hir::db::InternFunctionQuery
340 hir::db::InternStructQuery
341 hir::db::InternUnionQuery
342 hir::db::InternEnumQuery
343 hir::db::InternConstQuery
344 hir::db::InternStaticQuery
345 hir::db::InternTraitQuery
346 hir::db::InternTypeAliasQuery
347 hir::db::InternImplQuery
348
349 // HirDatabase
326 hir::db::DoInferQuery 350 hir::db::DoInferQuery
327 hir::db::TyQuery 351 hir::db::TyQuery
328 hir::db::ValueTyQuery 352 hir::db::ValueTyQuery
353 hir::db::ImplSelfTyQuery
354 hir::db::ImplTraitQuery
329 hir::db::FieldTypesQuery 355 hir::db::FieldTypesQuery
330 hir::db::CallableItemSignatureQuery 356 hir::db::CallableItemSignatureQuery
357 hir::db::GenericPredicatesForParamQuery
331 hir::db::GenericPredicatesQuery 358 hir::db::GenericPredicatesQuery
332 hir::db::GenericDefaultsQuery 359 hir::db::GenericDefaultsQuery
333 hir::db::BodyWithSourceMapQuery
334 hir::db::BodyQuery
335 hir::db::ImplsInCrateQuery 360 hir::db::ImplsInCrateQuery
336 hir::db::ImplsForTraitQuery 361 hir::db::ImplsForTraitQuery
362 hir::db::TraitSolverQuery
363 hir::db::InternTypeCtorQuery
364 hir::db::InternChalkImplQuery
365 hir::db::InternAssocTyValueQuery
337 hir::db::AssociatedTyDataQuery 366 hir::db::AssociatedTyDataQuery
367 hir::db::AssociatedTyValueQuery
368 hir::db::TraitSolveQuery
338 hir::db::TraitDatumQuery 369 hir::db::TraitDatumQuery
339 hir::db::StructDatumQuery 370 hir::db::StructDatumQuery
340 hir::db::ImplDatumQuery 371 hir::db::ImplDatumQuery
341 hir::db::ImplDataQuery
342 hir::db::TraitSolveQuery
343 ]; 372 ];
344 acc.sort_by_key(|it| std::cmp::Reverse(it.1)); 373 acc.sort_by_key(|it| std::cmp::Reverse(it.1));
345 acc 374 acc
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 15bf519c9..d850ded37 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -5,11 +5,18 @@ mod handlers;
5mod subscriptions; 5mod subscriptions;
6pub(crate) mod pending_requests; 6pub(crate) mod pending_requests;
7 7
8use std::{error::Error, fmt, panic, path::PathBuf, sync::Arc, time::Instant}; 8use std::{
9 env,
10 error::Error,
11 fmt, panic,
12 path::PathBuf,
13 sync::Arc,
14 time::{Duration, Instant},
15};
9 16
10use crossbeam_channel::{select, unbounded, RecvError, Sender}; 17use crossbeam_channel::{select, unbounded, RecvError, Sender};
11use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; 18use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
12use lsp_types::{ClientCapabilities, NumberOrString, Url}; 19use lsp_types::{ClientCapabilities, NumberOrString};
13use ra_cargo_watch::{CheckOptions, CheckTask}; 20use ra_cargo_watch::{CheckOptions, CheckTask};
14use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; 21use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId};
15use ra_prof::profile; 22use ra_prof::profile;
@@ -352,7 +359,7 @@ fn loop_turn(
352 world_state.maybe_collect_garbage(); 359 world_state.maybe_collect_garbage();
353 loop_state.in_flight_libraries -= 1; 360 loop_state.in_flight_libraries -= 1;
354 } 361 }
355 Event::CheckWatcher(task) => on_check_task(task, world_state, task_sender)?, 362 Event::CheckWatcher(task) => on_check_task(pool, task, world_state, task_sender)?,
356 Event::Msg(msg) => match msg { 363 Event::Msg(msg) => match msg {
357 Message::Request(req) => on_request( 364 Message::Request(req) => on_request(
358 world_state, 365 world_state,
@@ -425,6 +432,19 @@ fn loop_turn(
425 loop_state.subscriptions.subscriptions(), 432 loop_state.subscriptions.subscriptions(),
426 ) 433 )
427 } 434 }
435
436 let loop_duration = loop_start.elapsed();
437 if loop_duration > Duration::from_millis(100) {
438 log::error!("overly long loop turn: {:?}", loop_duration);
439 if env::var("RA_PROFILE").is_ok() {
440 show_message(
441 req::MessageType::Error,
442 format!("overly long loop turn: {:?}", loop_duration),
443 &connection.sender,
444 );
445 }
446 }
447
428 Ok(()) 448 Ok(())
429} 449}
430 450
@@ -452,7 +472,7 @@ fn on_request(
452 world: &mut WorldState, 472 world: &mut WorldState,
453 pending_requests: &mut PendingRequests, 473 pending_requests: &mut PendingRequests,
454 pool: &ThreadPool, 474 pool: &ThreadPool,
455 sender: &Sender<Task>, 475 task_sender: &Sender<Task>,
456 msg_sender: &Sender<Message>, 476 msg_sender: &Sender<Message>,
457 request_received: Instant, 477 request_received: Instant,
458 req: Request, 478 req: Request,
@@ -461,7 +481,7 @@ fn on_request(
461 req: Some(req), 481 req: Some(req),
462 pool, 482 pool,
463 world, 483 world,
464 sender, 484 task_sender,
465 msg_sender, 485 msg_sender,
466 pending_requests, 486 pending_requests,
467 request_received, 487 request_received,
@@ -602,31 +622,23 @@ fn on_notification(
602} 622}
603 623
604fn on_check_task( 624fn on_check_task(
625 pool: &ThreadPool,
605 task: CheckTask, 626 task: CheckTask,
606 world_state: &mut WorldState, 627 world_state: &mut WorldState,
607 task_sender: &Sender<Task>, 628 task_sender: &Sender<Task>,
608) -> Result<()> { 629) -> Result<()> {
609 match task { 630 let urls = match task {
610 CheckTask::ClearDiagnostics => { 631 CheckTask::ClearDiagnostics => {
611 let state = Arc::get_mut(&mut world_state.check_watcher.state) 632 let state = Arc::get_mut(&mut world_state.check_watcher.state)
612 .expect("couldn't get check watcher state as mutable"); 633 .expect("couldn't get check watcher state as mutable");
613 let cleared_files = state.clear(); 634 state.clear()
614
615 // Send updated diagnostics for each cleared file
616 for url in cleared_files {
617 publish_diagnostics_for_url(&url, world_state, task_sender)?;
618 }
619 } 635 }
620 636
621 CheckTask::AddDiagnostic(url, diagnostic) => { 637 CheckTask::AddDiagnostic(url, diagnostic) => {
622 let state = Arc::get_mut(&mut world_state.check_watcher.state) 638 let state = Arc::get_mut(&mut world_state.check_watcher.state)
623 .expect("couldn't get check watcher state as mutable"); 639 .expect("couldn't get check watcher state as mutable");
624 state.add_diagnostic_with_fixes(url.clone(), diagnostic); 640 state.add_diagnostic_with_fixes(url.clone(), diagnostic);
625 641 vec![url]
626 // We manually send a diagnostic update when the watcher asks
627 // us to, to avoid the issue of having to change the file to
628 // receive updated diagnostics.
629 publish_diagnostics_for_url(&url, world_state, task_sender)?;
630 } 642 }
631 643
632 CheckTask::Status(progress) => { 644 CheckTask::Status(progress) => {
@@ -636,22 +648,30 @@ fn on_check_task(
636 }; 648 };
637 let not = notification_new::<req::Progress>(params); 649 let not = notification_new::<req::Progress>(params);
638 task_sender.send(Task::Notify(not)).unwrap(); 650 task_sender.send(Task::Notify(not)).unwrap();
651 Vec::new()
639 } 652 }
640 } 653 };
641 Ok(()) 654
642} 655 let subscriptions = urls
656 .into_iter()
657 .map(|url| {
658 let path = url.to_file_path().map_err(|()| format!("invalid uri: {}", url))?;
659 Ok(world_state.vfs.read().path2file(&path).map(|it| FileId(it.0)))
660 })
661 .filter_map(|res| res.transpose())
662 .collect::<Result<Vec<_>>>()?;
663
664 // We manually send a diagnostic update when the watcher asks
665 // us to, to avoid the issue of having to change the file to
666 // receive updated diagnostics.
667 update_file_notifications_on_threadpool(
668 pool,
669 world_state.snapshot(),
670 false,
671 task_sender.clone(),
672 subscriptions,
673 );
643 674
644fn publish_diagnostics_for_url(
645 url: &Url,
646 world_state: &WorldState,
647 task_sender: &Sender<Task>,
648) -> Result<()> {
649 let path = url.to_file_path().map_err(|()| format!("invalid uri: {}", url))?;
650 if let Some(file_id) = world_state.vfs.read().path2file(&path) {
651 let params = handlers::publish_diagnostics(&world_state.snapshot(), FileId(file_id.0))?;
652 let not = notification_new::<req::PublishDiagnostics>(params);
653 task_sender.send(Task::Notify(not)).unwrap();
654 }
655 Ok(()) 675 Ok(())
656} 676}
657 677
@@ -661,7 +681,7 @@ struct PoolDispatcher<'a> {
661 world: &'a mut WorldState, 681 world: &'a mut WorldState,
662 pending_requests: &'a mut PendingRequests, 682 pending_requests: &'a mut PendingRequests,
663 msg_sender: &'a Sender<Message>, 683 msg_sender: &'a Sender<Message>,
664 sender: &'a Sender<Task>, 684 task_sender: &'a Sender<Task>,
665 request_received: Instant, 685 request_received: Instant,
666} 686}
667 687
@@ -708,7 +728,7 @@ impl<'a> PoolDispatcher<'a> {
708 728
709 self.pool.execute({ 729 self.pool.execute({
710 let world = self.world.snapshot(); 730 let world = self.world.snapshot();
711 let sender = self.sender.clone(); 731 let sender = self.task_sender.clone();
712 move || { 732 move || {
713 let result = f(world, params); 733 let result = f(world, params);
714 let task = result_to_task::<R>(id, result); 734 let task = result_to_task::<R>(id, result);
@@ -786,7 +806,7 @@ fn update_file_notifications_on_threadpool(
786 pool: &ThreadPool, 806 pool: &ThreadPool,
787 world: WorldSnapshot, 807 world: WorldSnapshot,
788 publish_decorations: bool, 808 publish_decorations: bool,
789 sender: Sender<Task>, 809 task_sender: Sender<Task>,
790 subscriptions: Vec<FileId>, 810 subscriptions: Vec<FileId>,
791) { 811) {
792 log::trace!("updating notifications for {:?}", subscriptions); 812 log::trace!("updating notifications for {:?}", subscriptions);
@@ -802,7 +822,7 @@ fn update_file_notifications_on_threadpool(
802 } 822 }
803 Ok(params) => { 823 Ok(params) => {
804 let not = notification_new::<req::PublishDiagnostics>(params); 824 let not = notification_new::<req::PublishDiagnostics>(params);
805 sender.send(Task::Notify(not)).unwrap(); 825 task_sender.send(Task::Notify(not)).unwrap();
806 } 826 }
807 } 827 }
808 } 828 }
@@ -815,7 +835,7 @@ fn update_file_notifications_on_threadpool(
815 } 835 }
816 Ok(params) => { 836 Ok(params) => {
817 let not = notification_new::<req::PublishDecorations>(params); 837 let not = notification_new::<req::PublishDecorations>(params);
818 sender.send(Task::Notify(not)).unwrap(); 838 task_sender.send(Task::Notify(not)).unwrap();
819 } 839 }
820 } 840 }
821 } 841 }
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index c7973ddf4..4a49e9f95 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -6,9 +6,9 @@ mod google_cpu_profiler;
6 6
7use std::{ 7use std::{
8 cell::RefCell, 8 cell::RefCell,
9 collections::BTreeMap,
9 collections::HashSet, 10 collections::HashSet,
10 io::{stderr, Write}, 11 io::{stderr, Write},
11 iter::repeat,
12 mem, 12 mem,
13 sync::{ 13 sync::{
14 atomic::{AtomicBool, Ordering}, 14 atomic::{AtomicBool, Ordering},
@@ -17,7 +17,6 @@ use std::{
17 time::{Duration, Instant}, 17 time::{Duration, Instant},
18}; 18};
19 19
20use itertools::Itertools;
21use once_cell::sync::Lazy; 20use once_cell::sync::Lazy;
22 21
23pub use crate::memory_usage::{Bytes, MemoryUsage}; 22pub use crate::memory_usage::{Bytes, MemoryUsage};
@@ -216,7 +215,7 @@ impl Drop for Profiler {
216 // (otherwise we could print `0ms` despite user's `>0` filter when 215 // (otherwise we could print `0ms` despite user's `>0` filter when
217 // `duration` is just a few nanos). 216 // `duration` is just a few nanos).
218 if duration.as_millis() > longer_than.as_millis() { 217 if duration.as_millis() > longer_than.as_millis() {
219 print(0, &stack.messages, &mut stdout.lock(), longer_than, None); 218 print(&stack.messages, longer_than, &mut stdout.lock());
220 } 219 }
221 stack.messages.clear(); 220 stack.messages.clear();
222 } 221 }
@@ -227,59 +226,85 @@ impl Drop for Profiler {
227 } 226 }
228} 227}
229 228
230fn print( 229fn print(msgs: &[Message], longer_than: Duration, out: &mut impl Write) {
231 lvl: usize,
232 msgs: &[Message],
233 out: &mut impl Write,
234 longer_than: Duration,
235 total: Option<Duration>,
236) {
237 if msgs.is_empty() { 230 if msgs.is_empty() {
238 return; 231 return;
239 } 232 }
240 // The index of the first element that will be included in the slice when we recurse. 233 let children_map = idx_to_children(msgs);
241 let mut next_start = 0; 234 let root_idx = msgs.len() - 1;
242 let indent = repeat(" ").take(lvl).collect::<String>(); 235 print_for_idx(root_idx, &children_map, msgs, longer_than, out);
243 // We output hierarchy for long calls, but sum up all short calls 236}
244 let mut short = Vec::new(); 237
238fn print_for_idx(
239 current_idx: usize,
240 children_map: &[Vec<usize>],
241 msgs: &[Message],
242 longer_than: Duration,
243 out: &mut impl Write,
244) {
245 let current = &msgs[current_idx];
246 let current_indent = " ".repeat(current.level);
247 writeln!(out, "{}{:5}ms - {}", current_indent, current.duration.as_millis(), current.message)
248 .expect("printing profiling info");
249
250 let longer_than_millis = longer_than.as_millis();
251 let children_indices = &children_map[current_idx];
245 let mut accounted_for = Duration::default(); 252 let mut accounted_for = Duration::default();
246 for (i, &Message { level, duration, message: ref msg }) in msgs.iter().enumerate() { 253 let mut short_children = BTreeMap::new(); // Use `BTreeMap` to get deterministic output.
247 if level != lvl {
248 continue;
249 }
250 accounted_for += duration;
251 if duration.as_millis() > longer_than.as_millis() {
252 writeln!(out, "{}{:5}ms - {}", indent, duration.as_millis(), msg)
253 .expect("printing profiling info to stdout");
254 254
255 print(lvl + 1, &msgs[next_start..i], out, longer_than, Some(duration)); 255 for child_idx in children_indices.iter() {
256 let child = &msgs[*child_idx];
257 if child.duration.as_millis() > longer_than_millis {
258 print_for_idx(*child_idx, children_map, msgs, longer_than, out);
256 } else { 259 } else {
257 short.push((msg, duration)) 260 let pair = short_children.entry(&child.message).or_insert((Duration::default(), 0));
261 pair.0 += child.duration;
262 pair.1 += 1;
258 } 263 }
264 accounted_for += child.duration;
265 }
259 266
260 next_start = i + 1; 267 for (child_msg, (duration, count)) in short_children.iter() {
268 let millis = duration.as_millis();
269 writeln!(out, " {}{:5}ms - {} ({} calls)", current_indent, millis, child_msg, count)
270 .expect("printing profiling info");
261 } 271 }
262 short.sort_by_key(|(msg, _time)| *msg); 272
263 for (msg, entires) in short.iter().group_by(|(msg, _time)| msg).into_iter() { 273 let unaccounted_millis = (current.duration - accounted_for).as_millis();
264 let mut count = 0; 274 if !children_indices.is_empty()
265 let mut total_duration = Duration::default(); 275 && unaccounted_millis > 0
266 entires.for_each(|(_msg, time)| { 276 && unaccounted_millis > longer_than_millis
267 count += 1; 277 {
268 total_duration += *time; 278 writeln!(out, " {}{:5}ms - ???", current_indent, unaccounted_millis)
269 }); 279 .expect("printing profiling info");
270 writeln!(out, "{}{:5}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count)
271 .expect("printing profiling info to stdout");
272 } 280 }
281}
273 282
274 if let Some(total) = total { 283/// Returns a mapping from an index in the `msgs` to the vector with the indices of its children.
275 if let Some(unaccounted) = total.checked_sub(accounted_for) { 284///
276 let unaccounted_millis = unaccounted.as_millis(); 285/// This assumes that the entries in `msgs` are in the order of when the calls to `profile` finish.
277 if unaccounted_millis > longer_than.as_millis() && unaccounted_millis > 0 { 286/// In other words, a postorder of the call graph. In particular, the root is the last element of
278 writeln!(out, "{}{:5}ms - ???", indent, unaccounted_millis) 287/// `msgs`.
279 .expect("printing profiling info to stdout"); 288fn idx_to_children(msgs: &[Message]) -> Vec<Vec<usize>> {
280 } 289 // Initialize with the index of the root; `msgs` and `ancestors` should be never empty.
290 assert!(!msgs.is_empty());
291 let mut ancestors = vec![msgs.len() - 1];
292 let mut result: Vec<Vec<usize>> = vec![vec![]; msgs.len()];
293 for (idx, msg) in msgs[..msgs.len() - 1].iter().enumerate().rev() {
294 // We need to find the parent of the current message, i.e., the last ancestor that has a
295 // level lower than the current message.
296 while msgs[*ancestors.last().unwrap()].level >= msg.level {
297 ancestors.pop();
281 } 298 }
299 result[*ancestors.last().unwrap()].push(idx);
300 ancestors.push(idx);
301 }
302 // Note that above we visited all children from the last to the first one. Let's reverse vectors
303 // to get the more natural order where the first element is the first child.
304 for vec in result.iter_mut() {
305 vec.reverse();
282 } 306 }
307 result
283} 308}
284 309
285/// Prints backtrace to stderr, useful for debugging. 310/// Prints backtrace to stderr, useful for debugging.
@@ -388,7 +413,7 @@ mod tests {
388 Message { level: 1, duration: Duration::from_nanos(2), message: "bar".to_owned() }, 413 Message { level: 1, duration: Duration::from_nanos(2), message: "bar".to_owned() },
389 Message { level: 0, duration: Duration::from_millis(1), message: "foo".to_owned() }, 414 Message { level: 0, duration: Duration::from_millis(1), message: "foo".to_owned() },
390 ]; 415 ];
391 print(0, &msgs, &mut result, Duration::from_millis(0), Some(Duration::from_millis(1))); 416 print(&msgs, Duration::from_millis(0), &mut result);
392 // The calls to `bar` are so short that they'll be rounded to 0ms and should get collapsed 417 // The calls to `bar` are so short that they'll be rounded to 0ms and should get collapsed
393 // when printing. 418 // when printing.
394 assert_eq!( 419 assert_eq!(
@@ -404,7 +429,7 @@ mod tests {
404 Message { level: 1, duration: Duration::from_millis(2), message: "bar".to_owned() }, 429 Message { level: 1, duration: Duration::from_millis(2), message: "bar".to_owned() },
405 Message { level: 0, duration: Duration::from_millis(5), message: "foo".to_owned() }, 430 Message { level: 0, duration: Duration::from_millis(5), message: "foo".to_owned() },
406 ]; 431 ];
407 print(0, &msgs, &mut result, Duration::from_millis(0), Some(Duration::from_millis(1))); 432 print(&msgs, Duration::from_millis(0), &mut result);
408 assert_eq!( 433 assert_eq!(
409 std::str::from_utf8(&result).unwrap().lines().collect::<Vec<_>>(), 434 std::str::from_utf8(&result).unwrap().lines().collect::<Vec<_>>(),
410 vec![ 435 vec![
@@ -426,7 +451,7 @@ mod tests {
426 Message { level: 1, duration: Duration::from_millis(4), message: "bar".to_owned() }, 451 Message { level: 1, duration: Duration::from_millis(4), message: "bar".to_owned() },
427 Message { level: 0, duration: Duration::from_millis(9), message: "foo".to_owned() }, 452 Message { level: 0, duration: Duration::from_millis(9), message: "foo".to_owned() },
428 ]; 453 ];
429 print(0, &msgs, &mut result, Duration::from_millis(0), None); 454 print(&msgs, Duration::from_millis(0), &mut result);
430 assert_eq!( 455 assert_eq!(
431 std::str::from_utf8(&result).unwrap().lines().collect::<Vec<_>>(), 456 std::str::from_utf8(&result).unwrap().lines().collect::<Vec<_>>(),
432 vec![ 457 vec![
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 659f77b71..336c594a6 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -21,6 +21,12 @@ pub use difference::Changeset as __Changeset;
21 21
22pub const CURSOR_MARKER: &str = "<|>"; 22pub const CURSOR_MARKER: &str = "<|>";
23 23
24/// Asserts that two strings are equal, otherwise displays a rich diff between them.
25///
26/// The diff shows changes from the "original" left string to the "actual" right string.
27///
28/// All arguments starting from and including the 3rd one are passed to
29/// `eprintln!()` macro in case of text inequality.
24#[macro_export] 30#[macro_export]
25macro_rules! assert_eq_text { 31macro_rules! assert_eq_text {
26 ($left:expr, $right:expr) => { 32 ($left:expr, $right:expr) => {
@@ -42,6 +48,7 @@ macro_rules! assert_eq_text {
42 }}; 48 }};
43} 49}
44 50
51/// Infallible version of `try_extract_offset()`.
45pub fn extract_offset(text: &str) -> (TextUnit, String) { 52pub fn extract_offset(text: &str) -> (TextUnit, String) {
46 match try_extract_offset(text) { 53 match try_extract_offset(text) {
47 None => panic!("text should contain cursor marker"), 54 None => panic!("text should contain cursor marker"),
@@ -49,6 +56,8 @@ pub fn extract_offset(text: &str) -> (TextUnit, String) {
49 } 56 }
50} 57}
51 58
59/// Returns the offset of the first occurence of `<|>` marker and the copy of `text`
60/// without the marker.
52fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> { 61fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> {
53 let cursor_pos = text.find(CURSOR_MARKER)?; 62 let cursor_pos = text.find(CURSOR_MARKER)?;
54 let mut new_text = String::with_capacity(text.len() - CURSOR_MARKER.len()); 63 let mut new_text = String::with_capacity(text.len() - CURSOR_MARKER.len());
@@ -58,6 +67,7 @@ fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> {
58 Some((cursor_pos, new_text)) 67 Some((cursor_pos, new_text))
59} 68}
60 69
70/// Infallible version of `try_extract_range()`.
61pub fn extract_range(text: &str) -> (TextRange, String) { 71pub fn extract_range(text: &str) -> (TextRange, String) {
62 match try_extract_range(text) { 72 match try_extract_range(text) {
63 None => panic!("text should contain cursor marker"), 73 None => panic!("text should contain cursor marker"),
@@ -65,6 +75,8 @@ pub fn extract_range(text: &str) -> (TextRange, String) {
65 } 75 }
66} 76}
67 77
78/// Returns `TextRange` between the first two markers `<|>...<|>` and the copy
79/// of `text` without both of these markers.
68fn try_extract_range(text: &str) -> Option<(TextRange, String)> { 80fn try_extract_range(text: &str) -> Option<(TextRange, String)> {
69 let (start, text) = try_extract_offset(text)?; 81 let (start, text) = try_extract_offset(text)?;
70 let (end, text) = try_extract_offset(&text)?; 82 let (end, text) = try_extract_offset(&text)?;
@@ -85,6 +97,11 @@ impl From<RangeOrOffset> for TextRange {
85 } 97 }
86} 98}
87 99
100/// Extracts `TextRange` or `TextUnit` depending on the amount of `<|>` markers
101/// found in `text`.
102///
103/// # Panics
104/// Panics if no `<|>` marker is present in the `text`.
88pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) { 105pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) {
89 if let Some((range, text)) = try_extract_range(text) { 106 if let Some((range, text)) = try_extract_range(text) {
90 return (RangeOrOffset::Range(range), text); 107 return (RangeOrOffset::Range(range), text);
@@ -93,7 +110,7 @@ pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) {
93 (RangeOrOffset::Offset(offset), text) 110 (RangeOrOffset::Offset(offset), text)
94} 111}
95 112
96/// Extracts ranges, marked with `<tag> </tag>` paris from the `text` 113/// Extracts ranges, marked with `<tag> </tag>` pairs from the `text`
97pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) { 114pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
98 let open = format!("<{}>", tag); 115 let open = format!("<{}>", tag);
99 let close = format!("</{}>", tag); 116 let close = format!("</{}>", tag);
@@ -127,9 +144,9 @@ pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
127 (ranges, res) 144 (ranges, res)
128} 145}
129 146
147/// Inserts `<|>` marker into the `text` at `offset`.
130pub fn add_cursor(text: &str, offset: TextUnit) -> String { 148pub fn add_cursor(text: &str, offset: TextUnit) -> String {
131 let offset: u32 = offset.into(); 149 let offset: usize = offset.to_usize();
132 let offset: usize = offset as usize;
133 let mut res = String::new(); 150 let mut res = String::new();
134 res.push_str(&text[..offset]); 151 res.push_str(&text[..offset]);
135 res.push_str("<|>"); 152 res.push_str("<|>");
@@ -152,19 +169,6 @@ pub struct FixtureEntry {
152/// // - other meta 169/// // - other meta
153/// ``` 170/// ```
154pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> { 171pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
155 let mut res = Vec::new();
156 let mut buf = String::new();
157 let mut meta: Option<&str> = None;
158
159 macro_rules! flush {
160 () => {
161 if let Some(meta) = meta {
162 res.push(FixtureEntry { meta: meta.to_string(), text: buf.clone() });
163 buf.clear();
164 }
165 };
166 };
167
168 let margin = fixture 172 let margin = fixture
169 .lines() 173 .lines()
170 .filter(|it| it.trim_start().starts_with("//-")) 174 .filter(|it| it.trim_start().starts_with("//-"))
@@ -172,7 +176,7 @@ pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
172 .next() 176 .next()
173 .expect("empty fixture"); 177 .expect("empty fixture");
174 178
175 let lines = fixture 179 let mut lines = fixture
176 .split('\n') // don't use `.lines` to not drop `\r\n` 180 .split('\n') // don't use `.lines` to not drop `\r\n`
177 .filter_map(|line| { 181 .filter_map(|line| {
178 if line.len() >= margin { 182 if line.len() >= margin {
@@ -184,17 +188,16 @@ pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
184 } 188 }
185 }); 189 });
186 190
187 for line in lines { 191 let mut res: Vec<FixtureEntry> = Vec::new();
192 for line in lines.by_ref() {
188 if line.starts_with("//-") { 193 if line.starts_with("//-") {
189 flush!(); 194 let meta = line["//-".len()..].trim().to_string();
190 buf.clear(); 195 res.push(FixtureEntry { meta, text: String::new() })
191 meta = Some(line["//-".len()..].trim()); 196 } else if let Some(entry) = res.last_mut() {
192 continue; 197 entry.text.push_str(line);
198 entry.text.push('\n');
193 } 199 }
194 buf.push_str(line);
195 buf.push('\n');
196 } 200 }
197 flush!();
198 res 201 res
199} 202}
200 203
@@ -236,11 +239,10 @@ fn lines_match_works() {
236 assert!(!lines_match("b", "cb")); 239 assert!(!lines_match("b", "cb"));
237} 240}
238 241
239// Compares JSON object for approximate equality. 242/// Compares JSON object for approximate equality.
240// You can use `[..]` wildcard in strings (useful for OS dependent things such 243/// You can use `[..]` wildcard in strings (useful for OS dependent things such
241// as paths). You can use a `"{...}"` string literal as a wildcard for 244/// as paths). You can use a `"{...}"` string literal as a wildcard for
242// arbitrary nested JSON (useful for parts of object emitted by other programs 245/// arbitrary nested JSON. Arrays are sorted before comparison.
243// (e.g. rustc) rather than Cargo itself). Arrays are sorted before comparison.
244pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> { 246pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> {
245 use serde_json::Value::*; 247 use serde_json::Value::*;
246 match (expected, actual) { 248 match (expected, actual) {
@@ -286,6 +288,14 @@ pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a
286 } 288 }
287} 289}
288 290
291/// Calls callback `f` with input code and file paths of all `.rs` files from `test_data_dir`
292/// subdirectories defined by `paths`.
293///
294/// If the content of the matching `.txt` file differs from the output of `f()`
295/// the test will fail.
296///
297/// If there is no matching `.txt` file it will be created and filled with the
298/// output of `f()`, but the test will fail.
289pub fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], f: F) 299pub fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], f: F)
290where 300where
291 F: Fn(&str, &Path) -> String, 301 F: Fn(&str, &Path) -> String,
@@ -307,6 +317,7 @@ where
307 } 317 }
308} 318}
309 319
320/// Collects all `.rs` files from `test_data_dir` subdirectories defined by `paths`.
310pub fn collect_tests(test_data_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> { 321pub fn collect_tests(test_data_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> {
311 paths 322 paths
312 .iter() 323 .iter()
@@ -321,6 +332,7 @@ pub fn collect_tests(test_data_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, Stri
321 .collect() 332 .collect()
322} 333}
323 334
335/// Collects paths to all `.rs` files from `dir` in a sorted `Vec<PathBuf>`.
324fn test_from_dir(dir: &Path) -> Vec<PathBuf> { 336fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
325 let mut acc = Vec::new(); 337 let mut acc = Vec::new();
326 for file in fs::read_dir(&dir).unwrap() { 338 for file in fs::read_dir(&dir).unwrap() {
@@ -334,6 +346,7 @@ fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
334 acc 346 acc
335} 347}
336 348
349/// Returns the path to the root directory of `rust-analyzer` project.
337pub fn project_dir() -> PathBuf { 350pub fn project_dir() -> PathBuf {
338 let dir = env!("CARGO_MANIFEST_DIR"); 351 let dir = env!("CARGO_MANIFEST_DIR");
339 PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned() 352 PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned()
@@ -356,6 +369,9 @@ pub fn read_text(path: &Path) -> String {
356 .replace("\r\n", "\n") 369 .replace("\r\n", "\n")
357} 370}
358 371
372/// Returns `false` if slow tests should not run, otherwise returns `true` and
373/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag
374/// that slow tests did run.
359pub fn skip_slow_tests() -> bool { 375pub fn skip_slow_tests() -> bool {
360 let should_skip = std::env::var("CI").is_err() && std::env::var("RUN_SLOW_TESTS").is_err(); 376 let should_skip = std::env::var("CI").is_err() && std::env::var("RUN_SLOW_TESTS").is_err();
361 if should_skip { 377 if should_skip {
@@ -367,8 +383,9 @@ pub fn skip_slow_tests() -> bool {
367 should_skip 383 should_skip
368} 384}
369 385
370const REWRITE: bool = false; 386/// Asserts that `expected` and `actual` strings are equal. If they differ only
371 387/// in trailing or leading whitespace the test won't fail and
388/// the contents of `actual` will be written to the file located at `path`.
372fn assert_equal_text(expected: &str, actual: &str, path: &Path) { 389fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
373 if expected == actual { 390 if expected == actual {
374 return; 391 return;
@@ -381,6 +398,7 @@ fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
381 fs::write(path, actual).unwrap(); 398 fs::write(path, actual).unwrap();
382 return; 399 return;
383 } 400 }
401 const REWRITE: bool = false;
384 if REWRITE { 402 if REWRITE {
385 println!("rewriting {}", pretty_path.display()); 403 println!("rewriting {}", pretty_path.display());
386 fs::write(path, actual).unwrap(); 404 fs::write(path, actual).unwrap();
diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/marks.rs
index fe1813947..f8fabfaff 100644
--- a/crates/test_utils/src/marks.rs
+++ b/crates/test_utils/src/marks.rs
@@ -1,4 +1,4 @@
1//! This module implements manually tracked test coverage, which useful for 1//! This module implements manually tracked test coverage, which is useful for
2//! quickly finding a test responsible for testing a particular bit of code. 2//! quickly finding a test responsible for testing a particular bit of code.
3//! 3//!
4//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html> 4//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html>
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 2f6215d6b..d30727786 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -26,15 +26,6 @@ Discussion happens in this Zulip stream:
26 26
27https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 27https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0
28 28
29# Work List
30
31We have this "work list" paper document:
32
33https://paper.dropbox.com/doc/RLS-2.0-work-list--AZ3BgHKKCtqszbsi3gi6sjchAQ-42vbnxzuKq2lKwW0mkn8Y
34
35It shows what everyone is working on right now. If you want to (this is not
36mandatory), add yourself to the list!
37
38# Issue Labels 29# Issue Labels
39 30
40* [good-first-issue](https://github.com/rust-analyzer/rust-analyzer/labels/good%20first%20issue) 31* [good-first-issue](https://github.com/rust-analyzer/rust-analyzer/labels/good%20first%20issue)
@@ -50,10 +41,12 @@ mandatory), add yourself to the list!
50 41
51# CI 42# CI
52 43
53We use Travis for CI. Most of the things, including formatting, are checked by 44We use GitHub Actions for CI. Most of the things, including formatting, are checked by
54`cargo test` so, if `cargo test` passes locally, that's a good sign that CI will 45`cargo test` so, if `cargo test` passes locally, that's a good sign that CI will
55be green as well. We use bors-ng to enforce the [not rocket 46be green as well. The only exception is that long-running by default a skipped locally.
56science](https://graydon2.dreamwidth.org/1597.html) rule. 47Use `env RUN_SLOW_TESTS=1 cargo test` to run the full suite.
48
49We use bors-ng to enforce the [not rocket science](https://graydon2.dreamwidth.org/1597.html) rule.
57 50
58You can run `cargo xtask install-pre-commit-hook` to install git-hook to run rustfmt on commit. 51You can run `cargo xtask install-pre-commit-hook` to install git-hook to run rustfmt on commit.
59 52
@@ -81,42 +74,41 @@ relevant test and execute it (VS Code includes an action for running a single
81test). 74test).
82 75
83However, launching a VS Code instance with locally build language server is 76However, launching a VS Code instance with locally build language server is
84possible. There's even a VS Code task for this, so just <kbd>F5</kbd> should 77possible. There's "Run Extension (Dev Server)" launch configuration for this.
85work (thanks, [@andrew-w-ross](https://github.com/andrew-w-ross)!). 78
86 79In general, I use one of the following workflows for fixing bugs and
87I often just install development version with `cargo xtask install --server --jemalloc` and 80implementing features.
88restart the host VS Code. 81
89 82If the problem concerns only internal parts of rust-analyzer (ie, I don't need
90See [./debugging.md](./debugging.md) for how to attach to rust-analyzer with 83to touch `ra_lsp_server` crate or typescript code), there is a unit-test for it.
91debugger, and don't forget that rust-analyzer has useful `pd` snippet and `dbg` 84So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and
92postfix completion for printf debugging :-) 85then just do printf-driven development/debugging. As a sanity check after I'm
93 86done, I use `cargo xtask install --server` and **Reload Window** action in VS
94# Working With VS Code Extension 87Code to sanity check that the thing works as I expect.
95 88
96To work on the VS Code extension, launch code inside `editors/code` and use `F5` 89If the problem concerns only the VS Code extension, I use **Run Extension**
97to launch/debug. To automatically apply formatter and linter suggestions, use 90launch configuration from `launch.json`. Notably, this uses the usual
98`npm run fix`. 91`ra_lsp_server` binary from `PATH`. After I am done with the fix, I use `cargo
99 92xtask install --client-code` to try the new extension for real.
100Tests are located inside `src/test` and are named `*.test.ts`. They use the 93
101[Mocha](https://mochajs.org) test framework and the builtin Node 94If I need to fix something in the `ra_lsp_server` crate, I feel sad because it's
102[assert](https://nodejs.org/api/assert.html) module. Unlike normal Node tests 95on the boundary between the two processes, and working there is slow. I usually
103they must be hosted inside a VS Code instance. This can be done in one of two 96just `cargo xtask install --server` and poke changes from my live environment.
104ways: 97Note that this uses `--release`, which is usually faster overall, because
105 98loading stdlib into debug version of rust-analyzer takes a lot of time. To speed
1061. When `F5` debugging in VS Code select the `Extension Tests` configuration 99things up, sometimes I open a temporary hello-world project which has
107 from the drop-down at the top of the Debug View. This will launch a temporary 100`"rust-analyzer.withSysroot": false` in `.code/settings.json`. This flag causes
108 instance of VS Code. The test results will appear in the "Debug Console" tab 101rust-analyzer to skip loading the sysroot, which greatly reduces the amount of
109 of the primary VS Code instance. 102things rust-analyzer needs to do, and makes printf's more useful. Note that you
110 103should only use `eprint!` family of macros for debugging: stdout is used for LSP
1112. Run `npm test` from the command line. Although this is initiated from the 104communication, and `print!` would break it.
112 command line it is not headless; it will also launch a temporary instance of 105
113 VS Code. 106If I need to fix something simultaneously in the server and in the client, I
114 107feel even more sad. I don't have a specific workflow for this case.
115Due to the requirements of running the tests inside VS Code they are **not run 108
116on CI**. When making changes to the extension please ensure the tests are not 109Additionally, I use `cargo run --release -p ra_cli -- analysis-stats
117broken locally before opening a Pull Request. 110path/to/some/rust/crate` to run a batch analysis. This is primaraly useful for
118 111performance optimiations, or for bug minimization.
119To install **only** the VS Code extension, use `cargo xtask install --client-code`.
120 112
121# Logging 113# Logging
122 114
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index 629645757..9675ed0b6 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -12,6 +12,9 @@ analyzer:
12 12
13https://www.youtube.com/playlist?list=PL85XCvVPmGQho7MZkdW-wtPtuJcFpzycE 13https://www.youtube.com/playlist?list=PL85XCvVPmGQho7MZkdW-wtPtuJcFpzycE
14 14
15Note that the guide and videos are pretty dated, this document should be in
16generally fresher.
17
15## The Big Picture 18## The Big Picture
16 19
17![](https://user-images.githubusercontent.com/1711539/50114578-e8a34280-0255-11e9-902c-7cfc70747966.png) 20![](https://user-images.githubusercontent.com/1711539/50114578-e8a34280-0255-11e9-902c-7cfc70747966.png)
@@ -20,13 +23,12 @@ On the highest level, rust-analyzer is a thing which accepts input source code
20from the client and produces a structured semantic model of the code. 23from the client and produces a structured semantic model of the code.
21 24
22More specifically, input data consists of a set of test files (`(PathBuf, 25More specifically, input data consists of a set of test files (`(PathBuf,
23String)` pairs) and information about project structure, captured in the so called 26String)` pairs) and information about project structure, captured in the so
24`CrateGraph`. The crate graph specifies which files are crate roots, which cfg 27called `CrateGraph`. The crate graph specifies which files are crate roots,
25flags are specified for each crate (TODO: actually implement this) and what 28which cfg flags are specified for each crate and what dependencies exist between
26dependencies exist between the crates. The analyzer keeps all this input data in 29the crates. The analyzer keeps all this input data in memory and never does any
27memory and never does any IO. Because the input data is source code, which 30IO. Because the input data are source code, which typically measures in tens of
28typically measures in tens of megabytes at most, keeping all input data in 31megabytes at most, keeping everything in memory is OK.
29memory is OK.
30 32
31A "structured semantic model" is basically an object-oriented representation of 33A "structured semantic model" is basically an object-oriented representation of
32modules, functions and types which appear in the source code. This representation 34modules, functions and types which appear in the source code. This representation
@@ -43,37 +45,39 @@ can be quickly updated for small modifications.
43## Code generation 45## Code generation
44 46
45Some of the components of this repository are generated through automatic 47Some of the components of this repository are generated through automatic
46processes. These are outlined below: 48processes. `cargo xtask codegen` runs all generation tasks. Generated code is
49commited to the git repository.
50
51In particular, `cargo xtask codegen` generates:
52
531. [`syntax_kind/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_parser/src/syntax_kind/generated.rs)
54 -- the set of terminals and non-terminals of rust grammar.
47 55
48- `cargo xtask codegen`: The kinds of tokens that are reused in several places, so a generator 562. [`ast/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/src/ast/generated.rs)
49 is used. We use `quote!` macro to generate the files listed below, based on 57 -- AST data structure.
50 the grammar described in [grammar.ron]:
51 - [ast/generated.rs][ast generated]
52 - [syntax_kind/generated.rs][syntax_kind generated]
53 58
54[grammar.ron]: ../../crates/ra_syntax/src/grammar.ron 59.3 [`doc_tests/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_assists/src/doc_tests/generated.rs),
55[ast generated]: ../../crates/ra_syntax/src/ast/generated.rs 60 [`test_data/parser/inline`](https://github.com/rust-analyzer/rust-analyzer/tree/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/test_data/parser/inline)
56[syntax_kind generated]: ../../crates/ra_parser/src/syntax_kind/generated.rs 61 -- tests for assists and the parser.
62
63The source for 1 and 2 is in [`ast_src.rs`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/xtask/src/ast_src.rs).
57 64
58## Code Walk-Through 65## Code Walk-Through
59 66
60### `crates/ra_syntax`, `crates/ra_parser` 67### `crates/ra_syntax`, `crates/ra_parser`
61 68
62Rust syntax tree structure and parser. See 69Rust syntax tree structure and parser. See
63[RFC](https://github.com/rust-lang/rfcs/pull/2256) for some design notes. 70[RFC](https://github.com/rust-lang/rfcs/pull/2256) and [./syntax.md](./syntax.md) for some design notes.
64 71
65- [rowan](https://github.com/rust-analyzer/rowan) library is used for constructing syntax trees. 72- [rowan](https://github.com/rust-analyzer/rowan) library is used for constructing syntax trees.
66- `grammar` module is the actual parser. It is a hand-written recursive descent parser, which 73- `grammar` module is the actual parser. It is a hand-written recursive descent parser, which
67 produces a sequence of events like "start node X", "finish node Y". It works similarly to [kotlin's parser](https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java), 74 produces a sequence of events like "start node X", "finish node Y". It works similarly to [kotlin's parser](https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java),
68 which is a good source of inspiration for dealing with syntax errors and incomplete input. Original [libsyntax parser](https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs) 75 which is a good source of inspiration for dealing with syntax errors and incomplete input. Original [libsyntax parser](https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs)
69 is what we use for the definition of the Rust language. 76 is what we use for the definition of the Rust language.
70- `parser_api/parser_impl` bridges the tree-agnostic parser from `grammar` with `rowan` trees. 77- `TreeSink` and `TokenSource` traits bridge the tree-agnostic parser from `grammar` with `rowan` trees.
71 This is the thing that turns a flat list of events into a tree (see `EventProcessor`)
72- `ast` provides a type safe API on top of the raw `rowan` tree. 78- `ast` provides a type safe API on top of the raw `rowan` tree.
73- `grammar.ron` RON description of the grammar, which is used to 79- `ast_src` description of the grammar, which is used to generate `syntax_kinds`
74 generate `syntax_kinds` and `ast` modules, using `cargo xtask codegen` command. 80 and `ast` modules, using `cargo xtask codegen` command.
75- `algo`: generic tree algorithms, including `walk` for O(1) stack
76 space tree traversal (this is cool).
77 81
78Tests for ra_syntax are mostly data-driven: `test_data/parser` contains subdirectories with a bunch of `.rs` 82Tests for ra_syntax are mostly data-driven: `test_data/parser` contains subdirectories with a bunch of `.rs`
79(test vectors) and `.txt` files with corresponding syntax trees. During testing, we check 83(test vectors) and `.txt` files with corresponding syntax trees. During testing, we check
@@ -81,6 +85,10 @@ Tests for ra_syntax are mostly data-driven: `test_data/parser` contains subdirec
81tests). Additionally, running `cargo xtask codegen` will walk the grammar module and collect 85tests). Additionally, running `cargo xtask codegen` will walk the grammar module and collect
82all `// test test_name` comments into files inside `test_data/parser/inline` directory. 86all `// test test_name` comments into files inside `test_data/parser/inline` directory.
83 87
88Note
89[`api_walkthrough`](https://github.com/rust-analyzer/rust-analyzer/blob/2fb6af89eb794f775de60b82afe56b6f986c2a40/crates/ra_syntax/src/lib.rs#L190-L348)
90in particular: it shows off various methods of working with syntax tree.
91
84See [#93](https://github.com/rust-analyzer/rust-analyzer/pull/93) for an example PR which 92See [#93](https://github.com/rust-analyzer/rust-analyzer/pull/93) for an example PR which
85fixes a bug in the grammar. 93fixes a bug in the grammar.
86 94
@@ -94,18 +102,22 @@ defines most of the "input" queries: facts supplied by the client of the
94analyzer. Reading the docs of the `ra_db::input` module should be useful: 102analyzer. Reading the docs of the `ra_db::input` module should be useful:
95everything else is strictly derived from those inputs. 103everything else is strictly derived from those inputs.
96 104
97### `crates/ra_hir` 105### `crates/ra_hir*` crates
98 106
99HIR provides high-level "object oriented" access to Rust code. 107HIR provides high-level "object oriented" access to Rust code.
100 108
101The principal difference between HIR and syntax trees is that HIR is bound to a 109The principal difference between HIR and syntax trees is that HIR is bound to a
102particular crate instance. That is, it has cfg flags and features applied (in 110particular crate instance. That is, it has cfg flags and features applied. So,
103theory, in practice this is to be implemented). So, the relation between 111the relation between syntax and HIR is many-to-one. The `source_binder` module
104syntax and HIR is many-to-one. The `source_binder` module is responsible for 112is responsible for guessing a HIR for a particular source position.
105guessing a HIR for a particular source position.
106 113
107Underneath, HIR works on top of salsa, using a `HirDatabase` trait. 114Underneath, HIR works on top of salsa, using a `HirDatabase` trait.
108 115
116`ra_hir_xxx` crates have a strong ECS flavor, in that they work with raw ids and
117directly query the databse.
118
119The top-level `ra_hir` façade crate wraps ids into a more OO-flavored API.
120
109### `crates/ra_ide` 121### `crates/ra_ide`
110 122
111A stateful library for analyzing many Rust files as they change. `AnalysisHost` 123A stateful library for analyzing many Rust files as they change. `AnalysisHost`
@@ -135,18 +147,9 @@ different from data on disk. This is more or less the single really
135platform-dependent component, so it lives in a separate repository and has an 147platform-dependent component, so it lives in a separate repository and has an
136extensive cross-platform CI testing. 148extensive cross-platform CI testing.
137 149
138### `crates/gen_lsp_server`
139
140A language server scaffold, exposing a synchronous crossbeam-channel based API.
141This crate handles protocol handshaking and parsing messages, while you
142control the message dispatch loop yourself.
143
144Run with `RUST_LOG=sync_lsp_server=debug` to see all the messages.
145
146### `crates/ra_cli` 150### `crates/ra_cli`
147 151
148A CLI interface to rust-analyzer. 152A CLI interface to rust-analyzer, mainly for testing.
149
150 153
151## Testing Infrastructure 154## Testing Infrastructure
152 155
diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md
index f868e6998..1ccf4dca2 100644
--- a/docs/dev/debugging.md
+++ b/docs/dev/debugging.md
@@ -1,5 +1,7 @@
1# Debugging vs Code plugin and the Language Server 1# Debugging vs Code plugin and the Language Server
2 2
3**NOTE:** the information here is mostly obsolete
4
3Install [LLDB](https://lldb.llvm.org/) and the [LLDB Extension](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb). 5Install [LLDB](https://lldb.llvm.org/) and the [LLDB Extension](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb).
4 6
5Checkout rust rust-analyzer and open it in vscode. 7Checkout rust rust-analyzer and open it in vscode.
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index d38a45b85..f92ce1fe2 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -25,9 +25,9 @@
25 } 25 }
26 }, 26 },
27 "@rollup/plugin-commonjs": { 27 "@rollup/plugin-commonjs": {
28 "version": "11.0.0", 28 "version": "11.0.1",
29 "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.0.0.tgz", 29 "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.0.1.tgz",
30 "integrity": "sha512-jnm//T5ZWOZ6zmJ61fReSCBOif+Ax8dHVoVggA+d2NA7T4qCWgQ3KYr+zN2faGEYLpe1wa03IzvhR+sqVLxUWg==", 30 "integrity": "sha512-SaVUoaLDg3KnIXC5IBNIspr1APTYDzk05VaYcI6qz+0XX3ZlSCwAkfAhNSOxfd5GAdcm/63Noi4TowOY9MpcDg==",
31 "dev": true, 31 "dev": true,
32 "requires": { 32 "requires": {
33 "@rollup/pluginutils": "^3.0.0", 33 "@rollup/pluginutils": "^3.0.0",
@@ -38,9 +38,9 @@
38 } 38 }
39 }, 39 },
40 "@rollup/plugin-node-resolve": { 40 "@rollup/plugin-node-resolve": {
41 "version": "6.0.0", 41 "version": "6.1.0",
42 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-6.0.0.tgz", 42 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-6.1.0.tgz",
43 "integrity": "sha512-GqWz1CfXOsqpeVMcoM315+O7zMxpRsmhWyhJoxLFHVSp9S64/u02i7len/FnbTNbmgYs+sZyilasijH8UiuboQ==", 43 "integrity": "sha512-Cv7PDIvxdE40SWilY5WgZpqfIUEaDxFxs89zCAHjqyRwlTSuql4M5hjIuc5QYJkOH0/vyiyNXKD72O+LhRipGA==",
44 "dev": true, 44 "dev": true,
45 "requires": { 45 "requires": {
46 "@rollup/pluginutils": "^3.0.0", 46 "@rollup/pluginutils": "^3.0.0",
@@ -51,34 +51,42 @@
51 } 51 }
52 }, 52 },
53 "@rollup/plugin-typescript": { 53 "@rollup/plugin-typescript": {
54 "version": "2.0.1", 54 "version": "2.1.0",
55 "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-2.0.1.tgz", 55 "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-2.1.0.tgz",
56 "integrity": "sha512-UA/bN/DlHN19xdOllXmp7G7pM2ac9dQMg0q2T1rg4Bogzb7oHXj2WGafpiNpEm54PivcJdzGRJvRnI6zCISW3w==", 56 "integrity": "sha512-7lXKGY06aofrceVez/YnN2axttFdHSqlUBpCJ6ebzDfxwLDKMgSV5lD4ykBcdgE7aK3egxuLkD/HKyRB5L8Log==",
57 "dev": true, 57 "dev": true,
58 "requires": { 58 "requires": {
59 "@rollup/pluginutils": "^3.0.0", 59 "@rollup/pluginutils": "^3.0.0",
60 "resolve": "^1.12.2" 60 "resolve": "^1.13.1"
61 } 61 }
62 }, 62 },
63 "@rollup/pluginutils": { 63 "@rollup/pluginutils": {
64 "version": "3.0.1", 64 "version": "3.0.6",
65 "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.1.tgz", 65 "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.6.tgz",
66 "integrity": "sha512-PmNurkecagFimv7ZdKCVOfQuqKDPkrcpLFxRBcQ00LYr4HAjJwhCFxBiY2Xoletll2htTIiXBg6g0Yg21h2M3w==", 66 "integrity": "sha512-Nb6U7sg11v8D+E4mxRxwT+UumUL7MSnwI8V1SJB3THyW2MOGD/Q6GyxLtpnjrbT3zTRPSozzDMyVZwemgldO3w==",
67 "dev": true, 67 "dev": true,
68 "requires": { 68 "requires": {
69 "estree-walker": "^0.6.1" 69 "estree-walker": "^1.0.1"
70 },
71 "dependencies": {
72 "estree-walker": {
73 "version": "1.0.1",
74 "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
75 "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
76 "dev": true
77 }
70 } 78 }
71 }, 79 },
72 "@types/estree": { 80 "@types/estree": {
73 "version": "0.0.41", 81 "version": "0.0.39",
74 "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.41.tgz", 82 "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
75 "integrity": "sha512-rIAmXyJlqw4KEBO7+u9gxZZSQHaCNnIzYrnNmYVpgfJhxTqO0brCX0SYpqUTkVI5mwwUwzmtspLBGBKroMeynA==", 83 "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
76 "dev": true 84 "dev": true
77 }, 85 },
78 "@types/node": { 86 "@types/node": {
79 "version": "12.12.22", 87 "version": "12.12.25",
80 "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.22.tgz", 88 "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.25.tgz",
81 "integrity": "sha512-r5i93jqbPWGXYXxianGATOxTelkp6ih/U0WVnvaqAvTqM+0U6J3kw6Xk6uq/dWNRkEVw/0SLcO5ORXbVNz4FMQ==", 89 "integrity": "sha512-nf1LMGZvgFX186geVZR1xMZKKblJiRfiASTHw85zED2kI1yDKHDwTKMdkaCbTlXoRKlGKaDfYywt+V0As30q3w==",
82 "dev": true 90 "dev": true
83 }, 91 },
84 "@types/resolve": { 92 "@types/resolve": {
@@ -429,14 +437,6 @@
429 "dev": true, 437 "dev": true,
430 "requires": { 438 "requires": {
431 "@types/estree": "0.0.39" 439 "@types/estree": "0.0.39"
432 },
433 "dependencies": {
434 "@types/estree": {
435 "version": "0.0.39",
436 "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
437 "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
438 "dev": true
439 }
440 } 440 }
441 }, 441 },
442 "js-tokens": { 442 "js-tokens": {
@@ -486,9 +486,9 @@
486 } 486 }
487 }, 487 },
488 "magic-string": { 488 "magic-string": {
489 "version": "0.25.4", 489 "version": "0.25.6",
490 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz", 490 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.6.tgz",
491 "integrity": "sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==", 491 "integrity": "sha512-3a5LOMSGoCTH5rbqobC2HuDNRtE2glHZ8J7pK+QZYppyWA36yuNpsX994rIY2nCuyP7CZYy7lQq/X2jygiZ89g==",
492 "dev": true, 492 "dev": true,
493 "requires": { 493 "requires": {
494 "sourcemap-codec": "^1.4.4" 494 "sourcemap-codec": "^1.4.4"
@@ -675,9 +675,9 @@
675 } 675 }
676 }, 676 },
677 "rollup": { 677 "rollup": {
678 "version": "1.27.14", 678 "version": "1.30.1",
679 "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.27.14.tgz", 679 "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.30.1.tgz",
680 "integrity": "sha512-DuDjEyn8Y79ALYXMt+nH/EI58L5pEw5HU9K38xXdRnxQhvzUTI/nxAawhkAHUQeudANQ//8iyrhVRHJBuR6DSQ==", 680 "integrity": "sha512-Uus8mwQXwaO+ZVoNwBcXKhT0AvycFCBW/W8VZtkpVGsotRllWk9oldfCjqWmTnFRI0y7x6BnEqSqc65N+/YdBw==",
681 "dev": true, 681 "dev": true,
682 "requires": { 682 "requires": {
683 "@types/estree": "*", 683 "@types/estree": "*",
@@ -708,9 +708,9 @@
708 "dev": true 708 "dev": true
709 }, 709 },
710 "sourcemap-codec": { 710 "sourcemap-codec": {
711 "version": "1.4.6", 711 "version": "1.4.8",
712 "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", 712 "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
713 "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==", 713 "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
714 "dev": true 714 "dev": true
715 }, 715 },
716 "sprintf-js": { 716 "sprintf-js": {
@@ -782,7 +782,7 @@
782 "semver": { 782 "semver": {
783 "version": "5.7.1", 783 "version": "5.7.1",
784 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 784 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
785 "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", 785 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
786 "dev": true 786 "dev": true
787 } 787 }
788 } 788 }
@@ -813,9 +813,9 @@
813 } 813 }
814 }, 814 },
815 "typescript": { 815 "typescript": {
816 "version": "3.7.4", 816 "version": "3.7.5",
817 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz", 817 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz",
818 "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==", 818 "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==",
819 "dev": true 819 "dev": true
820 }, 820 },
821 "typescript-formatter": { 821 "typescript-formatter": {
diff --git a/editors/code/package.json b/editors/code/package.json
index ce3de1e96..55d470fa0 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -28,16 +28,16 @@
28 "vscode-languageclient": "^6.1.0" 28 "vscode-languageclient": "^6.1.0"
29 }, 29 },
30 "devDependencies": { 30 "devDependencies": {
31 "@rollup/plugin-commonjs": "^11.0.0", 31 "@rollup/plugin-commonjs": "^11.0.1",
32 "@rollup/plugin-node-resolve": "^6.0.0", 32 "@rollup/plugin-node-resolve": "^6.1.0",
33 "@rollup/plugin-typescript": "^2.0.1", 33 "@rollup/plugin-typescript": "^2.1.0",
34 "@types/node": "^12.12.21", 34 "@types/node": "^12.12.25",
35 "@types/seedrandom": "^2.4.28", 35 "@types/seedrandom": "^2.4.28",
36 "@types/vscode": "^1.41.0", 36 "@types/vscode": "^1.41.0",
37 "rollup": "^1.27.14", 37 "rollup": "^1.30.1",
38 "tslib": "^1.10.0", 38 "tslib": "^1.10.0",
39 "tslint": "^5.20.1", 39 "tslint": "^5.20.1",
40 "typescript": "^3.7.3", 40 "typescript": "^3.7.5",
41 "typescript-formatter": "^7.2.2", 41 "typescript-formatter": "^7.2.2",
42 "vsce": "^1.71.0" 42 "vsce": "^1.71.0"
43 }, 43 },
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 1ff64a930..15e1a0873 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -15,7 +15,13 @@ export function createClient(config: Config): lc.LanguageClient {
15 15
16 const command = expandPathResolving(config.raLspServerPath); 16 const command = expandPathResolving(config.raLspServerPath);
17 if (spawnSync(command, ["--version"]).status !== 0) { 17 if (spawnSync(command, ["--version"]).status !== 0) {
18 window.showErrorMessage(`Unable to execute '${command} --version'`); 18 window.showErrorMessage(
19 `Unable to execute '${command} --version'
20
21Perhaps it is not in $PATH?
22
23PATH=${process.env.PATH}
24`);
19 } 25 }
20 const run: lc.Executable = { 26 const run: lc.Executable = {
21 command, 27 command,