aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml57
-rw-r--r--Cargo.lock93
-rw-r--r--crates/ra_assists/src/flip_eq_operands.rs86
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_cli/Cargo.toml1
-rw-r--r--crates/ra_cli/src/main.rs2
-rw-r--r--crates/ra_hir/src/code_model_api.rs33
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs19
-rw-r--r--crates/ra_hir/src/diagnostics.rs115
-rw-r--r--crates/ra_hir/src/expr.rs19
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir/src/mock.rs18
-rw-r--r--crates/ra_hir/src/nameres.rs81
-rw-r--r--crates/ra_hir/src/nameres/collector.rs70
-rw-r--r--crates/ra_hir/src/nameres/tests.rs19
-rw-r--r--crates/ra_hir/src/ty/infer.rs55
-rw-r--r--crates/ra_hir/src/ty/tests.rs24
-rw-r--r--crates/ra_ide_api/Cargo.toml1
-rw-r--r--crates/ra_ide_api/src/assists.rs11
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs112
-rw-r--r--crates/ra_ide_api/src/lib.rs101
-rw-r--r--crates/ra_ide_api/src/references.rs14
-rw-r--r--crates/ra_ide_api/src/snapshots/tests__file_structure.snap (renamed from crates/ra_ide_api_light/src/snapshots/tests__file_structure.snap)2
-rw-r--r--crates/ra_ide_api/src/structure.rs (renamed from crates/ra_ide_api_light/src/structure.rs)0
-rw-r--r--crates/ra_ide_api/src/typing.rs26
-rw-r--r--crates/ra_ide_api/tests/test/main.rs16
-rw-r--r--crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap28
-rw-r--r--crates/ra_ide_api_light/Cargo.toml26
-rw-r--r--crates/ra_ide_api_light/src/lib.rs12
-rw-r--r--crates/ra_syntax/src/ast.rs87
-rw-r--r--crates/ra_syntax/src/ptr.rs6
-rw-r--r--docs/dev/README.md6
-rw-r--r--docs/dev/architecture.md13
33 files changed, 746 insertions, 412 deletions
diff --git a/.travis.yml b/.travis.yml
index 8d10a43f0..940435172 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,42 +4,49 @@ before_cache:
4 - rm -fr ./target/debug/{deps,.fingerprint}/{*ra_*,*test*,*tools*,*gen_lsp*,*thread_worker*} 4 - rm -fr ./target/debug/{deps,.fingerprint}/{*ra_*,*test*,*tools*,*gen_lsp*,*thread_worker*}
5 - rm -f ./target/.rustc_info.json 5 - rm -f ./target/.rustc_info.json
6 6
7build: &rust_build
8 language: rust
9 rust: stable
10 script:
11 - rustup component add rustfmt
12 - rustup component add rust-src
13 - cargo test --no-run # let's measure compile time separately
14 - cargo test
15 env:
16 - RUSTFLAGS="-D warnings", CARGO_INCREMENTAL=0
17
18matrix: 7matrix:
19 include: 8 include:
20 - os: linux 9 - os: linux
21 <<: *rust_build 10 language: rust
22 - language: node_js 11 rust: stable
23 node_js: node
24 before_script: false
25 script: 12 script:
26 - cd editors/code && npm ci && npm run travis 13 - rustup component add rustfmt
14 - rustup component add rust-src
15 - cargo test --no-run # let's measure compile time separately
16 - cargo test
17 env:
18 - RUSTFLAGS="-D warnings", CARGO_INCREMENTAL=0
27 19
28 - os: windows 20 - os: linux
29 if: branch = master AND type = push 21 if: branch = master AND type = push
30 before_script: 22 before_script:
31 - dos2unix ./crates/ra_syntax/tests/data/parser/**/*.txt 23 - DEPLOY_DOCS=1
32 - dos2unix ./crates/ra_syntax/tests/data/parser/**/*.rs 24 language: rust
33 <<: *rust_build 25 rust: stable
26 script:
27 - cargo doc --all --no-deps
28 env:
29 - RUSTFLAGS="-D warnings", CARGO_INCREMENTAL=0
34 30
35 allow_failures: 31 - language: node_js
36 # Because Travis-Windows-Rust can be flaky 32 node_js: node
37 # We still support Windows and want the tests to be succeeding, 33 before_script: false
38 # but there are too many spurious failures 34 script:
39 - os: windows 35 - cd editors/code && npm ci && npm run travis
40 36
41branches: 37branches:
42 only: 38 only:
43 - staging 39 - staging
44 - master 40 - master
45 - trying 41 - trying
42
43deploy:
44 provider: pages
45 skip-cleanup: true
46 github-token: $DOCS_TOKEN # Set in the settings page of your repository, as a secure variable
47 keep-history: true
48 local-dir: target/doc
49 branch: gh-pages
50 on:
51 branch: master
52 condition: $DEPLOY_DOCS = 1
diff --git a/Cargo.lock b/Cargo.lock
index 1b5de271e..3bc5f261c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -76,15 +76,15 @@ dependencies = [
76 76
77[[package]] 77[[package]]
78name = "bit-set" 78name = "bit-set"
79version = "0.5.0" 79version = "0.5.1"
80source = "registry+https://github.com/rust-lang/crates.io-index" 80source = "registry+https://github.com/rust-lang/crates.io-index"
81dependencies = [ 81dependencies = [
82 "bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 82 "bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
83] 83]
84 84
85[[package]] 85[[package]]
86name = "bit-vec" 86name = "bit-vec"
87version = "0.5.0" 87version = "0.5.1"
88source = "registry+https://github.com/rust-lang/crates.io-index" 88source = "registry+https://github.com/rust-lang/crates.io-index"
89 89
90[[package]] 90[[package]]
@@ -118,7 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
118 118
119[[package]] 119[[package]]
120name = "cargo_metadata" 120name = "cargo_metadata"
121version = "0.7.3" 121version = "0.7.4"
122source = "registry+https://github.com/rust-lang/crates.io-index" 122source = "registry+https://github.com/rust-lang/crates.io-index"
123dependencies = [ 123dependencies = [
124 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 124 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -359,11 +359,11 @@ dependencies = [
359 359
360[[package]] 360[[package]]
361name = "flexi_logger" 361name = "flexi_logger"
362version = "0.11.1" 362version = "0.11.2"
363source = "registry+https://github.com/rust-lang/crates.io-index" 363source = "registry+https://github.com/rust-lang/crates.io-index"
364dependencies = [ 364dependencies = [
365 "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 365 "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
366 "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 366 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
367 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 367 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
368 "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 368 "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
369] 369]
@@ -444,6 +444,11 @@ version = "0.2.11"
444source = "registry+https://github.com/rust-lang/crates.io-index" 444source = "registry+https://github.com/rust-lang/crates.io-index"
445 445
446[[package]] 446[[package]]
447name = "glob"
448version = "0.3.0"
449source = "registry+https://github.com/rust-lang/crates.io-index"
450
451[[package]]
447name = "heck" 452name = "heck"
448version = "0.3.1" 453version = "0.3.1"
449source = "registry+https://github.com/rust-lang/crates.io-index" 454source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -503,7 +508,7 @@ dependencies = [
503 508
504[[package]] 509[[package]]
505name = "insta" 510name = "insta"
506version = "0.7.1" 511version = "0.7.4"
507source = "registry+https://github.com/rust-lang/crates.io-index" 512source = "registry+https://github.com/rust-lang/crates.io-index"
508dependencies = [ 513dependencies = [
509 "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 514 "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -518,7 +523,7 @@ dependencies = [
518 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 523 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
519 "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 524 "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
520 "serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", 525 "serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)",
521 "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 526 "uuid 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
522] 527]
523 528
524[[package]] 529[[package]]
@@ -589,9 +594,6 @@ dependencies = [
589name = "lazy_static" 594name = "lazy_static"
590version = "1.3.0" 595version = "1.3.0"
591source = "registry+https://github.com/rust-lang/crates.io-index" 596source = "registry+https://github.com/rust-lang/crates.io-index"
592dependencies = [
593 "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
594]
595 597
596[[package]] 598[[package]]
597name = "lazycell" 599name = "lazycell"
@@ -605,7 +607,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
605 607
606[[package]] 608[[package]]
607name = "linked-hash-map" 609name = "linked-hash-map"
608version = "0.5.1" 610version = "0.5.2"
609source = "registry+https://github.com/rust-lang/crates.io-index" 611source = "registry+https://github.com/rust-lang/crates.io-index"
610 612
611[[package]] 613[[package]]
@@ -855,10 +857,10 @@ dependencies = [
855 857
856[[package]] 858[[package]]
857name = "proptest" 859name = "proptest"
858version = "0.9.1" 860version = "0.9.2"
859source = "registry+https://github.com/rust-lang/crates.io-index" 861source = "registry+https://github.com/rust-lang/crates.io-index"
860dependencies = [ 862dependencies = [
861 "bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 863 "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
862 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 864 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
863 "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 865 "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
864 "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 866 "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -922,14 +924,13 @@ version = "0.1.0"
922dependencies = [ 924dependencies = [
923 "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", 925 "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
924 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 926 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
925 "flexi_logger 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", 927 "flexi_logger 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
926 "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 928 "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
927 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 929 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
928 "ra_batch 0.1.0", 930 "ra_batch 0.1.0",
929 "ra_db 0.1.0", 931 "ra_db 0.1.0",
930 "ra_hir 0.1.0", 932 "ra_hir 0.1.0",
931 "ra_ide_api 0.1.0", 933 "ra_ide_api 0.1.0",
932 "ra_ide_api_light 0.1.0",
933 "ra_syntax 0.1.0", 934 "ra_syntax 0.1.0",
934 "tools 0.1.0", 935 "tools 0.1.0",
935] 936]
@@ -961,8 +962,8 @@ version = "0.1.0"
961dependencies = [ 962dependencies = [
962 "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 963 "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
963 "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 964 "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
964 "flexi_logger 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", 965 "flexi_logger 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
965 "insta 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 966 "insta 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
966 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 967 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
967 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 968 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
968 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 969 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -981,19 +982,18 @@ name = "ra_ide_api"
981version = "0.1.0" 982version = "0.1.0"
982dependencies = [ 983dependencies = [
983 "fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 984 "fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
984 "insta 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 985 "insta 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
985 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 986 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
986 "jemalloc-ctl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 987 "jemalloc-ctl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
987 "jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 988 "jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
988 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 989 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
989 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 990 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
990 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 991 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
991 "proptest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 992 "proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
992 "ra_assists 0.1.0", 993 "ra_assists 0.1.0",
993 "ra_db 0.1.0", 994 "ra_db 0.1.0",
994 "ra_fmt 0.1.0", 995 "ra_fmt 0.1.0",
995 "ra_hir 0.1.0", 996 "ra_hir 0.1.0",
996 "ra_ide_api_light 0.1.0",
997 "ra_syntax 0.1.0", 997 "ra_syntax 0.1.0",
998 "ra_text_edit 0.1.0", 998 "ra_text_edit 0.1.0",
999 "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 999 "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1005,29 +1005,13 @@ dependencies = [
1005] 1005]
1006 1006
1007[[package]] 1007[[package]]
1008name = "ra_ide_api_light"
1009version = "0.1.0"
1010dependencies = [
1011 "insta 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1012 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1013 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
1014 "proptest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
1015 "ra_fmt 0.1.0",
1016 "ra_syntax 0.1.0",
1017 "ra_text_edit 0.1.0",
1018 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1019 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1020 "test_utils 0.1.0",
1021]
1022
1023[[package]]
1024name = "ra_lsp_server" 1008name = "ra_lsp_server"
1025version = "0.1.0" 1009version = "0.1.0"
1026dependencies = [ 1010dependencies = [
1027 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1011 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1028 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1012 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1029 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1030 "flexi_logger 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", 1014 "flexi_logger 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
1031 "gen_lsp_server 0.1.0", 1015 "gen_lsp_server 0.1.0",
1032 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1016 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1033 "lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)", 1017 "lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1070,7 +1054,7 @@ dependencies = [
1070name = "ra_project_model" 1054name = "ra_project_model"
1071version = "0.1.0" 1055version = "0.1.0"
1072dependencies = [ 1056dependencies = [
1073 "cargo_metadata 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 1057 "cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
1074 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1058 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1075 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1059 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1076 "ra_arena 0.1.0", 1060 "ra_arena 0.1.0",
@@ -1105,7 +1089,7 @@ dependencies = [
1105name = "ra_text_edit" 1089name = "ra_text_edit"
1106version = "0.1.0" 1090version = "0.1.0"
1107dependencies = [ 1091dependencies = [
1108 "proptest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 1092 "proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
1109 "test_utils 0.1.0", 1093 "test_utils 0.1.0",
1110 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1094 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1111] 1095]
@@ -1436,7 +1420,7 @@ version = "0.8.8"
1436source = "registry+https://github.com/rust-lang/crates.io-index" 1420source = "registry+https://github.com/rust-lang/crates.io-index"
1437dependencies = [ 1421dependencies = [
1438 "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 1422 "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
1439 "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1423 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1440 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 1424 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
1441 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 1425 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
1442] 1426]
@@ -1479,11 +1463,6 @@ dependencies = [
1479] 1463]
1480 1464
1481[[package]] 1465[[package]]
1482name = "spin"
1483version = "0.5.0"
1484source = "registry+https://github.com/rust-lang/crates.io-index"
1485
1486[[package]]
1487name = "stable_deref_trait" 1466name = "stable_deref_trait"
1488version = "1.1.1" 1467version = "1.1.1"
1489source = "registry+https://github.com/rust-lang/crates.io-index" 1468source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1776,7 +1755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1776 1755
1777[[package]] 1756[[package]]
1778name = "uuid" 1757name = "uuid"
1779version = "0.7.2" 1758version = "0.7.3"
1780source = "registry+https://github.com/rust-lang/crates.io-index" 1759source = "registry+https://github.com/rust-lang/crates.io-index"
1781dependencies = [ 1760dependencies = [
1782 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1761 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1854,7 +1833,7 @@ name = "yaml-rust"
1854version = "0.4.3" 1833version = "0.4.3"
1855source = "registry+https://github.com/rust-lang/crates.io-index" 1834source = "registry+https://github.com/rust-lang/crates.io-index"
1856dependencies = [ 1835dependencies = [
1857 "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1836 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1858] 1837]
1859 1838
1860[metadata] 1839[metadata]
@@ -1867,14 +1846,14 @@ dependencies = [
1867"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" 1846"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
1868"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" 1847"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
1869"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 1848"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
1870"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a" 1849"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
1871"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf" 1850"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
1872"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" 1851"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
1873"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 1852"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
1874"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" 1853"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
1875"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" 1854"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
1876"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" 1855"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
1877"checksum cargo_metadata 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bc796c7161c220089dfc7159e13324979181532850a237576b8fb907dd087c0d" 1856"checksum cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "178d62b240c34223f265a4c1e275e37d62da163d421fc8d7f7e3ee340f803c57"
1878"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" 1857"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
1879"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" 1858"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
1880"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" 1859"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
@@ -1903,7 +1882,7 @@ dependencies = [
1903"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" 1882"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
1904"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 1883"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
1905"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" 1884"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646"
1906"checksum flexi_logger 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7878fc9e06c948c6f9cddf571758e0c44786a509e646a094ef13ade3b1aab7" 1885"checksum flexi_logger 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "005c01dd6942ca46283b7304d14c6d04ec2c87a62f6e62e17c06fb812a574f4a"
1907"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" 1886"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
1908"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05" 1887"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
1909"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874" 1888"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
@@ -1913,6 +1892,7 @@ dependencies = [
1913"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1892"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
1914"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" 1893"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
1915"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" 1894"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
1895"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
1916"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 1896"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
1917"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" 1897"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e"
1918"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 1898"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
@@ -1920,7 +1900,7 @@ dependencies = [
1920"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" 1900"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c"
1921"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" 1901"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
1922"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" 1902"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
1923"checksum insta 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be9f00370d23dc7bd32a4d4506b1a14fb922fa39c576c3300fd25ce5b5dab18f" 1903"checksum insta 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "03e7d88a87d342ce8bd698516151be43e6eb2e84b683db528696cb4a382f734a"
1924"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" 1904"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
1925"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" 1905"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
1926"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 1906"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
@@ -1932,7 +1912,7 @@ dependencies = [
1932"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" 1912"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
1933"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" 1913"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
1934"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" 1914"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1"
1935"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" 1915"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
1936"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" 1916"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
1937"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" 1917"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
1938"checksum lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31954f2cf354421e6f99a48fdcfd5c3113c675a0db311960ffdac0b8d45cf09c" 1918"checksum lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31954f2cf354421e6f99a48fdcfd5c3113c675a0db311960ffdac0b8d45cf09c"
@@ -1960,7 +1940,7 @@ dependencies = [
1960"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646" 1940"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646"
1961"checksum pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e" 1941"checksum pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e"
1962"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" 1942"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
1963"checksum proptest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea66c78d75f2c6e9f304269eaef90899798daecc69f1a625d5a3dd793ff3522" 1943"checksum proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24f5844db2f839e97e3021980975f6ebf8691d9b9b2ca67ed3feb38dc3edb52c"
1964"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1944"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
1965"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 1945"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
1966"checksum ra_vfs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1839e4e003d865b58b8b6c231aae6c463dfcd01bfbbddffbdb7662a7b5a627" 1946"checksum ra_vfs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1839e4e003d865b58b8b6c231aae6c463dfcd01bfbbddffbdb7662a7b5a627"
@@ -2004,7 +1984,6 @@ dependencies = [
2004"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" 1984"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
2005"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" 1985"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
2006"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e" 1986"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e"
2007"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
2008"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 1987"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
2009"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 1988"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
2010"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1989"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
@@ -2038,7 +2017,7 @@ dependencies = [
2038"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" 2017"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
2039"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" 2018"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"
2040"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" 2019"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
2041"checksum uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0238db0c5b605dd1cf51de0f21766f97fba2645897024461d6a00c036819a768" 2020"checksum uuid 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "600ef8213e9f8a0ac1f876e470e90780ae0478eabce7f76aff41b0f4ef0fd5c0"
2042"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 2021"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
2043"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" 2022"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
2044"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" 2023"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
diff --git a/crates/ra_assists/src/flip_eq_operands.rs b/crates/ra_assists/src/flip_eq_operands.rs
new file mode 100644
index 000000000..df0bb689d
--- /dev/null
+++ b/crates/ra_assists/src/flip_eq_operands.rs
@@ -0,0 +1,86 @@
1use hir::db::HirDatabase;
2use ra_syntax::ast::{AstNode, BinExpr, BinOp};
3
4use crate::{AssistCtx, Assist, AssistId};
5
6pub(crate) fn flip_eq_operands(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
7 let expr = ctx.node_at_offset::<BinExpr>()?;
8 let lhs = expr.lhs()?.syntax();
9 let rhs = expr.rhs()?.syntax();
10 let op_range = expr.op()?.range();
11 let cursor_in_range = ctx.frange.range.is_subrange(&op_range);
12 let allowed_ops = [BinOp::EqualityTest, BinOp::NegatedEqualityTest];
13 let expr_op = expr.op_kind()?;
14 if !cursor_in_range || !allowed_ops.iter().any(|o| *o == expr_op) {
15 return None;
16 }
17 ctx.add_action(AssistId("flip_eq_operands"), "flip equality operands", |edit| {
18 edit.target(op_range);
19 edit.replace(lhs.range(), rhs.text());
20 edit.replace(rhs.range(), lhs.text());
21 });
22
23 ctx.build()
24}
25
26#[cfg(test)]
27mod tests {
28 use super::*;
29
30 use crate::helpers::{check_assist, check_assist_target};
31
32 #[test]
33 fn flip_eq_operands_for_simple_stmt() {
34 check_assist(
35 flip_eq_operands,
36 "fn f() { let res = 1 ==<|> 2; }",
37 "fn f() { let res = 2 ==<|> 1; }",
38 )
39 }
40
41 #[test]
42 fn flip_neq_operands_for_simple_stmt() {
43 check_assist(
44 flip_eq_operands,
45 "fn f() { let res = 1 !=<|> 2; }",
46 "fn f() { let res = 2 !=<|> 1; }",
47 )
48 }
49
50 #[test]
51 fn flip_eq_operands_for_complex_stmt() {
52 check_assist(
53 flip_eq_operands,
54 "fn f() { let res = (1 + 1) ==<|> (2 + 2); }",
55 "fn f() { let res = (2 + 2) ==<|> (1 + 1); }",
56 )
57 }
58
59 #[test]
60 fn flip_eq_operands_in_match_expr() {
61 check_assist(
62 flip_eq_operands,
63 r#"
64 fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
65 match other.downcast_ref::<Self>() {
66 None => false,
67 Some(it) => it ==<|> self,
68 }
69 }
70 "#,
71 r#"
72 fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
73 match other.downcast_ref::<Self>() {
74 None => false,
75 Some(it) => self ==<|> it,
76 }
77 }
78 "#,
79 )
80 }
81
82 #[test]
83 fn flip_eq_operands_target() {
84 check_assist_target(flip_eq_operands, "fn f() { let res = 1 ==<|> 2; }", "==")
85 }
86}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 378470ac8..2e47b5215 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -88,6 +88,7 @@ where
88mod add_derive; 88mod add_derive;
89mod add_impl; 89mod add_impl;
90mod flip_comma; 90mod flip_comma;
91mod flip_eq_operands;
91mod change_visibility; 92mod change_visibility;
92mod fill_match_arms; 93mod fill_match_arms;
93mod fill_struct_fields; 94mod fill_struct_fields;
@@ -107,6 +108,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
107 fill_match_arms::fill_match_arms, 108 fill_match_arms::fill_match_arms,
108 fill_struct_fields::fill_struct_fields, 109 fill_struct_fields::fill_struct_fields,
109 flip_comma::flip_comma, 110 flip_comma::flip_comma,
111 flip_eq_operands::flip_eq_operands,
110 introduce_variable::introduce_variable, 112 introduce_variable::introduce_variable,
111 replace_if_let_with_match::replace_if_let_with_match, 113 replace_if_let_with_match::replace_if_let_with_match,
112 split_import::split_import, 114 split_import::split_import,
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index 4c666f556..467628236 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -14,7 +14,6 @@ indicatif = "0.11.0"
14 14
15ra_syntax = { path = "../ra_syntax" } 15ra_syntax = { path = "../ra_syntax" }
16ra_ide_api = { path = "../ra_ide_api" } 16ra_ide_api = { path = "../ra_ide_api" }
17ra_ide_api_light = { path = "../ra_ide_api_light" }
18tools = { path = "../tools" } 17tools = { path = "../tools" }
19ra_batch = { path = "../ra_batch" } 18ra_batch = { path = "../ra_batch" }
20ra_hir = { path = "../ra_hir" } 19ra_hir = { path = "../ra_hir" }
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 5285f1f28..11f5541eb 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -5,7 +5,7 @@ use std::{fs, io::Read, path::Path, time::Instant};
5use clap::{App, Arg, SubCommand}; 5use clap::{App, Arg, SubCommand};
6use join_to_string::join; 6use join_to_string::join;
7use ra_ide_api::{Analysis, FileRange}; 7use ra_ide_api::{Analysis, FileRange};
8use ra_ide_api_light::file_structure; 8use ra_ide_api::file_structure;
9use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; 9use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode};
10use tools::collect_tests; 10use tools::collect_tests;
11use flexi_logger::Logger; 11use flexi_logger::Logger;
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 45fa4cd11..5437133b8 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -1,8 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use relative_path::RelativePathBuf;
4use ra_db::{CrateId, SourceRootId, Edition}; 3use ra_db::{CrateId, SourceRootId, Edition};
5use ra_syntax::{ast::self, TreeArc, SyntaxNode}; 4use ra_syntax::{ast::self, TreeArc};
6 5
7use crate::{ 6use crate::{
8 Name, ScopesWithSourceMap, Ty, HirFileId, 7 Name, ScopesWithSourceMap, Ty, HirFileId,
@@ -17,6 +16,7 @@ use crate::{
17 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, 16 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId},
18 impl_block::ImplBlock, 17 impl_block::ImplBlock,
19 resolve::Resolver, 18 resolve::Resolver,
19 diagnostics::DiagnosticSink,
20}; 20};
21 21
22/// hir::Crate describes a single crate. It's the main interface with which 22/// hir::Crate describes a single crate. It's the main interface with which
@@ -95,11 +95,6 @@ pub enum ModuleSource {
95 Module(TreeArc<ast::Module>), 95 Module(TreeArc<ast::Module>),
96} 96}
97 97
98#[derive(Clone, Debug, Hash, PartialEq, Eq)]
99pub enum Problem {
100 UnresolvedModule { candidate: RelativePathBuf },
101}
102
103impl Module { 98impl Module {
104 /// Name of this module. 99 /// Name of this module.
105 pub fn name(&self, db: &impl HirDatabase) -> Option<Name> { 100 pub fn name(&self, db: &impl HirDatabase) -> Option<Name> {
@@ -171,8 +166,24 @@ impl Module {
171 db.crate_def_map(self.krate)[self.module_id].scope.clone() 166 db.crate_def_map(self.krate)[self.module_id].scope.clone()
172 } 167 }
173 168
174 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { 169 pub fn diagnostics(&self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
175 self.problems_impl(db) 170 db.crate_def_map(self.krate).add_diagnostics(db, self.module_id, sink);
171 for decl in self.declarations(db) {
172 match decl {
173 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
174 crate::ModuleDef::Module(f) => f.diagnostics(db, sink),
175 _ => (),
176 }
177 }
178
179 for impl_block in self.impl_blocks(db) {
180 for item in impl_block.items(db) {
181 match item {
182 crate::ImplItem::Method(f) => f.diagnostics(db, sink),
183 _ => (),
184 }
185 }
186 }
176 } 187 }
177 188
178 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 189 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
@@ -519,6 +530,10 @@ impl Function {
519 let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; 530 let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
520 r 531 r
521 } 532 }
533
534 pub fn diagnostics(&self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
535 self.infer(db).add_diagnostics(db, *self, sink);
536 }
522} 537}
523 538
524impl Docs for Function { 539impl Docs for Function {
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 52a33e981..14237060c 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -1,8 +1,8 @@
1use ra_db::FileId; 1use ra_db::FileId;
2use ra_syntax::{ast, SyntaxNode, TreeArc, AstNode}; 2use ra_syntax::{ast, TreeArc, AstNode};
3 3
4use crate::{ 4use crate::{
5 Module, ModuleSource, Problem, Name, 5 Module, ModuleSource, Name,
6 nameres::{CrateModuleId, ImportId}, 6 nameres::{CrateModuleId, ImportId},
7 HirDatabase, DefDatabase, 7 HirDatabase, DefDatabase,
8 HirFileId, SourceItemId, 8 HirFileId, SourceItemId,
@@ -108,19 +108,4 @@ impl Module {
108 let parent_id = def_map[self.module_id].parent?; 108 let parent_id = def_map[self.module_id].parent?;
109 Some(self.with_module_id(parent_id)) 109 Some(self.with_module_id(parent_id))
110 } 110 }
111
112 pub(crate) fn problems_impl(
113 &self,
114 db: &impl HirDatabase,
115 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
116 let def_map = db.crate_def_map(self.krate);
117 let (my_file_id, _) = self.definition_source(db);
118 // FIXME: not entirely corret filterint by module
119 def_map
120 .problems()
121 .iter()
122 .filter(|(source_item_id, _problem)| my_file_id == source_item_id.file_id)
123 .map(|(source_item_id, problem)| (db.file_item(*source_item_id), problem.clone()))
124 .collect()
125 }
126} 111}
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
new file mode 100644
index 000000000..d6a51b833
--- /dev/null
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -0,0 +1,115 @@
1use std::{fmt, any::Any};
2
3use ra_syntax::{SyntaxNodePtr, TreeArc, AstPtr, TextRange, ast, SyntaxNode};
4use relative_path::RelativePathBuf;
5
6use crate::{HirFileId, HirDatabase};
7
8/// Diagnostic defines hir API for errors and warnings.
9///
10/// It is used as a `dyn` object, which you can downcast to a concrete
11/// diagnostic. DiagnosticSink are structured, meaning that they include rich
12/// information which can be used by IDE to create fixes. DiagnosticSink are
13/// expressed in terms of macro-expanded syntax tree nodes (so, it's a bad idea
14/// to diagnostic in a salsa value).
15///
16/// Internally, various subsystems of hir produce diagnostics specific to a
17/// subsystem (typically, an `enum`), which are safe to store in salsa but do not
18/// include source locations. Such internal diagnostic are transformed into an
19/// instance of `Diagnostic` on demand.
20pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
21 fn message(&self) -> String;
22 fn file(&self) -> HirFileId;
23 fn syntax_node_ptr(&self) -> SyntaxNodePtr;
24 fn highlight_range(&self) -> TextRange {
25 self.syntax_node_ptr().range()
26 }
27 fn as_any(&self) -> &(dyn Any + Send + 'static);
28}
29
30impl dyn Diagnostic {
31 pub fn syntax_node(&self, db: &impl HirDatabase) -> TreeArc<SyntaxNode> {
32 let source_file = db.hir_parse(self.file());
33 self.syntax_node_ptr().to_node(&source_file).to_owned()
34 }
35 pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> {
36 self.as_any().downcast_ref()
37 }
38}
39
40pub struct DiagnosticSink<'a> {
41 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
42 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
43}
44
45impl<'a> DiagnosticSink<'a> {
46 pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> {
47 DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) }
48 }
49
50 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> {
51 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
52 Some(d) => {
53 cb(d);
54 Ok(())
55 }
56 None => Err(()),
57 };
58 self.callbacks.push(Box::new(cb));
59 self
60 }
61
62 pub(crate) fn push(&mut self, d: impl Diagnostic) {
63 let d: &dyn Diagnostic = &d;
64 for cb in self.callbacks.iter_mut() {
65 match cb(d) {
66 Ok(()) => return,
67 Err(()) => (),
68 }
69 }
70 (self.default_callback)(d)
71 }
72}
73
74#[derive(Debug)]
75pub struct NoSuchField {
76 pub file: HirFileId,
77 pub field: AstPtr<ast::NamedField>,
78}
79
80impl Diagnostic for NoSuchField {
81 fn message(&self) -> String {
82 "no such field".to_string()
83 }
84 fn file(&self) -> HirFileId {
85 self.file
86 }
87 fn syntax_node_ptr(&self) -> SyntaxNodePtr {
88 self.field.into()
89 }
90 fn as_any(&self) -> &(Any + Send + 'static) {
91 self
92 }
93}
94
95#[derive(Debug)]
96pub struct UnresolvedModule {
97 pub file: HirFileId,
98 pub decl: AstPtr<ast::Module>,
99 pub candidate: RelativePathBuf,
100}
101
102impl Diagnostic for UnresolvedModule {
103 fn message(&self) -> String {
104 "unresolved module".to_string()
105 }
106 fn file(&self) -> HirFileId {
107 self.file
108 }
109 fn syntax_node_ptr(&self) -> SyntaxNodePtr {
110 self.decl.into()
111 }
112 fn as_any(&self) -> &(Any + Send + 'static) {
113 self
114 }
115}
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 703d99d9b..a85422955 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -5,7 +5,7 @@ use rustc_hash::FxHashMap;
5 5
6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
7use ra_syntax::{ 7use ra_syntax::{
8 SyntaxNodePtr, AstNode, 8 SyntaxNodePtr, AstPtr, AstNode,
9 ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor, TypeAscriptionOwner} 9 ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor, TypeAscriptionOwner}
10}; 10};
11 11
@@ -54,6 +54,7 @@ pub struct BodySourceMap {
54 expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, 54 expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>,
55 pat_map: FxHashMap<SyntaxNodePtr, PatId>, 55 pat_map: FxHashMap<SyntaxNodePtr, PatId>,
56 pat_map_back: ArenaMap<PatId, SyntaxNodePtr>, 56 pat_map_back: ArenaMap<PatId, SyntaxNodePtr>,
57 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::NamedField>>,
57} 58}
58 59
59impl Body { 60impl Body {
@@ -138,6 +139,10 @@ impl BodySourceMap {
138 pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { 139 pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> {
139 self.pat_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() 140 self.pat_map.get(&SyntaxNodePtr::new(node.syntax())).cloned()
140 } 141 }
142
143 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> {
144 self.field_map[&(expr, field)].clone()
145 }
141} 146}
142 147
143#[derive(Debug, Clone, Eq, PartialEq)] 148#[derive(Debug, Clone, Eq, PartialEq)]
@@ -629,8 +634,10 @@ impl ExprCollector {
629 } 634 }
630 ast::ExprKind::StructLit(e) => { 635 ast::ExprKind::StructLit(e) => {
631 let path = e.path().and_then(Path::from_ast); 636 let path = e.path().and_then(Path::from_ast);
637 let mut field_ptrs = Vec::new();
632 let fields = if let Some(nfl) = e.named_field_list() { 638 let fields = if let Some(nfl) = e.named_field_list() {
633 nfl.fields() 639 nfl.fields()
640 .inspect(|field| field_ptrs.push(AstPtr::new(*field)))
634 .map(|field| StructLitField { 641 .map(|field| StructLitField {
635 name: field 642 name: field
636 .name_ref() 643 .name_ref()
@@ -657,7 +664,11 @@ impl ExprCollector {
657 Vec::new() 664 Vec::new()
658 }; 665 };
659 let spread = e.spread().map(|s| self.collect_expr(s)); 666 let spread = e.spread().map(|s| self.collect_expr(s));
660 self.alloc_expr(Expr::StructLit { path, fields, spread }, syntax_ptr) 667 let res = self.alloc_expr(Expr::StructLit { path, fields, spread }, syntax_ptr);
668 for (i, ptr) in field_ptrs.into_iter().enumerate() {
669 self.source_map.field_map.insert((res, i), ptr);
670 }
671 res
661 } 672 }
662 ast::ExprKind::FieldExpr(e) => { 673 ast::ExprKind::FieldExpr(e) => {
663 let expr = self.collect_expr_opt(e.expr()); 674 let expr = self.collect_expr_opt(e.expr());
@@ -680,7 +691,7 @@ impl ExprCollector {
680 } 691 }
681 ast::ExprKind::PrefixExpr(e) => { 692 ast::ExprKind::PrefixExpr(e) => {
682 let expr = self.collect_expr_opt(e.expr()); 693 let expr = self.collect_expr_opt(e.expr());
683 if let Some(op) = e.op() { 694 if let Some(op) = e.op_kind() {
684 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) 695 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
685 } else { 696 } else {
686 self.alloc_expr(Expr::Missing, syntax_ptr) 697 self.alloc_expr(Expr::Missing, syntax_ptr)
@@ -703,7 +714,7 @@ impl ExprCollector {
703 ast::ExprKind::BinExpr(e) => { 714 ast::ExprKind::BinExpr(e) => {
704 let lhs = self.collect_expr_opt(e.lhs()); 715 let lhs = self.collect_expr_opt(e.lhs());
705 let rhs = self.collect_expr_opt(e.rhs()); 716 let rhs = self.collect_expr_opt(e.rhs());
706 let op = e.op(); 717 let op = e.op_kind();
707 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) 718 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
708 } 719 }
709 ast::ExprKind::TupleExpr(e) => { 720 ast::ExprKind::TupleExpr(e) => {
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index a89c916f8..ce54d7608 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -35,6 +35,7 @@ mod expr;
35mod generics; 35mod generics;
36mod docs; 36mod docs;
37mod resolve; 37mod resolve;
38pub mod diagnostics;
38 39
39mod code_model_api; 40mod code_model_api;
40mod code_model_impl; 41mod code_model_impl;
@@ -63,7 +64,7 @@ pub use self::{
63 64
64pub use self::code_model_api::{ 65pub use self::code_model_api::{
65 Crate, CrateDependency, 66 Crate, CrateDependency,
66 Module, ModuleDef, ModuleSource, Problem, 67 Module, ModuleDef, ModuleSource,
67 Struct, Enum, EnumVariant, 68 Struct, Enum, EnumVariant,
68 Function, FnSignature, 69 Function, FnSignature,
69 StructField, FieldSource, 70 StructField, FieldSource,
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 10d4c1b8c..aeab6b180 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -9,7 +9,7 @@ use relative_path::RelativePathBuf;
9use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 9use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11 11
12use crate::{db, HirInterner}; 12use crate::{db, HirInterner, diagnostics::DiagnosticSink};
13 13
14pub const WORKSPACE: SourceRootId = SourceRootId(0); 14pub const WORKSPACE: SourceRootId = SourceRootId(0);
15 15
@@ -70,6 +70,22 @@ impl MockDatabase {
70 self.set_crate_graph(Arc::new(crate_graph)) 70 self.set_crate_graph(Arc::new(crate_graph))
71 } 71 }
72 72
73 pub fn diagnostics(&self) -> String {
74 let mut buf = String::from("\n");
75 let mut files: Vec<FileId> = self.files.values().map(|&it| it).collect();
76 files.sort();
77 for file in files {
78 let module = crate::source_binder::module_from_file_id(self, file).unwrap();
79 module.diagnostics(
80 self,
81 &mut DiagnosticSink::new(|d| {
82 buf += &format!("{:?}: {}\n", d.syntax_node(self).text(), d.message());
83 }),
84 )
85 }
86 buf
87 }
88
73 fn from_fixture(fixture: &str) -> (MockDatabase, Option<FilePosition>) { 89 fn from_fixture(fixture: &str) -> (MockDatabase, Option<FilePosition>) {
74 let mut db = MockDatabase::default(); 90 let mut db = MockDatabase::default();
75 91
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index d361cf9e6..56ed872d5 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -61,9 +61,11 @@ use ra_db::{FileId, Edition};
61use test_utils::tested_by; 61use test_utils::tested_by;
62 62
63use crate::{ 63use crate::{
64 ModuleDef, Name, Crate, Module, Problem, 64 ModuleDef, Name, Crate, Module,
65 DefDatabase, Path, PathKind, HirFileId, 65 DefDatabase, Path, PathKind, HirFileId,
66 ids::{SourceItemId, SourceFileItemId, MacroCallId}, 66 ids::{SourceItemId, SourceFileItemId, MacroCallId},
67 diagnostics::DiagnosticSink,
68 nameres::diagnostics::DefDiagnostic,
67}; 69};
68 70
69pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; 71pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap};
@@ -85,7 +87,7 @@ pub struct CrateDefMap {
85 macros: Arena<CrateMacroId, mbe::MacroRules>, 87 macros: Arena<CrateMacroId, mbe::MacroRules>,
86 public_macros: FxHashMap<Name, CrateMacroId>, 88 public_macros: FxHashMap<Name, CrateMacroId>,
87 macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>, 89 macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>,
88 problems: CrateDefMapProblems, 90 diagnostics: Vec<DefDiagnostic>,
89} 91}
90 92
91impl std::ops::Index<CrateModuleId> for CrateDefMap { 93impl std::ops::Index<CrateModuleId> for CrateDefMap {
@@ -125,21 +127,6 @@ pub(crate) struct ModuleData {
125 pub(crate) definition: Option<FileId>, 127 pub(crate) definition: Option<FileId>,
126} 128}
127 129
128#[derive(Default, Debug, PartialEq, Eq)]
129pub(crate) struct CrateDefMapProblems {
130 problems: Vec<(SourceItemId, Problem)>,
131}
132
133impl CrateDefMapProblems {
134 fn add(&mut self, source_item_id: SourceItemId, problem: Problem) {
135 self.problems.push((source_item_id, problem))
136 }
137
138 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a {
139 self.problems.iter().map(|(s, p)| (s, p))
140 }
141}
142
143#[derive(Debug, Default, PartialEq, Eq, Clone)] 130#[derive(Debug, Default, PartialEq, Eq, Clone)]
144pub struct ModuleScope { 131pub struct ModuleScope {
145 items: FxHashMap<Name, Resolution>, 132 items: FxHashMap<Name, Resolution>,
@@ -212,7 +199,7 @@ impl CrateDefMap {
212 macros: Arena::default(), 199 macros: Arena::default(),
213 public_macros: FxHashMap::default(), 200 public_macros: FxHashMap::default(),
214 macro_resolutions: FxHashMap::default(), 201 macro_resolutions: FxHashMap::default(),
215 problems: CrateDefMapProblems::default(), 202 diagnostics: Vec::new(),
216 } 203 }
217 }; 204 };
218 let def_map = collector::collect_defs(db, def_map); 205 let def_map = collector::collect_defs(db, def_map);
@@ -224,10 +211,6 @@ impl CrateDefMap {
224 self.root 211 self.root
225 } 212 }
226 213
227 pub(crate) fn problems(&self) -> &CrateDefMapProblems {
228 &self.problems
229 }
230
231 pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module { 214 pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module {
232 Module { krate: self.krate, module_id } 215 Module { krate: self.krate, module_id }
233 } 216 }
@@ -240,6 +223,15 @@ impl CrateDefMap {
240 &self.extern_prelude 223 &self.extern_prelude
241 } 224 }
242 225
226 pub(crate) fn add_diagnostics(
227 &self,
228 db: &impl DefDatabase,
229 module: CrateModuleId,
230 sink: &mut DiagnosticSink,
231 ) {
232 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
233 }
234
243 pub(crate) fn resolve_macro( 235 pub(crate) fn resolve_macro(
244 &self, 236 &self,
245 macro_call_id: MacroCallId, 237 macro_call_id: MacroCallId,
@@ -452,3 +444,48 @@ impl CrateDefMap {
452 } 444 }
453 } 445 }
454} 446}
447
448mod diagnostics {
449 use relative_path::RelativePathBuf;
450 use ra_syntax::{AstPtr, AstNode, ast};
451
452 use crate::{
453 SourceItemId, DefDatabase,
454 nameres::CrateModuleId,
455 diagnostics::{DiagnosticSink, UnresolvedModule},
456};
457
458 #[derive(Debug, PartialEq, Eq)]
459 pub(super) enum DefDiagnostic {
460 UnresolvedModule {
461 module: CrateModuleId,
462 declaration: SourceItemId,
463 candidate: RelativePathBuf,
464 },
465 }
466
467 impl DefDiagnostic {
468 pub(super) fn add_to(
469 &self,
470 db: &impl DefDatabase,
471 target_module: CrateModuleId,
472 sink: &mut DiagnosticSink,
473 ) {
474 match self {
475 DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
476 if *module != target_module {
477 return;
478 }
479 let syntax = db.file_item(*declaration);
480 let decl = ast::Module::cast(&syntax).unwrap();
481 sink.push(UnresolvedModule {
482 file: declaration.file_id,
483 decl: AstPtr::new(&decl),
484 candidate: candidate.clone(),
485 })
486 }
487 }
488 }
489 }
490
491}
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index c5b73cfbe..8830b4624 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -6,14 +6,17 @@ use ra_db::FileId;
6 6
7use crate::{ 7use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 DefDatabase, HirFileId, Name, Path, Problem, Crate, 9 DefDatabase, HirFileId, Name, Path, Crate,
10 KnownName, 10 KnownName,
11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw}, 11 nameres::{
12 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
13 CrateDefMap, CrateModuleId, ModuleData, CrateMacroId,
14 diagnostics::DefDiagnostic,
15 raw,
16 },
12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, 17 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
13}; 18};
14 19
15use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId};
16
17pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 20pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
18 // populate external prelude 21 // populate external prelude
19 for dep in def_map.krate.dependencies(db) { 22 for dep in def_map.krate.dependencies(db) {
@@ -405,25 +408,27 @@ where
405 raw::ModuleData::Declaration { name, source_item_id } => { 408 raw::ModuleData::Declaration { name, source_item_id } => {
406 let source_item_id = source_item_id.with_file_id(self.file_id); 409 let source_item_id = source_item_id.with_file_id(self.file_id);
407 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 410 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
408 let (file_ids, problem) = 411 match resolve_submodule(self.def_collector.db, self.file_id, name, is_root) {
409 resolve_submodule(self.def_collector.db, self.file_id, name, is_root); 412 Ok(file_id) => {
410 413 let module_id =
411 if let Some(problem) = problem { 414 self.push_child_module(name.clone(), source_item_id, Some(file_id));
412 self.def_collector.def_map.problems.add(source_item_id, problem) 415 let raw_items = self.def_collector.db.raw_items(file_id);
413 } 416 ModCollector {
414 417 def_collector: &mut *self.def_collector,
415 if let Some(&file_id) = file_ids.first() { 418 module_id,
416 let module_id = 419 file_id: file_id.into(),
417 self.push_child_module(name.clone(), source_item_id, Some(file_id)); 420 raw_items: &raw_items,
418 let raw_items = self.def_collector.db.raw_items(file_id); 421 }
419 ModCollector { 422 .collect(raw_items.items())
420 def_collector: &mut *self.def_collector,
421 module_id,
422 file_id: file_id.into(),
423 raw_items: &raw_items,
424 } 423 }
425 .collect(raw_items.items()) 424 Err(candidate) => self.def_collector.def_map.diagnostics.push(
426 } 425 DefDiagnostic::UnresolvedModule {
426 module: self.module_id,
427 declaration: source_item_id,
428 candidate,
429 },
430 ),
431 };
427 } 432 }
428 } 433 }
429 } 434 }
@@ -524,7 +529,7 @@ fn resolve_submodule(
524 file_id: HirFileId, 529 file_id: HirFileId,
525 name: &Name, 530 name: &Name,
526 is_root: bool, 531 is_root: bool,
527) -> (Vec<FileId>, Option<Problem>) { 532) -> Result<FileId, RelativePathBuf> {
528 // FIXME: handle submodules of inline modules properly 533 // FIXME: handle submodules of inline modules properly
529 let file_id = file_id.original_file(db); 534 let file_id = file_id.original_file(db);
530 let source_root_id = db.file_source_root(file_id); 535 let source_root_id = db.file_source_root(file_id);
@@ -545,17 +550,10 @@ fn resolve_submodule(
545 candidates.push(file_dir_mod.clone()); 550 candidates.push(file_dir_mod.clone());
546 }; 551 };
547 let sr = db.source_root(source_root_id); 552 let sr = db.source_root(source_root_id);
548 let points_to = candidates 553 let mut points_to = candidates.into_iter().filter_map(|path| sr.files.get(&path)).map(|&it| it);
549 .into_iter() 554 // FIXME: handle ambiguity
550 .filter_map(|path| sr.files.get(&path)) 555 match points_to.next() {
551 .map(|&it| it) 556 Some(file_id) => Ok(file_id),
552 .collect::<Vec<_>>(); 557 None => Err(if is_dir_owner { file_mod } else { file_dir_mod }),
553 let problem = if points_to.is_empty() { 558 }
554 Some(Problem::UnresolvedModule {
555 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
556 })
557 } else {
558 None
559 };
560 (points_to, problem)
561} 559}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index ac9b88520..572bd1bf7 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -552,3 +552,22 @@ foo: v
552"### 552"###
553 ); 553 );
554} 554}
555
556#[test]
557fn unresolved_module_diagnostics() {
558 let diagnostics = MockDatabase::with_files(
559 r"
560 //- /lib.rs
561 mod foo;
562 mod bar;
563 mod baz {}
564 //- /foo.rs
565 ",
566 )
567 .diagnostics();
568
569 assert_snapshot_matches!(diagnostics, @r###"
570"mod bar;": unresolved module
571"###
572 );
573}
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index cff7e7481..5fd602a9e 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -36,7 +36,9 @@ use crate::{
36 path::{GenericArgs, GenericArg}, 36 path::{GenericArgs, GenericArg},
37 adt::VariantDef, 37 adt::VariantDef,
38 resolve::{Resolver, Resolution}, 38 resolve::{Resolver, Resolution},
39 nameres::Namespace 39 nameres::Namespace,
40 ty::infer::diagnostics::InferenceDiagnostic,
41 diagnostics::DiagnosticSink,
40}; 42};
41use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; 43use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor};
42 44
@@ -96,6 +98,7 @@ pub struct InferenceResult {
96 field_resolutions: FxHashMap<ExprId, StructField>, 98 field_resolutions: FxHashMap<ExprId, StructField>,
97 /// For each associated item record what it resolves to 99 /// For each associated item record what it resolves to
98 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, 100 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
101 diagnostics: Vec<InferenceDiagnostic>,
99 pub(super) type_of_expr: ArenaMap<ExprId, Ty>, 102 pub(super) type_of_expr: ArenaMap<ExprId, Ty>,
100 pub(super) type_of_pat: ArenaMap<PatId, Ty>, 103 pub(super) type_of_pat: ArenaMap<PatId, Ty>,
101} 104}
@@ -113,6 +116,14 @@ impl InferenceResult {
113 pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> { 116 pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> {
114 self.assoc_resolutions.get(&id.into()).map(|it| *it) 117 self.assoc_resolutions.get(&id.into()).map(|it| *it)
115 } 118 }
119 pub(crate) fn add_diagnostics(
120 &self,
121 db: &impl HirDatabase,
122 owner: Function,
123 sink: &mut DiagnosticSink,
124 ) {
125 self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink))
126 }
116} 127}
117 128
118impl Index<ExprId> for InferenceResult { 129impl Index<ExprId> for InferenceResult {
@@ -143,6 +154,7 @@ struct InferenceContext<'a, D: HirDatabase> {
143 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, 154 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
144 type_of_expr: ArenaMap<ExprId, Ty>, 155 type_of_expr: ArenaMap<ExprId, Ty>,
145 type_of_pat: ArenaMap<PatId, Ty>, 156 type_of_pat: ArenaMap<PatId, Ty>,
157 diagnostics: Vec<InferenceDiagnostic>,
146 /// The return type of the function being inferred. 158 /// The return type of the function being inferred.
147 return_ty: Ty, 159 return_ty: Ty,
148} 160}
@@ -155,6 +167,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
155 assoc_resolutions: FxHashMap::default(), 167 assoc_resolutions: FxHashMap::default(),
156 type_of_expr: ArenaMap::default(), 168 type_of_expr: ArenaMap::default(),
157 type_of_pat: ArenaMap::default(), 169 type_of_pat: ArenaMap::default(),
170 diagnostics: Vec::default(),
158 var_unification_table: InPlaceUnificationTable::new(), 171 var_unification_table: InPlaceUnificationTable::new(),
159 return_ty: Ty::Unknown, // set in collect_fn_signature 172 return_ty: Ty::Unknown, // set in collect_fn_signature
160 db, 173 db,
@@ -181,6 +194,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
181 assoc_resolutions: self.assoc_resolutions, 194 assoc_resolutions: self.assoc_resolutions,
182 type_of_expr: expr_types, 195 type_of_expr: expr_types,
183 type_of_pat: pat_types, 196 type_of_pat: pat_types,
197 diagnostics: self.diagnostics,
184 } 198 }
185 } 199 }
186 200
@@ -915,9 +929,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
915 Expr::StructLit { path, fields, spread } => { 929 Expr::StructLit { path, fields, spread } => {
916 let (ty, def_id) = self.resolve_variant(path.as_ref()); 930 let (ty, def_id) = self.resolve_variant(path.as_ref());
917 let substs = ty.substs().unwrap_or_else(Substs::empty); 931 let substs = ty.substs().unwrap_or_else(Substs::empty);
918 for field in fields { 932 for (field_idx, field) in fields.into_iter().enumerate() {
919 let field_ty = def_id 933 let field_ty = def_id
920 .and_then(|it| it.field(self.db, &field.name)) 934 .and_then(|it| match it.field(self.db, &field.name) {
935 Some(field) => Some(field),
936 None => {
937 self.diagnostics.push(InferenceDiagnostic::NoSuchField {
938 expr: tgt_expr,
939 field: field_idx,
940 });
941 None
942 }
943 })
921 .map_or(Ty::Unknown, |field| field.ty(self.db)) 944 .map_or(Ty::Unknown, |field| field.ty(self.db))
922 .subst(&substs); 945 .subst(&substs);
923 self.infer_expr(field.expr, &Expectation::has_type(field_ty)); 946 self.infer_expr(field.expr, &Expectation::has_type(field_ty));
@@ -1244,3 +1267,29 @@ impl Expectation {
1244 Expectation { ty: Ty::Unknown } 1267 Expectation { ty: Ty::Unknown }
1245 } 1268 }
1246} 1269}
1270
1271mod diagnostics {
1272 use crate::{expr::ExprId, diagnostics::{DiagnosticSink, NoSuchField}, HirDatabase, Function};
1273
1274 #[derive(Debug, PartialEq, Eq, Clone)]
1275 pub(super) enum InferenceDiagnostic {
1276 NoSuchField { expr: ExprId, field: usize },
1277 }
1278
1279 impl InferenceDiagnostic {
1280 pub(super) fn add_to(
1281 &self,
1282 db: &impl HirDatabase,
1283 owner: Function,
1284 sink: &mut DiagnosticSink,
1285 ) {
1286 match self {
1287 InferenceDiagnostic::NoSuchField { expr, field } => {
1288 let (file, _) = owner.source(db);
1289 let field = owner.body_source_map(db).field_syntax(*expr, *field);
1290 sink.push(NoSuchField { file, field })
1291 }
1292 }
1293 }
1294 }
1295}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 5d8ad4aa7..3aedba243 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2319,3 +2319,27 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
2319 assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) 2319 assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events)
2320 } 2320 }
2321} 2321}
2322
2323#[test]
2324fn no_such_field_diagnostics() {
2325 let diagnostics = MockDatabase::with_files(
2326 r"
2327 //- /lib.rs
2328 struct S { foo: i32, bar: () }
2329 impl S {
2330 fn new() -> S {
2331 S {
2332 foo: 92,
2333 baz: 62,
2334 }
2335 }
2336 }
2337 ",
2338 )
2339 .diagnostics();
2340
2341 assert_snapshot_matches!(diagnostics, @r###"
2342"baz: 62": no such field
2343"###
2344 );
2345}
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml
index c64226801..45bab4e28 100644
--- a/crates/ra_ide_api/Cargo.toml
+++ b/crates/ra_ide_api/Cargo.toml
@@ -20,7 +20,6 @@ jemallocator = { version = "0.1.9", optional = true }
20jemalloc-ctl = { version = "0.2.0", optional = true } 20jemalloc-ctl = { version = "0.2.0", optional = true }
21 21
22ra_syntax = { path = "../ra_syntax" } 22ra_syntax = { path = "../ra_syntax" }
23ra_ide_api_light = { path = "../ra_ide_api_light" }
24ra_text_edit = { path = "../ra_text_edit" } 23ra_text_edit = { path = "../ra_text_edit" }
25ra_db = { path = "../ra_db" } 24ra_db = { path = "../ra_db" }
26ra_fmt = { path = "../ra_fmt" } 25ra_fmt = { path = "../ra_fmt" }
diff --git a/crates/ra_ide_api/src/assists.rs b/crates/ra_ide_api/src/assists.rs
index 3c0475a51..355c0a42a 100644
--- a/crates/ra_ide_api/src/assists.rs
+++ b/crates/ra_ide_api/src/assists.rs
@@ -17,14 +17,9 @@ pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> {
17 let file_id = frange.file_id; 17 let file_id = frange.file_id;
18 let file_edit = SourceFileEdit { file_id, edit: action.edit }; 18 let file_edit = SourceFileEdit { file_id, edit: action.edit };
19 let id = label.id; 19 let id = label.id;
20 let change = SourceChange { 20 let change = SourceChange::source_file_edit(label.label, file_edit).with_cursor_opt(
21 label: label.label, 21 action.cursor_position.map(|offset| FilePosition { offset, file_id }),
22 source_file_edits: vec![file_edit], 22 );
23 file_system_edits: vec![],
24 cursor_position: action
25 .cursor_position
26 .map(|offset| FilePosition { offset, file_id }),
27 };
28 Assist { id, change } 23 Assist { id, change }
29 }) 24 })
30 .collect() 25 .collect()
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index b9dc424c6..5a78e94d8 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -1,10 +1,11 @@
1use std::cell::RefCell;
2
1use itertools::Itertools; 3use itertools::Itertools;
2use hir::{Problem, source_binder}; 4use hir::{source_binder, diagnostics::{Diagnostic as _, DiagnosticSink}};
3use ra_db::SourceDatabase; 5use ra_db::SourceDatabase;
4use ra_syntax::{ 6use ra_syntax::{
5 Location, SourceFile, SyntaxKind, TextRange, SyntaxNode, 7 Location, SourceFile, SyntaxKind, TextRange, SyntaxNode,
6 ast::{self, AstNode}, 8 ast::{self, AstNode},
7
8}; 9};
9use ra_text_edit::{TextEdit, TextEditBuilder}; 10use ra_text_edit::{TextEdit, TextEditBuilder};
10 11
@@ -26,11 +27,31 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
26 check_unnecessary_braces_in_use_statement(&mut res, file_id, node); 27 check_unnecessary_braces_in_use_statement(&mut res, file_id, node);
27 check_struct_shorthand_initialization(&mut res, file_id, node); 28 check_struct_shorthand_initialization(&mut res, file_id, node);
28 } 29 }
29 30 let res = RefCell::new(res);
31 let mut sink = DiagnosticSink::new(|d| {
32 res.borrow_mut().push(Diagnostic {
33 message: d.message(),
34 range: d.highlight_range(),
35 severity: Severity::Error,
36 fix: None,
37 })
38 })
39 .on::<hir::diagnostics::UnresolvedModule, _>(|d| {
40 let source_root = db.file_source_root(d.file().original_file(db));
41 let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() };
42 let fix = SourceChange::file_system_edit("create module", create_file);
43 res.borrow_mut().push(Diagnostic {
44 range: d.highlight_range(),
45 message: d.message(),
46 severity: Severity::Error,
47 fix: Some(fix),
48 })
49 });
30 if let Some(m) = source_binder::module_from_file_id(db, file_id) { 50 if let Some(m) = source_binder::module_from_file_id(db, file_id) {
31 check_module(&mut res, db, file_id, m); 51 m.diagnostics(db, &mut sink);
32 }; 52 };
33 res 53 drop(sink);
54 res.into_inner()
34} 55}
35 56
36fn syntax_errors(acc: &mut Vec<Diagnostic>, source_file: &SourceFile) { 57fn syntax_errors(acc: &mut Vec<Diagnostic>, source_file: &SourceFile) {
@@ -71,12 +92,10 @@ fn check_unnecessary_braces_in_use_statement(
71 range, 92 range,
72 message: format!("Unnecessary braces in use statement"), 93 message: format!("Unnecessary braces in use statement"),
73 severity: Severity::WeakWarning, 94 severity: Severity::WeakWarning,
74 fix: Some(SourceChange { 95 fix: Some(SourceChange::source_file_edit(
75 label: "Remove unnecessary braces".to_string(), 96 "Remove unnecessary braces",
76 source_file_edits: vec![SourceFileEdit { file_id, edit }], 97 SourceFileEdit { file_id, edit },
77 file_system_edits: Vec::new(), 98 )),
78 cursor_position: None,
79 }),
80 }); 99 });
81 } 100 }
82 101
@@ -119,12 +138,10 @@ fn check_struct_shorthand_initialization(
119 range: named_field.syntax().range(), 138 range: named_field.syntax().range(),
120 message: format!("Shorthand struct initialization"), 139 message: format!("Shorthand struct initialization"),
121 severity: Severity::WeakWarning, 140 severity: Severity::WeakWarning,
122 fix: Some(SourceChange { 141 fix: Some(SourceChange::source_file_edit(
123 label: "use struct shorthand initialization".to_string(), 142 "use struct shorthand initialization",
124 source_file_edits: vec![SourceFileEdit { file_id, edit }], 143 SourceFileEdit { file_id, edit },
125 file_system_edits: Vec::new(), 144 )),
126 cursor_position: None,
127 }),
128 }); 145 });
129 } 146 }
130 } 147 }
@@ -132,39 +149,12 @@ fn check_struct_shorthand_initialization(
132 Some(()) 149 Some(())
133} 150}
134 151
135fn check_module(
136 acc: &mut Vec<Diagnostic>,
137 db: &RootDatabase,
138 file_id: FileId,
139 module: hir::Module,
140) {
141 let source_root = db.file_source_root(file_id);
142 for (name_node, problem) in module.problems(db) {
143 let diag = match problem {
144 Problem::UnresolvedModule { candidate } => {
145 let create_file =
146 FileSystemEdit::CreateFile { source_root, path: candidate.clone() };
147 let fix = SourceChange {
148 label: "create module".to_string(),
149 source_file_edits: Vec::new(),
150 file_system_edits: vec![create_file],
151 cursor_position: None,
152 };
153 Diagnostic {
154 range: name_node.range(),
155 message: "unresolved module".to_string(),
156 severity: Severity::Error,
157 fix: Some(fix),
158 }
159 }
160 };
161 acc.push(diag)
162 }
163}
164
165#[cfg(test)] 152#[cfg(test)]
166mod tests { 153mod tests {
167 use test_utils::assert_eq_text; 154 use test_utils::assert_eq_text;
155 use insta::assert_debug_snapshot_matches;
156
157 use crate::mock_analysis::single_file;
168 158
169 use super::*; 159 use super::*;
170 160
@@ -194,6 +184,34 @@ mod tests {
194 } 184 }
195 185
196 #[test] 186 #[test]
187 fn test_unresolved_module_diagnostic() {
188 let (analysis, file_id) = single_file("mod foo;");
189 let diagnostics = analysis.diagnostics(file_id).unwrap();
190 assert_debug_snapshot_matches!(diagnostics, @r####"[
191 Diagnostic {
192 message: "unresolved module",
193 range: [0; 8),
194 fix: Some(
195 SourceChange {
196 label: "create module",
197 source_file_edits: [],
198 file_system_edits: [
199 CreateFile {
200 source_root: SourceRootId(
201 0
202 ),
203 path: "foo.rs"
204 }
205 ],
206 cursor_position: None
207 }
208 ),
209 severity: Error
210 }
211]"####);
212 }
213
214 #[test]
197 fn test_check_unnecessary_braces_in_use_statement() { 215 fn test_check_unnecessary_braces_in_use_statement() {
198 check_not_applicable( 216 check_not_applicable(
199 " 217 "
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 99f18b6b8..9063f78a9 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -6,9 +6,6 @@
6//! database, and the `ra_hir` crate, where majority of the analysis happens. 6//! database, and the `ra_hir` crate, where majority of the analysis happens.
7//! However, IDE specific bits of the analysis (most notably completion) happen 7//! However, IDE specific bits of the analysis (most notably completion) happen
8//! in this crate. 8//! in this crate.
9//!
10//! The sibling `ra_ide_api_light` handles those bits of IDE functionality
11//! which are restricted to a single file and need only syntax.
12 9
13// For proving that RootDatabase is RefUnwindSafe. 10// For proving that RootDatabase is RefUnwindSafe.
14#![recursion_limit = "128"] 11#![recursion_limit = "128"]
@@ -33,10 +30,11 @@ mod impls;
33mod assists; 30mod assists;
34mod diagnostics; 31mod diagnostics;
35mod syntax_tree; 32mod syntax_tree;
36mod line_index;
37mod folding_ranges; 33mod folding_ranges;
34mod line_index;
38mod line_index_utils; 35mod line_index_utils;
39mod join_lines; 36mod join_lines;
37mod structure;
40mod typing; 38mod typing;
41mod matching_brace; 39mod matching_brace;
42 40
@@ -72,9 +70,10 @@ pub use crate::{
72 line_index_utils::translate_offset_with_edit, 70 line_index_utils::translate_offset_with_edit,
73 folding_ranges::{Fold, FoldKind}, 71 folding_ranges::{Fold, FoldKind},
74 syntax_highlighting::HighlightedRange, 72 syntax_highlighting::HighlightedRange,
73 structure::{StructureNode, file_structure},
75 diagnostics::Severity, 74 diagnostics::Severity,
76}; 75};
77pub use ra_ide_api_light::StructureNode; 76
78pub use ra_db::{ 77pub use ra_db::{
79 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId, 78 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId,
80 Edition 79 Edition
@@ -97,6 +96,79 @@ pub struct SourceChange {
97 pub cursor_position: Option<FilePosition>, 96 pub cursor_position: Option<FilePosition>,
98} 97}
99 98
99impl SourceChange {
100 /// Creates a new SourceChange with the given label
101 /// from the edits.
102 pub(crate) fn from_edits<L: Into<String>>(
103 label: L,
104 source_file_edits: Vec<SourceFileEdit>,
105 file_system_edits: Vec<FileSystemEdit>,
106 ) -> Self {
107 SourceChange {
108 label: label.into(),
109 source_file_edits,
110 file_system_edits,
111 cursor_position: None,
112 }
113 }
114
115 /// Creates a new SourceChange with the given label,
116 /// containing only the given `SourceFileEdits`.
117 pub(crate) fn source_file_edits<L: Into<String>>(label: L, edits: Vec<SourceFileEdit>) -> Self {
118 SourceChange {
119 label: label.into(),
120 source_file_edits: edits,
121 file_system_edits: vec![],
122 cursor_position: None,
123 }
124 }
125
126 /// Creates a new SourceChange with the given label,
127 /// containing only the given `FileSystemEdits`.
128 pub(crate) fn file_system_edits<L: Into<String>>(label: L, edits: Vec<FileSystemEdit>) -> Self {
129 SourceChange {
130 label: label.into(),
131 source_file_edits: vec![],
132 file_system_edits: edits,
133 cursor_position: None,
134 }
135 }
136
137 /// Creates a new SourceChange with the given label,
138 /// containing only a single `SourceFileEdit`.
139 pub(crate) fn source_file_edit<L: Into<String>>(label: L, edit: SourceFileEdit) -> Self {
140 SourceChange::source_file_edits(label, vec![edit])
141 }
142
143 /// Creates a new SourceChange with the given label
144 /// from the given `FileId` and `TextEdit`
145 pub(crate) fn source_file_edit_from<L: Into<String>>(
146 label: L,
147 file_id: FileId,
148 edit: TextEdit,
149 ) -> Self {
150 SourceChange::source_file_edit(label, SourceFileEdit { file_id, edit })
151 }
152
153 /// Creates a new SourceChange with the given label
154 /// from the given `FileId` and `TextEdit`
155 pub(crate) fn file_system_edit<L: Into<String>>(label: L, edit: FileSystemEdit) -> Self {
156 SourceChange::file_system_edits(label, vec![edit])
157 }
158
159 /// Sets the cursor position to the given `FilePosition`
160 pub(crate) fn with_cursor(mut self, cursor_position: FilePosition) -> Self {
161 self.cursor_position = Some(cursor_position);
162 self
163 }
164
165 /// Sets the cursor position to the given `FilePosition`
166 pub(crate) fn with_cursor_opt(mut self, cursor_position: Option<FilePosition>) -> Self {
167 self.cursor_position = cursor_position;
168 self
169 }
170}
171
100#[derive(Debug)] 172#[derive(Debug)]
101pub struct SourceFileEdit { 173pub struct SourceFileEdit {
102 pub file_id: FileId, 174 pub file_id: FileId,
@@ -285,12 +357,7 @@ impl Analysis {
285 file_id: frange.file_id, 357 file_id: frange.file_id,
286 edit: join_lines::join_lines(&file, frange.range), 358 edit: join_lines::join_lines(&file, frange.range),
287 }; 359 };
288 SourceChange { 360 SourceChange::source_file_edit("join lines", file_edit)
289 label: "join lines".to_string(),
290 source_file_edits: vec![file_edit],
291 file_system_edits: vec![],
292 cursor_position: None,
293 }
294 } 361 }
295 362
296 /// Returns an edit which should be applied when opening a new line, fixing 363 /// Returns an edit which should be applied when opening a new line, fixing
@@ -305,12 +372,10 @@ impl Analysis {
305 pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { 372 pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> {
306 let file = self.db.parse(position.file_id); 373 let file = self.db.parse(position.file_id);
307 let edit = typing::on_eq_typed(&file, position.offset)?; 374 let edit = typing::on_eq_typed(&file, position.offset)?;
308 Some(SourceChange { 375 Some(SourceChange::source_file_edit(
309 label: "add semicolon".to_string(), 376 "add semicolon",
310 source_file_edits: vec![SourceFileEdit { edit, file_id: position.file_id }], 377 SourceFileEdit { edit, file_id: position.file_id },
311 file_system_edits: vec![], 378 ))
312 cursor_position: None,
313 })
314 } 379 }
315 380
316 /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. 381 /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
@@ -322,7 +387,7 @@ impl Analysis {
322 /// file outline. 387 /// file outline.
323 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { 388 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
324 let file = self.db.parse(file_id); 389 let file = self.db.parse(file_id);
325 ra_ide_api_light::file_structure(&file) 390 structure::file_structure(&file)
326 } 391 }
327 392
328 /// Returns the set of folding ranges. 393 /// Returns the set of folding ranges.
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index b7784e577..22741445a 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -187,12 +187,7 @@ fn rename_mod(
187 }; 187 };
188 source_file_edits.push(edit); 188 source_file_edits.push(edit);
189 189
190 Some(SourceChange { 190 Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits))
191 label: "rename".to_string(),
192 source_file_edits,
193 file_system_edits,
194 cursor_position: None,
195 })
196} 191}
197 192
198fn rename_reference( 193fn rename_reference(
@@ -211,12 +206,7 @@ fn rename_reference(
211 return None; 206 return None;
212 } 207 }
213 208
214 Some(SourceChange { 209 Some(SourceChange::source_file_edits("rename", edit))
215 label: "rename".to_string(),
216 source_file_edits: edit,
217 file_system_edits: Vec::new(),
218 cursor_position: None,
219 })
220} 210}
221 211
222#[cfg(test)] 212#[cfg(test)]
diff --git a/crates/ra_ide_api_light/src/snapshots/tests__file_structure.snap b/crates/ra_ide_api/src/snapshots/tests__file_structure.snap
index 8e4184b31..2efa8e22c 100644
--- a/crates/ra_ide_api_light/src/snapshots/tests__file_structure.snap
+++ b/crates/ra_ide_api/src/snapshots/tests__file_structure.snap
@@ -1,7 +1,7 @@
1--- 1---
2created: "2019-02-05T22:03:50.763530100Z" 2created: "2019-02-05T22:03:50.763530100Z"
3creator: [email protected] 3creator: [email protected]
4source: crates/ra_ide_api_light/src/structure.rs 4source: crates/ra_ide_api/src/structure.rs
5expression: structure 5expression: structure
6--- 6---
7[ 7[
diff --git a/crates/ra_ide_api_light/src/structure.rs b/crates/ra_ide_api/src/structure.rs
index ec2c9bbc6..ec2c9bbc6 100644
--- a/crates/ra_ide_api_light/src/structure.rs
+++ b/crates/ra_ide_api/src/structure.rs
diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs
index 94b228466..501d44dbb 100644
--- a/crates/ra_ide_api/src/typing.rs
+++ b/crates/ra_ide_api/src/typing.rs
@@ -31,12 +31,14 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Sour
31 let cursor_position = position.offset + TextUnit::of_str(&inserted); 31 let cursor_position = position.offset + TextUnit::of_str(&inserted);
32 let mut edit = TextEditBuilder::default(); 32 let mut edit = TextEditBuilder::default();
33 edit.insert(position.offset, inserted); 33 edit.insert(position.offset, inserted);
34 Some(SourceChange { 34
35 label: "on enter".to_string(), 35 Some(
36 source_file_edits: vec![SourceFileEdit { edit: edit.finish(), file_id: position.file_id }], 36 SourceChange::source_file_edit(
37 file_system_edits: vec![], 37 "on enter",
38 cursor_position: Some(FilePosition { offset: cursor_position, file_id: position.file_id }), 38 SourceFileEdit { edit: edit.finish(), file_id: position.file_id },
39 }) 39 )
40 .with_cursor(FilePosition { offset: cursor_position, file_id: position.file_id }),
41 )
40} 42}
41 43
42fn node_indent<'a>(file: &'a SourceFile, node: &SyntaxNode) -> Option<&'a str> { 44fn node_indent<'a>(file: &'a SourceFile, node: &SyntaxNode) -> Option<&'a str> {
@@ -110,16 +112,14 @@ pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option<
110 TextRange::from_to(position.offset - current_indent_len, position.offset), 112 TextRange::from_to(position.offset - current_indent_len, position.offset),
111 target_indent.into(), 113 target_indent.into(),
112 ); 114 );
113 let res = SourceChange { 115
114 label: "reindent dot".to_string(), 116 let res = SourceChange::source_file_edit_from("reindent dot", position.file_id, edit.finish())
115 source_file_edits: vec![SourceFileEdit { edit: edit.finish(), file_id: position.file_id }], 117 .with_cursor(FilePosition {
116 file_system_edits: vec![],
117 cursor_position: Some(FilePosition {
118 offset: position.offset + target_indent_len - current_indent_len 118 offset: position.offset + target_indent_len - current_indent_len
119 + TextUnit::of_char('.'), 119 + TextUnit::of_char('.'),
120 file_id: position.file_id, 120 file_id: position.file_id,
121 }), 121 });
122 }; 122
123 Some(res) 123 Some(res)
124} 124}
125 125
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs
index 0f0766f62..d4ff21c09 100644
--- a/crates/ra_ide_api/tests/test/main.rs
+++ b/crates/ra_ide_api/tests/test/main.rs
@@ -1,4 +1,3 @@
1use insta::assert_debug_snapshot_matches;
2use ra_ide_api::{ 1use ra_ide_api::{
3 mock_analysis::{single_file, single_file_with_position, single_file_with_range, MockAnalysis}, 2 mock_analysis::{single_file, single_file_with_position, single_file_with_range, MockAnalysis},
4 AnalysisChange, CrateGraph, Edition::Edition2018, Query, NavigationTarget, 3 AnalysisChange, CrateGraph, Edition::Edition2018, Query, NavigationTarget,
@@ -7,21 +6,6 @@ use ra_ide_api::{
7use ra_syntax::SmolStr; 6use ra_syntax::SmolStr;
8 7
9#[test] 8#[test]
10fn test_unresolved_module_diagnostic() {
11 let (analysis, file_id) = single_file("mod foo;");
12 let diagnostics = analysis.diagnostics(file_id).unwrap();
13 assert_debug_snapshot_matches!("unresolved_module_diagnostic", &diagnostics);
14}
15
16// FIXME: move this test to hir
17#[test]
18fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
19 let (analysis, file_id) = single_file("mod foo {}");
20 let diagnostics = analysis.diagnostics(file_id).unwrap();
21 assert!(diagnostics.is_empty());
22}
23
24#[test]
25fn test_resolve_crate_root() { 9fn test_resolve_crate_root() {
26 let mock = MockAnalysis::with_files( 10 let mock = MockAnalysis::with_files(
27 " 11 "
diff --git a/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap b/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap
deleted file mode 100644
index 5bb953892..000000000
--- a/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap
+++ /dev/null
@@ -1,28 +0,0 @@
1---
2created: "2019-01-22T14:45:01.486985900+00:00"
3creator: [email protected]
4expression: "&diagnostics"
5source: "crates\\ra_ide_api\\tests\\test\\main.rs"
6---
7[
8 Diagnostic {
9 message: "unresolved module",
10 range: [0; 8),
11 fix: Some(
12 SourceChange {
13 label: "create module",
14 source_file_edits: [],
15 file_system_edits: [
16 CreateFile {
17 source_root: SourceRootId(
18 0
19 ),
20 path: "foo.rs"
21 }
22 ],
23 cursor_position: None
24 }
25 ),
26 severity: Error
27 }
28]
diff --git a/crates/ra_ide_api_light/Cargo.toml b/crates/ra_ide_api_light/Cargo.toml
deleted file mode 100644
index 4e69f5325..000000000
--- a/crates/ra_ide_api_light/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
1[package]
2edition = "2018"
3name = "ra_ide_api_light"
4version = "0.1.0"
5authors = ["rust-analyzer developers"]
6publish = false
7
8[dependencies]
9itertools = "0.8.0"
10superslice = "1.0.0"
11join_to_string = "0.1.1"
12rustc-hash = "1.0"
13
14ra_syntax = { path = "../ra_syntax" }
15ra_text_edit = { path = "../ra_text_edit" }
16ra_fmt = { path = "../ra_fmt" }
17
18[dev-dependencies]
19test_utils = { path = "../test_utils" }
20insta = "0.7.0"
21
22[dev-dependencies.proptest]
23version = "0.9.0"
24# Disable `fork` feature to allow compiling on webassembly
25default-features = false
26features = ["std", "bit-set", "break-dead-code"]
diff --git a/crates/ra_ide_api_light/src/lib.rs b/crates/ra_ide_api_light/src/lib.rs
deleted file mode 100644
index df7f144b6..000000000
--- a/crates/ra_ide_api_light/src/lib.rs
+++ /dev/null
@@ -1,12 +0,0 @@
1//! This crate provides those IDE features which use only a single file.
2//!
3//! This usually means functions which take syntax tree as an input and produce
4//! an edit or some auxiliary info.
5
6mod structure;
7
8use ra_syntax::TextRange;
9
10pub use crate::{
11 structure::{file_structure, StructureNode},
12};
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index d8c2cb063..a6fac07c4 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -521,7 +521,7 @@ pub enum PrefixOp {
521} 521}
522 522
523impl PrefixExpr { 523impl PrefixExpr {
524 pub fn op(&self) -> Option<PrefixOp> { 524 pub fn op_kind(&self) -> Option<PrefixOp> {
525 match self.syntax().first_child()?.kind() { 525 match self.syntax().first_child()?.kind() {
526 STAR => Some(PrefixOp::Deref), 526 STAR => Some(PrefixOp::Deref),
527 EXCL => Some(PrefixOp::Not), 527 EXCL => Some(PrefixOp::Not),
@@ -529,6 +529,10 @@ impl PrefixExpr {
529 _ => None, 529 _ => None,
530 } 530 }
531 } 531 }
532
533 pub fn op(&self) -> Option<&SyntaxNode> {
534 self.syntax().first_child()
535 }
532} 536}
533 537
534#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 538#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -598,44 +602,49 @@ pub enum BinOp {
598} 602}
599 603
600impl BinExpr { 604impl BinExpr {
601 pub fn op(&self) -> Option<BinOp> { 605 fn op_details(&self) -> Option<(&SyntaxNode, BinOp)> {
602 self.syntax() 606 self.syntax().children().find_map(|c| match c.kind() {
603 .children() 607 PIPEPIPE => Some((c, BinOp::BooleanOr)),
604 .filter_map(|c| match c.kind() { 608 AMPAMP => Some((c, BinOp::BooleanAnd)),
605 PIPEPIPE => Some(BinOp::BooleanOr), 609 EQEQ => Some((c, BinOp::EqualityTest)),
606 AMPAMP => Some(BinOp::BooleanAnd), 610 NEQ => Some((c, BinOp::NegatedEqualityTest)),
607 EQEQ => Some(BinOp::EqualityTest), 611 LTEQ => Some((c, BinOp::LesserEqualTest)),
608 NEQ => Some(BinOp::NegatedEqualityTest), 612 GTEQ => Some((c, BinOp::GreaterEqualTest)),
609 LTEQ => Some(BinOp::LesserEqualTest), 613 L_ANGLE => Some((c, BinOp::LesserTest)),
610 GTEQ => Some(BinOp::GreaterEqualTest), 614 R_ANGLE => Some((c, BinOp::GreaterTest)),
611 L_ANGLE => Some(BinOp::LesserTest), 615 PLUS => Some((c, BinOp::Addition)),
612 R_ANGLE => Some(BinOp::GreaterTest), 616 STAR => Some((c, BinOp::Multiplication)),
613 PLUS => Some(BinOp::Addition), 617 MINUS => Some((c, BinOp::Subtraction)),
614 STAR => Some(BinOp::Multiplication), 618 SLASH => Some((c, BinOp::Division)),
615 MINUS => Some(BinOp::Subtraction), 619 PERCENT => Some((c, BinOp::Remainder)),
616 SLASH => Some(BinOp::Division), 620 SHL => Some((c, BinOp::LeftShift)),
617 PERCENT => Some(BinOp::Remainder), 621 SHR => Some((c, BinOp::RightShift)),
618 SHL => Some(BinOp::LeftShift), 622 CARET => Some((c, BinOp::BitwiseXor)),
619 SHR => Some(BinOp::RightShift), 623 PIPE => Some((c, BinOp::BitwiseOr)),
620 CARET => Some(BinOp::BitwiseXor), 624 AMP => Some((c, BinOp::BitwiseAnd)),
621 PIPE => Some(BinOp::BitwiseOr), 625 DOTDOT => Some((c, BinOp::RangeRightOpen)),
622 AMP => Some(BinOp::BitwiseAnd), 626 DOTDOTEQ => Some((c, BinOp::RangeRightClosed)),
623 DOTDOT => Some(BinOp::RangeRightOpen), 627 EQ => Some((c, BinOp::Assignment)),
624 DOTDOTEQ => Some(BinOp::RangeRightClosed), 628 PLUSEQ => Some((c, BinOp::AddAssign)),
625 EQ => Some(BinOp::Assignment), 629 SLASHEQ => Some((c, BinOp::DivAssign)),
626 PLUSEQ => Some(BinOp::AddAssign), 630 STAREQ => Some((c, BinOp::MulAssign)),
627 SLASHEQ => Some(BinOp::DivAssign), 631 PERCENTEQ => Some((c, BinOp::RemAssign)),
628 STAREQ => Some(BinOp::MulAssign), 632 SHREQ => Some((c, BinOp::ShrAssign)),
629 PERCENTEQ => Some(BinOp::RemAssign), 633 SHLEQ => Some((c, BinOp::ShlAssign)),
630 SHREQ => Some(BinOp::ShrAssign), 634 MINUSEQ => Some((c, BinOp::SubAssign)),
631 SHLEQ => Some(BinOp::ShlAssign), 635 PIPEEQ => Some((c, BinOp::BitOrAssign)),
632 MINUSEQ => Some(BinOp::SubAssign), 636 AMPEQ => Some((c, BinOp::BitAndAssign)),
633 PIPEEQ => Some(BinOp::BitOrAssign), 637 CARETEQ => Some((c, BinOp::BitXorAssign)),
634 AMPEQ => Some(BinOp::BitAndAssign), 638 _ => None,
635 CARETEQ => Some(BinOp::BitXorAssign), 639 })
636 _ => None, 640 }
637 }) 641
638 .next() 642 pub fn op_kind(&self) -> Option<BinOp> {
643 self.op_details().map(|t| t.1)
644 }
645
646 pub fn op(&self) -> Option<&SyntaxNode> {
647 self.op_details().map(|t| t.0)
639 } 648 }
640 649
641 pub fn lhs(&self) -> Option<&Expr> { 650 pub fn lhs(&self) -> Option<&Expr> {
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index aae590cb6..d8de1c4c1 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -64,6 +64,12 @@ impl<N: AstNode> AstPtr<N> {
64 } 64 }
65} 65}
66 66
67impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
68 fn from(ptr: AstPtr<N>) -> SyntaxNodePtr {
69 ptr.raw
70 }
71}
72
67#[test] 73#[test]
68fn test_local_syntax_ptr() { 74fn test_local_syntax_ptr() {
69 use crate::{ast, AstNode}; 75 use crate::{ast, AstNode};
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 104dd703d..d81c2f70d 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -12,7 +12,11 @@ should be enough to get you started!
12To learn more about how rust-analyzer works, see 12To learn more about how rust-analyzer works, see
13[./architecture.md](./architecture.md) document. 13[./architecture.md](./architecture.md) document.
14 14
15Various organizational and process issues are discussed here. 15We also publish rustdoc docs to pages:
16
17https://rust-analyzer.github.io/rust-analyzer/ra_ide_api/index.html
18
19Various organizational and process issues are discussed in this document.
16 20
17# Getting in Touch 21# Getting in Touch
18 22
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index f990d5bf0..890b18fcd 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -130,19 +130,6 @@ APIs in this crate are IDE centric: they take text offsets as input and produce
130offsets and strings as output. This works on top of rich code model powered by 130offsets and strings as output. This works on top of rich code model powered by
131`hir`. 131`hir`.
132 132
133### `crates/ra_ide_api_light`
134
135All IDE features which can be implemented if you only have access to a single
136file. `ra_ide_api_light` could be used to enhance editing of Rust code without
137the need to fiddle with build-systems, file synchronization and such.
138
139In a sense, `ra_ide_api_light` is just a bunch of pure functions which take a
140syntax tree as input.
141
142The tests for `ra_ide_api_light` are `#[cfg(test)] mod tests` unit-tests spread
143throughout its modules.
144
145
146### `crates/ra_lsp_server` 133### `crates/ra_lsp_server`
147 134
148An LSP implementation which wraps `ra_ide_api` into a langauge server protocol. 135An LSP implementation which wraps `ra_ide_api` into a langauge server protocol.