aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock113
-rw-r--r--README.md6
-rw-r--r--crates/ra_assists/src/flip_binexpr.rs141
-rw-r--r--crates/ra_assists/src/flip_eq_operands.rs86
-rw-r--r--crates/ra_assists/src/inline_local_variable.rs298
-rw-r--r--crates/ra_assists/src/lib.rs6
-rw-r--r--crates/ra_cli/Cargo.toml1
-rw-r--r--crates/ra_cli/src/main.rs2
-rw-r--r--crates/ra_db/Cargo.toml2
-rw-r--r--crates/ra_hir/src/code_model_api.rs50
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs35
-rw-r--r--crates/ra_hir/src/db.rs31
-rw-r--r--crates/ra_hir/src/diagnostics.rs115
-rw-r--r--crates/ra_hir/src/expr.rs15
-rw-r--r--crates/ra_hir/src/ids.rs197
-rw-r--r--crates/ra_hir/src/lib.rs10
-rw-r--r--crates/ra_hir/src/mock.rs18
-rw-r--r--crates/ra_hir/src/nameres.rs115
-rw-r--r--crates/ra_hir/src/nameres/collector.rs198
-rw-r--r--crates/ra_hir/src/nameres/raw.rs143
-rw-r--r--crates/ra_hir/src/nameres/tests.rs19
-rw-r--r--crates/ra_hir/src/nameres/tests/incremental.rs46
-rw-r--r--crates/ra_hir/src/resolve.rs17
-rw-r--r--crates/ra_hir/src/source_binder.rs10
-rw-r--r--crates/ra_hir/src/source_id.rs150
-rw-r--r--crates/ra_hir/src/traits.rs52
-rw-r--r--crates/ra_hir/src/ty.rs23
-rw-r--r--crates/ra_hir/src/ty/infer.rs58
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs95
-rw-r--r--crates/ra_hir/src/ty/tests.rs36
-rw-r--r--crates/ra_ide_api/Cargo.toml1
-rw-r--r--crates/ra_ide_api/src/change.rs4
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs87
-rw-r--r--crates/ra_ide_api/src/lib.rs11
-rw-r--r--crates/ra_ide_api/src/parent_module.rs30
-rw-r--r--crates/ra_ide_api/src/references.rs48
-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/symbol_index.rs58
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs257
-rw-r--r--crates/ra_ide_api/tests/test/main.rs392
-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_parser/src/grammar.rs4
-rw-r--r--crates/ra_syntax/src/ast/generated.rs6
-rw-r--r--crates/ra_syntax/src/grammar.ron5
-rw-r--r--crates/ra_syntax/src/ptr.rs6
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.rs1
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt17
-rw-r--r--crates/tools/src/lib.rs6
-rw-r--r--docs/dev/architecture.md13
-rw-r--r--docs/user/features.md19
-rw-r--r--editors/emacs/ra-emacs-lsp.el2
54 files changed, 1943 insertions, 1180 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7c07bddf9..669977163 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)",
@@ -911,7 +913,7 @@ dependencies = [
911 "ra_hir 0.1.0", 913 "ra_hir 0.1.0",
912 "ra_project_model 0.1.0", 914 "ra_project_model 0.1.0",
913 "ra_syntax 0.1.0", 915 "ra_syntax 0.1.0",
914 "ra_vfs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 916 "ra_vfs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
915 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 917 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
916 "test_utils 0.1.0", 918 "test_utils 0.1.0",
917] 919]
@@ -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_prof 0.1.0", 934 "ra_prof 0.1.0",
934 "ra_syntax 0.1.0", 935 "ra_syntax 0.1.0",
935 "tools 0.1.0", 936 "tools 0.1.0",
@@ -944,7 +945,7 @@ dependencies = [
944 "ra_syntax 0.1.0", 945 "ra_syntax 0.1.0",
945 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 946 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
946 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 947 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
947 "salsa 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 948 "salsa 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
948 "test_utils 0.1.0", 949 "test_utils 0.1.0",
949] 950]
950 951
@@ -962,8 +963,8 @@ version = "0.1.0"
962dependencies = [ 963dependencies = [
963 "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 964 "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
964 "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 965 "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
965 "flexi_logger 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", 966 "flexi_logger 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
966 "insta 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 967 "insta 0.7.4 (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)", 968 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
968 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 969 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
969 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 970 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -983,19 +984,18 @@ name = "ra_ide_api"
983version = "0.1.0" 984version = "0.1.0"
984dependencies = [ 985dependencies = [
985 "fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 986 "fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
986 "insta 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 987 "insta 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
987 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 988 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
988 "jemalloc-ctl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 989 "jemalloc-ctl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
989 "jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 990 "jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
990 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 991 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
991 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 992 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
992 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 993 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
993 "proptest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 994 "proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
994 "ra_assists 0.1.0", 995 "ra_assists 0.1.0",
995 "ra_db 0.1.0", 996 "ra_db 0.1.0",
996 "ra_fmt 0.1.0", 997 "ra_fmt 0.1.0",
997 "ra_hir 0.1.0", 998 "ra_hir 0.1.0",
998 "ra_ide_api_light 0.1.0",
999 "ra_syntax 0.1.0", 999 "ra_syntax 0.1.0",
1000 "ra_text_edit 0.1.0", 1000 "ra_text_edit 0.1.0",
1001 "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 1001 "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1007,29 +1007,13 @@ dependencies = [
1007] 1007]
1008 1008
1009[[package]] 1009[[package]]
1010name = "ra_ide_api_light"
1011version = "0.1.0"
1012dependencies = [
1013 "insta 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1014 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1015 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
1016 "proptest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
1017 "ra_fmt 0.1.0",
1018 "ra_syntax 0.1.0",
1019 "ra_text_edit 0.1.0",
1020 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1021 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1022 "test_utils 0.1.0",
1023]
1024
1025[[package]]
1026name = "ra_lsp_server" 1010name = "ra_lsp_server"
1027version = "0.1.0" 1011version = "0.1.0"
1028dependencies = [ 1012dependencies = [
1029 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1030 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1014 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1031 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1015 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1032 "flexi_logger 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", 1016 "flexi_logger 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
1033 "gen_lsp_server 0.1.0", 1017 "gen_lsp_server 0.1.0",
1034 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1018 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1035 "lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)", 1019 "lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1040,7 +1024,7 @@ dependencies = [
1040 "ra_project_model 0.1.0", 1024 "ra_project_model 0.1.0",
1041 "ra_syntax 0.1.0", 1025 "ra_syntax 0.1.0",
1042 "ra_text_edit 0.1.0", 1026 "ra_text_edit 0.1.0",
1043 "ra_vfs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1027 "ra_vfs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
1044 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1028 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1045 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1029 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1046 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 1030 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1080,7 +1064,7 @@ dependencies = [
1080name = "ra_project_model" 1064name = "ra_project_model"
1081version = "0.1.0" 1065version = "0.1.0"
1082dependencies = [ 1066dependencies = [
1083 "cargo_metadata 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 1067 "cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
1084 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1068 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1085 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1069 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1086 "ra_arena 0.1.0", 1070 "ra_arena 0.1.0",
@@ -1115,7 +1099,7 @@ dependencies = [
1115name = "ra_text_edit" 1099name = "ra_text_edit"
1116version = "0.1.0" 1100version = "0.1.0"
1117dependencies = [ 1101dependencies = [
1118 "proptest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 1102 "proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
1119 "test_utils 0.1.0", 1103 "test_utils 0.1.0",
1120 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1104 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1121] 1105]
@@ -1129,7 +1113,7 @@ dependencies = [
1129 1113
1130[[package]] 1114[[package]]
1131name = "ra_vfs" 1115name = "ra_vfs"
1132version = "0.2.0" 1116version = "0.2.1"
1133source = "registry+https://github.com/rust-lang/crates.io-index" 1117source = "registry+https://github.com/rust-lang/crates.io-index"
1134dependencies = [ 1118dependencies = [
1135 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1119 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1361,7 +1345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1361 1345
1362[[package]] 1346[[package]]
1363name = "salsa" 1347name = "salsa"
1364version = "0.10.0" 1348version = "0.11.1"
1365source = "registry+https://github.com/rust-lang/crates.io-index" 1349source = "registry+https://github.com/rust-lang/crates.io-index"
1366dependencies = [ 1350dependencies = [
1367 "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", 1351 "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1370,13 +1354,13 @@ dependencies = [
1370 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1354 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1371 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1355 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1372 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1356 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1373 "salsa-macros 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 1357 "salsa-macros 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
1374 "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 1358 "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
1375] 1359]
1376 1360
1377[[package]] 1361[[package]]
1378name = "salsa-macros" 1362name = "salsa-macros"
1379version = "0.10.0" 1363version = "0.11.1"
1380source = "registry+https://github.com/rust-lang/crates.io-index" 1364source = "registry+https://github.com/rust-lang/crates.io-index"
1381dependencies = [ 1365dependencies = [
1382 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1366 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1446,7 +1430,7 @@ version = "0.8.8"
1446source = "registry+https://github.com/rust-lang/crates.io-index" 1430source = "registry+https://github.com/rust-lang/crates.io-index"
1447dependencies = [ 1431dependencies = [
1448 "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 1432 "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
1449 "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1433 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1450 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 1434 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
1451 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 1435 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
1452] 1436]
@@ -1489,11 +1473,6 @@ dependencies = [
1489] 1473]
1490 1474
1491[[package]] 1475[[package]]
1492name = "spin"
1493version = "0.5.0"
1494source = "registry+https://github.com/rust-lang/crates.io-index"
1495
1496[[package]]
1497name = "stable_deref_trait" 1476name = "stable_deref_trait"
1498version = "1.1.1" 1477version = "1.1.1"
1499source = "registry+https://github.com/rust-lang/crates.io-index" 1478source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1786,7 +1765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1786 1765
1787[[package]] 1766[[package]]
1788name = "uuid" 1767name = "uuid"
1789version = "0.7.2" 1768version = "0.7.3"
1790source = "registry+https://github.com/rust-lang/crates.io-index" 1769source = "registry+https://github.com/rust-lang/crates.io-index"
1791dependencies = [ 1770dependencies = [
1792 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1771 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1864,7 +1843,7 @@ name = "yaml-rust"
1864version = "0.4.3" 1843version = "0.4.3"
1865source = "registry+https://github.com/rust-lang/crates.io-index" 1844source = "registry+https://github.com/rust-lang/crates.io-index"
1866dependencies = [ 1845dependencies = [
1867 "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1846 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1868] 1847]
1869 1848
1870[metadata] 1849[metadata]
@@ -1877,14 +1856,14 @@ dependencies = [
1877"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" 1856"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
1878"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" 1857"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
1879"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 1858"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
1880"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a" 1859"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
1881"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf" 1860"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
1882"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" 1861"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
1883"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 1862"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
1884"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" 1863"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
1885"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" 1864"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
1886"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" 1865"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
1887"checksum cargo_metadata 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bc796c7161c220089dfc7159e13324979181532850a237576b8fb907dd087c0d" 1866"checksum cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "178d62b240c34223f265a4c1e275e37d62da163d421fc8d7f7e3ee340f803c57"
1888"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" 1867"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
1889"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" 1868"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
1890"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" 1869"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
@@ -1913,7 +1892,7 @@ dependencies = [
1913"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" 1892"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
1914"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 1893"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
1915"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" 1894"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646"
1916"checksum flexi_logger 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7878fc9e06c948c6f9cddf571758e0c44786a509e646a094ef13ade3b1aab7" 1895"checksum flexi_logger 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "005c01dd6942ca46283b7304d14c6d04ec2c87a62f6e62e17c06fb812a574f4a"
1917"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" 1896"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
1918"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05" 1897"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
1919"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874" 1898"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
@@ -1923,6 +1902,7 @@ dependencies = [
1923"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1902"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
1924"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" 1903"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
1925"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" 1904"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
1905"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
1926"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 1906"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
1927"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" 1907"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e"
1928"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 1908"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
@@ -1930,7 +1910,7 @@ dependencies = [
1930"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" 1910"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c"
1931"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" 1911"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
1932"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" 1912"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
1933"checksum insta 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be9f00370d23dc7bd32a4d4506b1a14fb922fa39c576c3300fd25ce5b5dab18f" 1913"checksum insta 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "03e7d88a87d342ce8bd698516151be43e6eb2e84b683db528696cb4a382f734a"
1934"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" 1914"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
1935"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" 1915"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
1936"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 1916"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
@@ -1942,7 +1922,7 @@ dependencies = [
1942"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" 1922"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
1943"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" 1923"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
1944"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" 1924"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1"
1945"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" 1925"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
1946"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" 1926"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
1947"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" 1927"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
1948"checksum lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31954f2cf354421e6f99a48fdcfd5c3113c675a0db311960ffdac0b8d45cf09c" 1928"checksum lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31954f2cf354421e6f99a48fdcfd5c3113c675a0db311960ffdac0b8d45cf09c"
@@ -1970,10 +1950,10 @@ dependencies = [
1970"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646" 1950"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646"
1971"checksum pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e" 1951"checksum pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e"
1972"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" 1952"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
1973"checksum proptest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea66c78d75f2c6e9f304269eaef90899798daecc69f1a625d5a3dd793ff3522" 1953"checksum proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24f5844db2f839e97e3021980975f6ebf8691d9b9b2ca67ed3feb38dc3edb52c"
1974"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1954"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
1975"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 1955"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
1976"checksum ra_vfs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1839e4e003d865b58b8b6c231aae6c463dfcd01bfbbddffbdb7662a7b5a627" 1956"checksum ra_vfs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d75d08da053ec832676686c72dfe509fdd1e807191a50ac79087466ffefccb1c"
1977"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1957"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
1978"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1958"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
1979"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 1959"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
@@ -1999,8 +1979,8 @@ dependencies = [
1999"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" 1979"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
2000"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1980"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
2001"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" 1981"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
2002"checksum salsa 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cad0e2348e2f80725b2980914a08a00267136c3ecf720896d3f7f08eef51e08f" 1982"checksum salsa 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94f14bbb013866db2fbeceb97ed82cf35f42020edd39d35268f0b11f89399c79"
2003"checksum salsa-macros 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c79744109df21b80aef1367669b0a9e4985bc966e76bf0e9321b222ec0b9fbb" 1983"checksum salsa-macros 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1ad27cbae189e9739a96e469d37c6a6deafec36f1282d4fdf4681eae67c9dd39"
2004"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" 1984"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
2005"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 1985"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
2006"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1986"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
@@ -2014,7 +1994,6 @@ dependencies = [
2014"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" 1994"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
2015"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" 1995"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
2016"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e" 1996"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e"
2017"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
2018"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 1997"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
2019"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 1998"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
2020"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1999"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
@@ -2048,7 +2027,7 @@ dependencies = [
2048"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" 2027"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
2049"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" 2028"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"
2050"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" 2029"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
2051"checksum uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0238db0c5b605dd1cf51de0f21766f97fba2645897024461d6a00c036819a768" 2030"checksum uuid 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "600ef8213e9f8a0ac1f876e470e90780ae0478eabce7f76aff41b0f4ef0fd5c0"
2052"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 2031"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
2053"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" 2032"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
2054"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" 2033"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
diff --git a/README.md b/README.md
index 3a0c9dee1..8df991246 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,12 @@ We are on the rust-lang Zulip!
51 51
52https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0 52https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0
53 53
54## Quick Links
55
56* Work List: https://paper.dropbox.com/doc/RLS-2.0-work-list--AZ3BgHKKCtqszbsi3gi6sjchAQ-42vbnxzuKq2lKwW0mkn8Y
57* API docs: https://rust-analyzer.github.io/rust-analyzer/ra_ide_api/index.html
58* CI: https://travis-ci.org/rust-analyzer/rust-analyzer
59
54## License 60## License
55 61
56Rust analyzer is primarily distributed under the terms of both the MIT 62Rust analyzer is primarily distributed under the terms of both the MIT
diff --git a/crates/ra_assists/src/flip_binexpr.rs b/crates/ra_assists/src/flip_binexpr.rs
new file mode 100644
index 000000000..ec377642e
--- /dev/null
+++ b/crates/ra_assists/src/flip_binexpr.rs
@@ -0,0 +1,141 @@
1use hir::db::HirDatabase;
2use ra_syntax::ast::{AstNode, BinExpr, BinOp};
3
4use crate::{AssistCtx, Assist, AssistId};
5
6/// Flip binary expression assist.
7pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
8 let expr = ctx.node_at_offset::<BinExpr>()?;
9 let lhs = expr.lhs()?.syntax();
10 let rhs = expr.rhs()?.syntax();
11 let op_range = expr.op()?.range();
12 // The assist should be applied only if the cursor is on the operator
13 let cursor_in_range = ctx.frange.range.is_subrange(&op_range);
14 if !cursor_in_range {
15 return None;
16 }
17 let action: FlipAction = expr.op_kind()?.into();
18 // The assist should not be applied for certain operators
19 if let FlipAction::DontFlip = action {
20 return None;
21 }
22
23 ctx.add_action(AssistId("flip_binexpr"), "flip binary expression", |edit| {
24 edit.target(op_range);
25 if let FlipAction::FlipAndReplaceOp(new_op) = action {
26 edit.replace(op_range, new_op);
27 }
28 edit.replace(lhs.range(), rhs.text());
29 edit.replace(rhs.range(), lhs.text());
30 });
31
32 ctx.build()
33}
34
35enum FlipAction {
36 // Flip the expression
37 Flip,
38 // Flip the expression and replace the operator with this string
39 FlipAndReplaceOp(&'static str),
40 // Do not flip the expression
41 DontFlip,
42}
43
44impl From<BinOp> for FlipAction {
45 fn from(op_kind: BinOp) -> Self {
46 match op_kind {
47 BinOp::Assignment => FlipAction::DontFlip,
48 BinOp::AddAssign => FlipAction::DontFlip,
49 BinOp::DivAssign => FlipAction::DontFlip,
50 BinOp::MulAssign => FlipAction::DontFlip,
51 BinOp::RemAssign => FlipAction::DontFlip,
52 BinOp::ShrAssign => FlipAction::DontFlip,
53 BinOp::ShlAssign => FlipAction::DontFlip,
54 BinOp::SubAssign => FlipAction::DontFlip,
55 BinOp::BitOrAssign => FlipAction::DontFlip,
56 BinOp::BitAndAssign => FlipAction::DontFlip,
57 BinOp::BitXorAssign => FlipAction::DontFlip,
58 BinOp::GreaterTest => FlipAction::FlipAndReplaceOp("<"),
59 BinOp::GreaterEqualTest => FlipAction::FlipAndReplaceOp("<="),
60 BinOp::LesserTest => FlipAction::FlipAndReplaceOp(">"),
61 BinOp::LesserEqualTest => FlipAction::FlipAndReplaceOp(">="),
62 _ => FlipAction::Flip,
63 }
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 use crate::helpers::{ check_assist, check_assist_target, check_assist_not_applicable };
72
73 #[test]
74 fn flip_binexpr_target_is_the_op() {
75 check_assist_target(flip_binexpr, "fn f() { let res = 1 ==<|> 2; }", "==")
76 }
77
78 #[test]
79 fn flip_binexpr_not_applicable_for_assignment() {
80 check_assist_not_applicable(flip_binexpr, "fn f() { let mut _x = 1; _x +=<|> 2 }")
81 }
82
83 #[test]
84 fn flip_binexpr_works_for_eq() {
85 check_assist(
86 flip_binexpr,
87 "fn f() { let res = 1 ==<|> 2; }",
88 "fn f() { let res = 2 ==<|> 1; }",
89 )
90 }
91
92 #[test]
93 fn flip_binexpr_works_for_gt() {
94 check_assist(
95 flip_binexpr,
96 "fn f() { let res = 1 ><|> 2; }",
97 "fn f() { let res = 2 <<|> 1; }",
98 )
99 }
100
101 #[test]
102 fn flip_binexpr_works_for_lteq() {
103 check_assist(
104 flip_binexpr,
105 "fn f() { let res = 1 <=<|> 2; }",
106 "fn f() { let res = 2 >=<|> 1; }",
107 )
108 }
109
110 #[test]
111 fn flip_binexpr_works_for_complex_expr() {
112 check_assist(
113 flip_binexpr,
114 "fn f() { let res = (1 + 1) ==<|> (2 + 2); }",
115 "fn f() { let res = (2 + 2) ==<|> (1 + 1); }",
116 )
117 }
118
119 #[test]
120 fn flip_binexpr_works_inside_match() {
121 check_assist(
122 flip_binexpr,
123 r#"
124 fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
125 match other.downcast_ref::<Self>() {
126 None => false,
127 Some(it) => it ==<|> self,
128 }
129 }
130 "#,
131 r#"
132 fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
133 match other.downcast_ref::<Self>() {
134 None => false,
135 Some(it) => self ==<|> it,
136 }
137 }
138 "#,
139 )
140 }
141}
diff --git a/crates/ra_assists/src/flip_eq_operands.rs b/crates/ra_assists/src/flip_eq_operands.rs
deleted file mode 100644
index df0bb689d..000000000
--- a/crates/ra_assists/src/flip_eq_operands.rs
+++ /dev/null
@@ -1,86 +0,0 @@
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/inline_local_variable.rs b/crates/ra_assists/src/inline_local_variable.rs
new file mode 100644
index 000000000..bd3cdb970
--- /dev/null
+++ b/crates/ra_assists/src/inline_local_variable.rs
@@ -0,0 +1,298 @@
1use hir::db::HirDatabase;
2use hir::source_binder::function_from_child_node;
3use ra_syntax::{ast::{self, AstNode}, TextRange};
4use ra_syntax::ast::{PatKind, ExprKind};
5
6use crate::{Assist, AssistCtx, AssistId};
7use crate::assist_ctx::AssistBuilder;
8
9pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
10 let let_stmt = ctx.node_at_offset::<ast::LetStmt>()?;
11 let bind_pat = match let_stmt.pat()?.kind() {
12 PatKind::BindPat(pat) => pat,
13 _ => return None,
14 };
15 if bind_pat.is_mutable() {
16 return None;
17 }
18 let initializer = let_stmt.initializer()?;
19 let wrap_in_parens = match initializer.kind() {
20 ExprKind::LambdaExpr(_)
21 | ExprKind::IfExpr(_)
22 | ExprKind::LoopExpr(_)
23 | ExprKind::ForExpr(_)
24 | ExprKind::WhileExpr(_)
25 | ExprKind::ContinueExpr(_)
26 | ExprKind::BreakExpr(_)
27 | ExprKind::Label(_)
28 | ExprKind::ReturnExpr(_)
29 | ExprKind::MatchExpr(_)
30 | ExprKind::StructLit(_)
31 | ExprKind::CastExpr(_)
32 | ExprKind::PrefixExpr(_)
33 | ExprKind::RangeExpr(_)
34 | ExprKind::BinExpr(_) => true,
35 ExprKind::CallExpr(_)
36 | ExprKind::IndexExpr(_)
37 | ExprKind::MethodCallExpr(_)
38 | ExprKind::FieldExpr(_)
39 | ExprKind::TryExpr(_)
40 | ExprKind::RefExpr(_)
41 | ExprKind::Literal(_)
42 | ExprKind::TupleExpr(_)
43 | ExprKind::ArrayExpr(_)
44 | ExprKind::ParenExpr(_)
45 | ExprKind::PathExpr(_)
46 | ExprKind::BlockExpr(_) => false,
47 };
48
49 let delete_range = if let Some(whitespace) =
50 let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast)
51 {
52 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end())
53 } else {
54 let_stmt.syntax().range()
55 };
56
57 let init_str = if wrap_in_parens {
58 format!("({})", initializer.syntax().text().to_string())
59 } else {
60 initializer.syntax().text().to_string()
61 };
62 let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?;
63 let scope = function.scopes(ctx.db);
64 let refs = scope.find_all_refs(bind_pat);
65
66 ctx.add_action(
67 AssistId("inline_local_variable"),
68 "inline local variable",
69 move |edit: &mut AssistBuilder| {
70 edit.delete(delete_range);
71 for desc in refs {
72 edit.replace(desc.range, init_str.clone())
73 }
74 edit.set_cursor(delete_range.start())
75 },
76 );
77
78 ctx.build()
79}
80
81#[cfg(test)]
82mod tests {
83 use crate::helpers::{check_assist, check_assist_not_applicable};
84
85 use super::*;
86
87 #[test]
88 fn test_inline_let_bind_literal_expr() {
89 check_assist(
90 inline_local_varialbe,
91 "
92fn bar(a: usize) {}
93fn foo() {
94 let a<|> = 1;
95 a + 1;
96 if a > 10 {
97 }
98
99 while a > 10 {
100
101 }
102 let b = a * 10;
103 bar(a);
104}",
105 "
106fn bar(a: usize) {}
107fn foo() {
108 <|>1 + 1;
109 if 1 > 10 {
110 }
111
112 while 1 > 10 {
113
114 }
115 let b = 1 * 10;
116 bar(1);
117}",
118 );
119 }
120
121 #[test]
122 fn test_inline_let_bind_bin_expr() {
123 check_assist(
124 inline_local_varialbe,
125 "
126fn bar(a: usize) {}
127fn foo() {
128 let a<|> = 1 + 1;
129 a + 1;
130 if a > 10 {
131 }
132
133 while a > 10 {
134
135 }
136 let b = a * 10;
137 bar(a);
138}",
139 "
140fn bar(a: usize) {}
141fn foo() {
142 <|>(1 + 1) + 1;
143 if (1 + 1) > 10 {
144 }
145
146 while (1 + 1) > 10 {
147
148 }
149 let b = (1 + 1) * 10;
150 bar((1 + 1));
151}",
152 );
153 }
154
155 #[test]
156 fn test_inline_let_bind_function_call_expr() {
157 check_assist(
158 inline_local_varialbe,
159 "
160fn bar(a: usize) {}
161fn foo() {
162 let a<|> = bar(1);
163 a + 1;
164 if a > 10 {
165 }
166
167 while a > 10 {
168
169 }
170 let b = a * 10;
171 bar(a);
172}",
173 "
174fn bar(a: usize) {}
175fn foo() {
176 <|>bar(1) + 1;
177 if bar(1) > 10 {
178 }
179
180 while bar(1) > 10 {
181
182 }
183 let b = bar(1) * 10;
184 bar(bar(1));
185}",
186 );
187 }
188
189 #[test]
190 fn test_inline_let_bind_cast_expr() {
191 check_assist(
192 inline_local_varialbe,
193 "
194fn bar(a: usize): usize { a }
195fn foo() {
196 let a<|> = bar(1) as u64;
197 a + 1;
198 if a > 10 {
199 }
200
201 while a > 10 {
202
203 }
204 let b = a * 10;
205 bar(a);
206}",
207 "
208fn bar(a: usize): usize { a }
209fn foo() {
210 <|>(bar(1) as u64) + 1;
211 if (bar(1) as u64) > 10 {
212 }
213
214 while (bar(1) as u64) > 10 {
215
216 }
217 let b = (bar(1) as u64) * 10;
218 bar((bar(1) as u64));
219}",
220 );
221 }
222
223 #[test]
224 fn test_inline_let_bind_block_expr() {
225 check_assist(
226 inline_local_varialbe,
227 "
228fn foo() {
229 let a<|> = { 10 + 1 };
230 a + 1;
231 if a > 10 {
232 }
233
234 while a > 10 {
235
236 }
237 let b = a * 10;
238 bar(a);
239}",
240 "
241fn foo() {
242 <|>{ 10 + 1 } + 1;
243 if { 10 + 1 } > 10 {
244 }
245
246 while { 10 + 1 } > 10 {
247
248 }
249 let b = { 10 + 1 } * 10;
250 bar({ 10 + 1 });
251}",
252 );
253 }
254
255 #[test]
256 fn test_inline_let_bind_paren_expr() {
257 check_assist(
258 inline_local_varialbe,
259 "
260fn foo() {
261 let a<|> = ( 10 + 1 );
262 a + 1;
263 if a > 10 {
264 }
265
266 while a > 10 {
267
268 }
269 let b = a * 10;
270 bar(a);
271}",
272 "
273fn foo() {
274 <|>( 10 + 1 ) + 1;
275 if ( 10 + 1 ) > 10 {
276 }
277
278 while ( 10 + 1 ) > 10 {
279
280 }
281 let b = ( 10 + 1 ) * 10;
282 bar(( 10 + 1 ));
283}",
284 );
285 }
286
287 #[test]
288 fn test_not_inline_mut_variable() {
289 check_assist_not_applicable(
290 inline_local_varialbe,
291 "
292fn foo() {
293 let mut a<|> = 1 + 1;
294 a + 1;
295}",
296 );
297 }
298}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 8900fbc4b..c1514f8e5 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -88,11 +88,12 @@ where
88mod add_derive; 88mod add_derive;
89mod add_impl; 89mod add_impl;
90mod flip_comma; 90mod flip_comma;
91mod flip_eq_operands; 91mod flip_binexpr;
92mod change_visibility; 92mod change_visibility;
93mod fill_match_arms; 93mod fill_match_arms;
94mod fill_struct_fields; 94mod fill_struct_fields;
95mod introduce_variable; 95mod introduce_variable;
96mod inline_local_variable;
96mod replace_if_let_with_match; 97mod replace_if_let_with_match;
97mod split_import; 98mod split_import;
98mod remove_dbg; 99mod remove_dbg;
@@ -107,7 +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,
110 flip_eq_operands::flip_eq_operands, 111 flip_binexpr::flip_binexpr,
111 introduce_variable::introduce_variable, 112 introduce_variable::introduce_variable,
112 replace_if_let_with_match::replace_if_let_with_match, 113 replace_if_let_with_match::replace_if_let_with_match,
113 split_import::split_import, 114 split_import::split_import,
@@ -115,6 +116,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
115 auto_import::auto_import, 116 auto_import::auto_import,
116 add_missing_impl_members::add_missing_impl_members, 117 add_missing_impl_members::add_missing_impl_members,
117 add_missing_impl_members::add_missing_default_members, 118 add_missing_impl_members::add_missing_default_members,
119 inline_local_variable::inline_local_varialbe,
118 ] 120 ]
119} 121}
120 122
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index a92a63257..328b2436f 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 c13c7910c..ecea516f1 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};
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_db/Cargo.toml b/crates/ra_db/Cargo.toml
index c9b8f3c8e..581cd32fd 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8salsa = "0.10.0" 8salsa = "0.11.1"
9relative-path = "0.4.0" 9relative-path = "0.4.0"
10rustc-hash = "1.0" 10rustc-hash = "1.0"
11parking_lot = "0.7.0" 11parking_lot = "0.7.0"
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 45fa4cd11..624c25c4d 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,
@@ -14,9 +13,11 @@ use crate::{
14 adt::{EnumVariantId, StructFieldId, VariantDef}, 13 adt::{EnumVariantId, StructFieldId, VariantDef},
15 generics::GenericParams, 14 generics::GenericParams,
16 docs::{Documentation, Docs, docs_from_ast}, 15 docs::{Documentation, Docs, docs_from_ast},
17 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, 16 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeAliasId},
18 impl_block::ImplBlock, 17 impl_block::ImplBlock,
19 resolve::Resolver, 18 resolve::Resolver,
19 diagnostics::DiagnosticSink,
20 traits::{TraitItem, TraitData},
20}; 21};
21 22
22/// hir::Crate describes a single crate. It's the main interface with which 23/// hir::Crate describes a single crate. It's the main interface with which
@@ -95,11 +96,6 @@ pub enum ModuleSource {
95 Module(TreeArc<ast::Module>), 96 Module(TreeArc<ast::Module>),
96} 97}
97 98
98#[derive(Clone, Debug, Hash, PartialEq, Eq)]
99pub enum Problem {
100 UnresolvedModule { candidate: RelativePathBuf },
101}
102
103impl Module { 99impl Module {
104 /// Name of this module. 100 /// Name of this module.
105 pub fn name(&self, db: &impl HirDatabase) -> Option<Name> { 101 pub fn name(&self, db: &impl HirDatabase) -> Option<Name> {
@@ -171,8 +167,24 @@ impl Module {
171 db.crate_def_map(self.krate)[self.module_id].scope.clone() 167 db.crate_def_map(self.krate)[self.module_id].scope.clone()
172 } 168 }
173 169
174 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { 170 pub fn diagnostics(&self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
175 self.problems_impl(db) 171 db.crate_def_map(self.krate).add_diagnostics(db, self.module_id, sink);
172 for decl in self.declarations(db) {
173 match decl {
174 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
175 crate::ModuleDef::Module(f) => f.diagnostics(db, sink),
176 _ => (),
177 }
178 }
179
180 for impl_block in self.impl_blocks(db) {
181 for item in impl_block.items(db) {
182 match item {
183 crate::ImplItem::Method(f) => f.diagnostics(db, sink),
184 _ => (),
185 }
186 }
187 }
176 } 188 }
177 189
178 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 190 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
@@ -519,6 +531,10 @@ impl Function {
519 let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; 531 let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
520 r 532 r
521 } 533 }
534
535 pub fn diagnostics(&self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
536 self.infer(db).add_diagnostics(db, *self, sink);
537 }
522} 538}
523 539
524impl Docs for Function { 540impl Docs for Function {
@@ -634,6 +650,18 @@ impl Trait {
634 pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { 650 pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> {
635 db.generic_params((*self).into()) 651 db.generic_params((*self).into())
636 } 652 }
653
654 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
655 self.trait_data(db).name().clone()
656 }
657
658 pub fn items(self, db: &impl DefDatabase) -> Vec<TraitItem> {
659 self.trait_data(db).items().to_vec()
660 }
661
662 pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
663 db.trait_data(self)
664 }
637} 665}
638 666
639impl Docs for Trait { 667impl Docs for Trait {
@@ -644,7 +672,7 @@ impl Docs for Trait {
644 672
645#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 673#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
646pub struct TypeAlias { 674pub struct TypeAlias {
647 pub(crate) id: TypeId, 675 pub(crate) id: TypeAliasId,
648} 676}
649 677
650impl TypeAlias { 678impl TypeAlias {
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 52a33e981..0edb8ade5 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -1,18 +1,18 @@
1use ra_db::FileId; 1use ra_db::FileId;
2use ra_syntax::{ast, SyntaxNode, TreeArc, AstNode}; 2use ra_syntax::{ast, TreeArc};
3 3
4use crate::{ 4use crate::{
5 Module, ModuleSource, Problem, Name, 5 Module, ModuleSource, Name, AstId,
6 nameres::{CrateModuleId, ImportId}, 6 nameres::{CrateModuleId, ImportId},
7 HirDatabase, DefDatabase, 7 HirDatabase, DefDatabase,
8 HirFileId, SourceItemId, 8 HirFileId,
9}; 9};
10 10
11impl ModuleSource { 11impl ModuleSource {
12 pub(crate) fn new( 12 pub(crate) fn new(
13 db: &impl DefDatabase, 13 db: &impl DefDatabase,
14 file_id: Option<FileId>, 14 file_id: Option<FileId>,
15 decl_id: Option<SourceItemId>, 15 decl_id: Option<AstId<ast::Module>>,
16 ) -> ModuleSource { 16 ) -> ModuleSource {
17 match (file_id, decl_id) { 17 match (file_id, decl_id) {
18 (Some(file_id), _) => { 18 (Some(file_id), _) => {
@@ -20,8 +20,7 @@ impl ModuleSource {
20 ModuleSource::SourceFile(source_file) 20 ModuleSource::SourceFile(source_file)
21 } 21 }
22 (None, Some(item_id)) => { 22 (None, Some(item_id)) => {
23 let module = db.file_item(item_id); 23 let module = item_id.to_node(db);
24 let module = ast::Module::cast(&*module).unwrap();
25 assert!(module.item_list().is_some(), "expected inline module"); 24 assert!(module.item_list().is_some(), "expected inline module");
26 ModuleSource::Module(module.to_owned()) 25 ModuleSource::Module(module.to_owned())
27 } 26 }
@@ -55,7 +54,7 @@ impl Module {
55 let decl_id = def_map[self.module_id].declaration; 54 let decl_id = def_map[self.module_id].declaration;
56 let file_id = def_map[self.module_id].definition; 55 let file_id = def_map[self.module_id].definition;
57 let module_source = ModuleSource::new(db, file_id, decl_id); 56 let module_source = ModuleSource::new(db, file_id, decl_id);
58 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id); 57 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id());
59 (file_id, module_source) 58 (file_id, module_source)
60 } 59 }
61 60
@@ -65,9 +64,8 @@ impl Module {
65 ) -> Option<(HirFileId, TreeArc<ast::Module>)> { 64 ) -> Option<(HirFileId, TreeArc<ast::Module>)> {
66 let def_map = db.crate_def_map(self.krate); 65 let def_map = db.crate_def_map(self.krate);
67 let decl = def_map[self.module_id].declaration?; 66 let decl = def_map[self.module_id].declaration?;
68 let syntax_node = db.file_item(decl); 67 let ast = decl.to_node(db);
69 let ast = ast::Module::cast(&syntax_node).unwrap().to_owned(); 68 Some((decl.file_id(), ast))
70 Some((decl.file_id, ast))
71 } 69 }
72 70
73 pub(crate) fn import_source_impl( 71 pub(crate) fn import_source_impl(
@@ -76,7 +74,7 @@ impl Module {
76 import: ImportId, 74 import: ImportId,
77 ) -> TreeArc<ast::PathSegment> { 75 ) -> TreeArc<ast::PathSegment> {
78 let (file_id, source) = self.definition_source(db); 76 let (file_id, source) = self.definition_source(db);
79 let (_, source_map) = db.raw_items_with_source_map(file_id.original_file(db)); 77 let (_, source_map) = db.raw_items_with_source_map(file_id);
80 source_map.get(&source, import) 78 source_map.get(&source, import)
81 } 79 }
82 80
@@ -108,19 +106,4 @@ impl Module {
108 let parent_id = def_map[self.module_id].parent?; 106 let parent_id = def_map[self.module_id].parent?;
109 Some(self.with_module_id(parent_id)) 107 Some(self.with_module_id(parent_id))
110 } 108 }
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} 109}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index d3908f8ac..147005848 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,10 +1,10 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SourceDatabase, salsa, FileId}; 4use ra_db::{SourceDatabase, salsa};
5 5
6use crate::{ 6use crate::{
7 HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner, 7 HirFileId, MacroDefId, AstIdMap, ErasedFileAstId, Crate, Module, HirInterner,
8 Function, FnSignature, ExprScopes, TypeAlias, 8 Function, FnSignature, ExprScopes, TypeAlias,
9 Struct, Enum, StructField, 9 Struct, Enum, StructField,
10 Const, ConstSignature, Static, 10 Const, ConstSignature, Static,
@@ -14,11 +14,15 @@ use crate::{
14 impl_block::{ModuleImplBlocks, ImplSourceMap}, 14 impl_block::{ModuleImplBlocks, ImplSourceMap},
15 generics::{GenericParams, GenericDef}, 15 generics::{GenericParams, GenericDef},
16 type_ref::TypeRef, 16 type_ref::TypeRef,
17 traits::TraitData, Trait, ty::TraitRef
17}; 18};
18 19
19#[salsa::query_group(DefDatabaseStorage)] 20#[salsa::query_group(DefDatabaseStorage)]
20pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { 21pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> {
21 #[salsa::invoke(HirFileId::hir_parse)] 22 #[salsa::invoke(crate::ids::macro_def_query)]
23 fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>;
24
25 #[salsa::invoke(HirFileId::hir_parse_query)]
22 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; 26 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;
23 27
24 #[salsa::invoke(crate::adt::StructData::struct_data_query)] 28 #[salsa::invoke(crate::adt::StructData::struct_data_query)]
@@ -27,17 +31,23 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> {
27 #[salsa::invoke(crate::adt::EnumData::enum_data_query)] 31 #[salsa::invoke(crate::adt::EnumData::enum_data_query)]
28 fn enum_data(&self, e: Enum) -> Arc<EnumData>; 32 fn enum_data(&self, e: Enum) -> Arc<EnumData>;
29 33
30 #[salsa::invoke(crate::ids::SourceFileItems::file_items_query)] 34 #[salsa::invoke(crate::traits::TraitData::trait_data_query)]
31 fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>; 35 fn trait_data(&self, t: Trait) -> Arc<TraitData>;
36
37 #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)]
38 fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
32 39
33 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)] 40 #[salsa::invoke(crate::source_id::AstIdMap::file_item_query)]
34 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; 41 fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> TreeArc<SyntaxNode>;
35 42
36 #[salsa::invoke(RawItems::raw_items_query)] 43 #[salsa::invoke(RawItems::raw_items_query)]
37 fn raw_items(&self, file_id: FileId) -> Arc<RawItems>; 44 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
38 45
39 #[salsa::invoke(RawItems::raw_items_with_source_map_query)] 46 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
40 fn raw_items_with_source_map(&self, file_id: FileId) -> (Arc<RawItems>, Arc<ImportSourceMap>); 47 fn raw_items_with_source_map(
48 &self,
49 file_id: HirFileId,
50 ) -> (Arc<RawItems>, Arc<ImportSourceMap>);
41 51
42 #[salsa::invoke(CrateDefMap::crate_def_map_query)] 52 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
43 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>; 53 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
@@ -98,6 +108,9 @@ pub trait HirDatabase: DefDatabase {
98 108
99 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] 109 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
100 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; 110 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;
111
112 #[salsa::invoke(crate::ty::method_resolution::implements)]
113 fn implements(&self, trait_ref: TraitRef) -> bool;
101} 114}
102 115
103#[test] 116#[test]
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 c37fd0454..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());
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 18401f865..eb9939df7 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -1,16 +1,15 @@
1use std::{ 1use std::{
2 marker::PhantomData,
3 hash::{Hash, Hasher}, 2 hash::{Hash, Hasher},
4 sync::Arc, 3 sync::Arc,
5}; 4};
6 5
7use ra_db::{LocationInterner, FileId}; 6use ra_db::{LocationInterner, FileId};
8use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; 7use ra_syntax::{TreeArc, SourceFile, AstNode, ast};
9use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; 8use ra_arena::{RawId, ArenaId, impl_arena_id};
9use mbe::MacroRules;
10 10
11use crate::{ 11use crate::{
12 Module, 12 Module, DefDatabase, AstId, FileAstId,
13 DefDatabase,
14}; 13};
15 14
16#[derive(Debug, Default)] 15#[derive(Debug, Default)]
@@ -22,7 +21,7 @@ pub struct HirInterner {
22 consts: LocationInterner<ItemLoc<ast::ConstDef>, ConstId>, 21 consts: LocationInterner<ItemLoc<ast::ConstDef>, ConstId>,
23 statics: LocationInterner<ItemLoc<ast::StaticDef>, StaticId>, 22 statics: LocationInterner<ItemLoc<ast::StaticDef>, StaticId>,
24 traits: LocationInterner<ItemLoc<ast::TraitDef>, TraitId>, 23 traits: LocationInterner<ItemLoc<ast::TraitDef>, TraitId>,
25 types: LocationInterner<ItemLoc<ast::TypeAliasDef>, TypeId>, 24 types: LocationInterner<ItemLoc<ast::TypeAliasDef>, TypeAliasId>,
26} 25}
27 26
28impl HirInterner { 27impl HirInterner {
@@ -68,7 +67,7 @@ impl HirFileId {
68 HirFileIdRepr::File(file_id) => file_id, 67 HirFileIdRepr::File(file_id) => file_id,
69 HirFileIdRepr::Macro(macro_call_id) => { 68 HirFileIdRepr::Macro(macro_call_id) => {
70 let loc = macro_call_id.loc(db); 69 let loc = macro_call_id.loc(db);
71 loc.source_item_id.file_id.original_file(db) 70 loc.ast_id.file_id().original_file(db)
72 } 71 }
73 } 72 }
74 } 73 }
@@ -83,7 +82,10 @@ impl HirFileId {
83 } 82 }
84 } 83 }
85 84
86 pub(crate) fn hir_parse(db: &impl DefDatabase, file_id: HirFileId) -> TreeArc<SourceFile> { 85 pub(crate) fn hir_parse_query(
86 db: &impl DefDatabase,
87 file_id: HirFileId,
88 ) -> TreeArc<SourceFile> {
87 match file_id.0 { 89 match file_id.0 {
88 HirFileIdRepr::File(file_id) => db.parse(file_id), 90 HirFileIdRepr::File(file_id) => db.parse(file_id),
89 HirFileIdRepr::Macro(macro_call_id) => { 91 HirFileIdRepr::Macro(macro_call_id) => {
@@ -96,14 +98,10 @@ impl HirFileId {
96 98
97fn parse_macro(db: &impl DefDatabase, macro_call_id: MacroCallId) -> Option<TreeArc<SourceFile>> { 99fn parse_macro(db: &impl DefDatabase, macro_call_id: MacroCallId) -> Option<TreeArc<SourceFile>> {
98 let loc = macro_call_id.loc(db); 100 let loc = macro_call_id.loc(db);
99 let syntax = db.file_item(loc.source_item_id); 101 let macro_call = loc.ast_id.to_node(db);
100 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
101 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?; 102 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?;
102 103
103 let def_map = db.crate_def_map(loc.module.krate); 104 let macro_rules = db.macro_def(loc.def)?;
104 let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?;
105 let def_map = db.crate_def_map(krate);
106 let macro_rules = &def_map[macro_id];
107 let tt = macro_rules.expand(&macro_arg).ok()?; 105 let tt = macro_rules.expand(&macro_arg).ok()?;
108 Some(mbe::token_tree_to_ast_item_list(&tt)) 106 Some(mbe::token_tree_to_ast_item_list(&tt))
109} 107}
@@ -126,6 +124,17 @@ impl From<MacroCallId> for HirFileId {
126 } 124 }
127} 125}
128 126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
128pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>);
129
130pub(crate) fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
131 let macro_call = id.0.to_node(db);
132 let arg = macro_call.token_tree()?;
133 let (tt, _) = mbe::ast_to_token_tree(arg)?;
134 let rules = MacroRules::parse(&tt).ok()?;
135 Some(Arc::new(rules))
136}
137
129/// `MacroCallId` identifies a particular macro invocation, like 138/// `MacroCallId` identifies a particular macro invocation, like
130/// `println!("Hello, {}", world)`. 139/// `println!("Hello, {}", world)`.
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -134,8 +143,8 @@ impl_arena_id!(MacroCallId);
134 143
135#[derive(Debug, Clone, PartialEq, Eq, Hash)] 144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
136pub struct MacroCallLoc { 145pub struct MacroCallLoc {
137 pub(crate) module: Module, 146 pub(crate) def: MacroDefId,
138 pub(crate) source_item_id: SourceItemId, 147 pub(crate) ast_id: AstId<ast::MacroCall>,
139} 148}
140 149
141impl MacroCallId { 150impl MacroCallId {
@@ -145,7 +154,6 @@ impl MacroCallId {
145} 154}
146 155
147impl MacroCallLoc { 156impl MacroCallLoc {
148 #[allow(unused)]
149 pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> MacroCallId { 157 pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> MacroCallId {
150 db.as_ref().macros.loc2id(&self) 158 db.as_ref().macros.loc2id(&self)
151 } 159 }
@@ -154,26 +162,25 @@ impl MacroCallLoc {
154#[derive(Debug)] 162#[derive(Debug)]
155pub struct ItemLoc<N: AstNode> { 163pub struct ItemLoc<N: AstNode> {
156 pub(crate) module: Module, 164 pub(crate) module: Module,
157 raw: SourceItemId, 165 ast_id: AstId<N>,
158 _ty: PhantomData<N>,
159} 166}
160 167
161impl<N: AstNode> PartialEq for ItemLoc<N> { 168impl<N: AstNode> PartialEq for ItemLoc<N> {
162 fn eq(&self, other: &Self) -> bool { 169 fn eq(&self, other: &Self) -> bool {
163 self.module == other.module && self.raw == other.raw 170 self.module == other.module && self.ast_id == other.ast_id
164 } 171 }
165} 172}
166impl<N: AstNode> Eq for ItemLoc<N> {} 173impl<N: AstNode> Eq for ItemLoc<N> {}
167impl<N: AstNode> Hash for ItemLoc<N> { 174impl<N: AstNode> Hash for ItemLoc<N> {
168 fn hash<H: Hasher>(&self, hasher: &mut H) { 175 fn hash<H: Hasher>(&self, hasher: &mut H) {
169 self.module.hash(hasher); 176 self.module.hash(hasher);
170 self.raw.hash(hasher); 177 self.ast_id.hash(hasher);
171 } 178 }
172} 179}
173 180
174impl<N: AstNode> Clone for ItemLoc<N> { 181impl<N: AstNode> Clone for ItemLoc<N> {
175 fn clone(&self) -> ItemLoc<N> { 182 fn clone(&self) -> ItemLoc<N> {
176 ItemLoc { module: self.module, raw: self.raw, _ty: PhantomData } 183 ItemLoc { module: self.module, ast_id: self.ast_id }
177 } 184 }
178} 185}
179 186
@@ -200,26 +207,19 @@ impl<'a, DB: DefDatabase> LocationCtx<&'a DB> {
200pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone { 207pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
201 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<N>, Self>; 208 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<N>, Self>;
202 fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self { 209 fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self {
203 let items = ctx.db.file_items(ctx.file_id); 210 let items = ctx.db.ast_id_map(ctx.file_id);
204 let item_id = items.id_of(ctx.file_id, ast.syntax()); 211 let item_id = items.ast_id(ast);
205 Self::from_source_item_id_unchecked(ctx, item_id) 212 Self::from_ast_id(ctx, item_id)
206 } 213 }
207 fn from_source_item_id_unchecked( 214 fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self {
208 ctx: LocationCtx<&impl DefDatabase>, 215 let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) };
209 item_id: SourceFileItemId,
210 ) -> Self {
211 let raw = SourceItemId { file_id: ctx.file_id, item_id };
212 let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData };
213
214 Self::interner(ctx.db.as_ref()).loc2id(&loc) 216 Self::interner(ctx.db.as_ref()).loc2id(&loc)
215 } 217 }
216 fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) { 218 fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) {
217 let int = Self::interner(db.as_ref()); 219 let int = Self::interner(db.as_ref());
218 let loc = int.id2loc(self); 220 let loc = int.id2loc(self);
219 let syntax = db.file_item(loc.raw); 221 let ast = loc.ast_id.to_node(db);
220 let ast = 222 (loc.ast_id.file_id(), ast)
221 N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned();
222 (loc.raw.file_id, ast)
223 } 223 }
224 fn module(self, db: &impl DefDatabase) -> Module { 224 fn module(self, db: &impl DefDatabase) -> Module {
225 let int = Self::interner(db.as_ref()); 225 let int = Self::interner(db.as_ref());
@@ -229,7 +229,7 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
229} 229}
230 230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
232pub struct FunctionId(RawId); 232pub(crate) struct FunctionId(RawId);
233impl_arena_id!(FunctionId); 233impl_arena_id!(FunctionId);
234impl AstItemDef<ast::FnDef> for FunctionId { 234impl AstItemDef<ast::FnDef> for FunctionId {
235 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::FnDef>, Self> { 235 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::FnDef>, Self> {
@@ -238,7 +238,7 @@ impl AstItemDef<ast::FnDef> for FunctionId {
238} 238}
239 239
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
241pub struct StructId(RawId); 241pub(crate) struct StructId(RawId);
242impl_arena_id!(StructId); 242impl_arena_id!(StructId);
243impl AstItemDef<ast::StructDef> for StructId { 243impl AstItemDef<ast::StructDef> for StructId {
244 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StructDef>, Self> { 244 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StructDef>, Self> {
@@ -247,7 +247,7 @@ impl AstItemDef<ast::StructDef> for StructId {
247} 247}
248 248
249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
250pub struct EnumId(RawId); 250pub(crate) struct EnumId(RawId);
251impl_arena_id!(EnumId); 251impl_arena_id!(EnumId);
252impl AstItemDef<ast::EnumDef> for EnumId { 252impl AstItemDef<ast::EnumDef> for EnumId {
253 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::EnumDef>, Self> { 253 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::EnumDef>, Self> {
@@ -256,7 +256,7 @@ impl AstItemDef<ast::EnumDef> for EnumId {
256} 256}
257 257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
259pub struct ConstId(RawId); 259pub(crate) struct ConstId(RawId);
260impl_arena_id!(ConstId); 260impl_arena_id!(ConstId);
261impl AstItemDef<ast::ConstDef> for ConstId { 261impl AstItemDef<ast::ConstDef> for ConstId {
262 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::ConstDef>, Self> { 262 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::ConstDef>, Self> {
@@ -265,7 +265,7 @@ impl AstItemDef<ast::ConstDef> for ConstId {
265} 265}
266 266
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
268pub struct StaticId(RawId); 268pub(crate) struct StaticId(RawId);
269impl_arena_id!(StaticId); 269impl_arena_id!(StaticId);
270impl AstItemDef<ast::StaticDef> for StaticId { 270impl AstItemDef<ast::StaticDef> for StaticId {
271 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StaticDef>, Self> { 271 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StaticDef>, Self> {
@@ -274,7 +274,7 @@ impl AstItemDef<ast::StaticDef> for StaticId {
274} 274}
275 275
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
277pub struct TraitId(RawId); 277pub(crate) struct TraitId(RawId);
278impl_arena_id!(TraitId); 278impl_arena_id!(TraitId);
279impl AstItemDef<ast::TraitDef> for TraitId { 279impl AstItemDef<ast::TraitDef> for TraitId {
280 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TraitDef>, Self> { 280 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TraitDef>, Self> {
@@ -283,117 +283,10 @@ impl AstItemDef<ast::TraitDef> for TraitId {
283} 283}
284 284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
286pub struct TypeId(RawId); 286pub(crate) struct TypeAliasId(RawId);
287impl_arena_id!(TypeId); 287impl_arena_id!(TypeAliasId);
288impl AstItemDef<ast::TypeAliasDef> for TypeId { 288impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
289 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TypeAliasDef>, Self> { 289 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TypeAliasDef>, Self> {
290 &interner.types 290 &interner.types
291 } 291 }
292} 292}
293
294/// Identifier of item within a specific file. This is stable over reparses, so
295/// it's OK to use it as a salsa key/value.
296#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
297pub struct SourceFileItemId(RawId);
298impl_arena_id!(SourceFileItemId);
299
300impl SourceFileItemId {
301 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
302 SourceItemId { file_id, item_id: self }
303 }
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
307pub struct SourceItemId {
308 pub(crate) file_id: HirFileId,
309 pub(crate) item_id: SourceFileItemId,
310}
311
312/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back.
313#[derive(Debug, PartialEq, Eq)]
314pub struct SourceFileItems {
315 file_id: HirFileId,
316 arena: Arena<SourceFileItemId, SyntaxNodePtr>,
317}
318
319impl SourceFileItems {
320 pub(crate) fn file_items_query(
321 db: &impl DefDatabase,
322 file_id: HirFileId,
323 ) -> Arc<SourceFileItems> {
324 let source_file = db.hir_parse(file_id);
325 Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
326 }
327
328 pub(crate) fn file_item_query(
329 db: &impl DefDatabase,
330 source_item_id: SourceItemId,
331 ) -> TreeArc<SyntaxNode> {
332 let source_file = db.hir_parse(source_item_id.file_id);
333 db.file_items(source_item_id.file_id)[source_item_id.item_id]
334 .to_node(&source_file)
335 .to_owned()
336 }
337
338 pub(crate) fn from_source_file(
339 source_file: &SourceFile,
340 file_id: HirFileId,
341 ) -> SourceFileItems {
342 let mut res = SourceFileItems { file_id, arena: Arena::default() };
343 // By walking the tree in bread-first order we make sure that parents
344 // get lower ids then children. That is, adding a new child does not
345 // change parent's id. This means that, say, adding a new function to a
346 // trait does not change ids of top-level items, which helps caching.
347 bfs(source_file.syntax(), |it| {
348 if let Some(module_item) = ast::ModuleItem::cast(it) {
349 res.alloc(module_item.syntax());
350 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
351 res.alloc(macro_call.syntax());
352 }
353 });
354 res
355 }
356
357 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
358 self.arena.alloc(SyntaxNodePtr::new(item))
359 }
360 pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId {
361 assert_eq!(
362 self.file_id, file_id,
363 "SourceFileItems: wrong file, expected {:?}, got {:?}",
364 self.file_id, file_id
365 );
366 self.id_of_unchecked(item)
367 }
368 pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId {
369 let ptr = SyntaxNodePtr::new(item);
370 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) {
371 return id;
372 }
373 panic!(
374 "Can't find {:?} in SourceFileItems:\n{:?}",
375 item,
376 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
377 );
378 }
379}
380
381impl std::ops::Index<SourceFileItemId> for SourceFileItems {
382 type Output = SyntaxNodePtr;
383 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
384 &self.arena[idx]
385 }
386}
387
388/// Walks the subtree in bfs order, calling `f` for each node.
389fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
390 let mut curr_layer = vec![node];
391 let mut next_layer = vec![];
392 while !curr_layer.is_empty() {
393 curr_layer.drain(..).for_each(|node| {
394 next_layer.extend(node.children());
395 f(node);
396 });
397 std::mem::swap(&mut curr_layer, &mut next_layer);
398 }
399}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index a89c916f8..7c603bbd3 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -23,10 +23,12 @@ pub mod mock;
23mod path; 23mod path;
24pub mod source_binder; 24pub mod source_binder;
25 25
26mod source_id;
26mod ids; 27mod ids;
27mod name; 28mod name;
28mod nameres; 29mod nameres;
29mod adt; 30mod adt;
31mod traits;
30mod type_alias; 32mod type_alias;
31mod type_ref; 33mod type_ref;
32mod ty; 34mod ty;
@@ -35,6 +37,7 @@ mod expr;
35mod generics; 37mod generics;
36mod docs; 38mod docs;
37mod resolve; 39mod resolve;
40pub mod diagnostics;
38 41
39mod code_model_api; 42mod code_model_api;
40mod code_model_impl; 43mod code_model_impl;
@@ -45,13 +48,14 @@ mod marks;
45use crate::{ 48use crate::{
46 db::{HirDatabase, DefDatabase}, 49 db::{HirDatabase, DefDatabase},
47 name::{AsName, KnownName}, 50 name::{AsName, KnownName},
48 ids::{SourceItemId, SourceFileItems}, 51 source_id::{FileAstId, AstId},
49}; 52};
50 53
51pub use self::{ 54pub use self::{
52 path::{Path, PathKind}, 55 path::{Path, PathKind},
53 name::Name, 56 name::Name,
54 ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, 57 source_id::{AstIdMap, ErasedFileAstId},
58 ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner},
55 nameres::{PerNs, Namespace}, 59 nameres::{PerNs, Namespace},
56 ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, 60 ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay},
57 impl_block::{ImplBlock, ImplItem}, 61 impl_block::{ImplBlock, ImplItem},
@@ -63,7 +67,7 @@ pub use self::{
63 67
64pub use self::code_model_api::{ 68pub use self::code_model_api::{
65 Crate, CrateDependency, 69 Crate, CrateDependency,
66 Module, ModuleDef, ModuleSource, Problem, 70 Module, ModuleDef, ModuleSource,
67 Struct, Enum, EnumVariant, 71 Struct, Enum, EnumVariant,
68 Function, FnSignature, 72 Function, FnSignature,
69 StructField, FieldSource, 73 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 5ac878c79..8adc6d368 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -59,12 +59,16 @@ use rustc_hash::FxHashMap;
59use ra_arena::{Arena, RawId, impl_arena_id}; 59use ra_arena::{Arena, RawId, impl_arena_id};
60use ra_db::{FileId, Edition}; 60use ra_db::{FileId, Edition};
61use test_utils::tested_by; 61use test_utils::tested_by;
62use ra_syntax::ast;
62use ra_prof::profile; 63use ra_prof::profile;
63 64
64use crate::{ 65use crate::{
65 ModuleDef, Name, Crate, Module, Problem, 66 ModuleDef, Name, Crate, Module,
66 DefDatabase, Path, PathKind, HirFileId, 67 DefDatabase, Path, PathKind, HirFileId, Trait,
67 ids::{SourceItemId, SourceFileItemId, MacroCallId}, 68 ids::MacroDefId,
69 diagnostics::DiagnosticSink,
70 nameres::diagnostics::DefDiagnostic,
71 AstId,
68}; 72};
69 73
70pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; 74pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap};
@@ -83,10 +87,8 @@ pub struct CrateDefMap {
83 extern_prelude: FxHashMap<Name, ModuleDef>, 87 extern_prelude: FxHashMap<Name, ModuleDef>,
84 root: CrateModuleId, 88 root: CrateModuleId,
85 modules: Arena<CrateModuleId, ModuleData>, 89 modules: Arena<CrateModuleId, ModuleData>,
86 macros: Arena<CrateMacroId, mbe::MacroRules>, 90 public_macros: FxHashMap<Name, MacroDefId>,
87 public_macros: FxHashMap<Name, CrateMacroId>, 91 diagnostics: Vec<DefDiagnostic>,
88 macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>,
89 problems: CrateDefMapProblems,
90} 92}
91 93
92impl std::ops::Index<CrateModuleId> for CrateDefMap { 94impl std::ops::Index<CrateModuleId> for CrateDefMap {
@@ -96,18 +98,6 @@ impl std::ops::Index<CrateModuleId> for CrateDefMap {
96 } 98 }
97} 99}
98 100
99impl std::ops::Index<CrateMacroId> for CrateDefMap {
100 type Output = mbe::MacroRules;
101 fn index(&self, id: CrateMacroId) -> &mbe::MacroRules {
102 &self.macros[id]
103 }
104}
105
106/// An ID of a macro, **local** to a specific crate
107#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
108pub(crate) struct CrateMacroId(RawId);
109impl_arena_id!(CrateMacroId);
110
111/// An ID of a module, **local** to a specific crate 101/// An ID of a module, **local** to a specific crate
112#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 102#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
113pub(crate) struct CrateModuleId(RawId); 103pub(crate) struct CrateModuleId(RawId);
@@ -119,28 +109,13 @@ pub(crate) struct ModuleData {
119 pub(crate) children: FxHashMap<Name, CrateModuleId>, 109 pub(crate) children: FxHashMap<Name, CrateModuleId>,
120 pub(crate) scope: ModuleScope, 110 pub(crate) scope: ModuleScope,
121 /// None for root 111 /// None for root
122 pub(crate) declaration: Option<SourceItemId>, 112 pub(crate) declaration: Option<AstId<ast::Module>>,
123 /// None for inline modules. 113 /// None for inline modules.
124 /// 114 ///
125 /// Note that non-inline modules, by definition, live inside non-macro file. 115 /// Note that non-inline modules, by definition, live inside non-macro file.
126 pub(crate) definition: Option<FileId>, 116 pub(crate) definition: Option<FileId>,
127} 117}
128 118
129#[derive(Default, Debug, PartialEq, Eq)]
130pub(crate) struct CrateDefMapProblems {
131 problems: Vec<(SourceItemId, Problem)>,
132}
133
134impl CrateDefMapProblems {
135 fn add(&mut self, source_item_id: SourceItemId, problem: Problem) {
136 self.problems.push((source_item_id, problem))
137 }
138
139 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a {
140 self.problems.iter().map(|(s, p)| (s, p))
141 }
142}
143
144#[derive(Debug, Default, PartialEq, Eq, Clone)] 119#[derive(Debug, Default, PartialEq, Eq, Clone)]
145pub struct ModuleScope { 120pub struct ModuleScope {
146 items: FxHashMap<Name, Resolution>, 121 items: FxHashMap<Name, Resolution>,
@@ -153,6 +128,12 @@ impl ModuleScope {
153 pub fn get(&self, name: &Name) -> Option<&Resolution> { 128 pub fn get(&self, name: &Name) -> Option<&Resolution> {
154 self.items.get(name) 129 self.items.get(name)
155 } 130 }
131 pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
132 self.items.values().filter_map(|r| match r.def.take_types() {
133 Some(ModuleDef::Trait(t)) => Some(t),
134 _ => None,
135 })
136 }
156} 137}
157 138
158#[derive(Debug, Clone, PartialEq, Eq, Default)] 139#[derive(Debug, Clone, PartialEq, Eq, Default)]
@@ -210,10 +191,8 @@ impl CrateDefMap {
210 prelude: None, 191 prelude: None,
211 root, 192 root,
212 modules, 193 modules,
213 macros: Arena::default(),
214 public_macros: FxHashMap::default(), 194 public_macros: FxHashMap::default(),
215 macro_resolutions: FxHashMap::default(), 195 diagnostics: Vec::new(),
216 problems: CrateDefMapProblems::default(),
217 } 196 }
218 }; 197 };
219 let def_map = collector::collect_defs(db, def_map); 198 let def_map = collector::collect_defs(db, def_map);
@@ -224,10 +203,6 @@ impl CrateDefMap {
224 self.root 203 self.root
225 } 204 }
226 205
227 pub(crate) fn problems(&self) -> &CrateDefMapProblems {
228 &self.problems
229 }
230
231 pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module { 206 pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module {
232 Module { krate: self.krate, module_id } 207 Module { krate: self.krate, module_id }
233 } 208 }
@@ -240,19 +215,20 @@ impl CrateDefMap {
240 &self.extern_prelude 215 &self.extern_prelude
241 } 216 }
242 217
243 pub(crate) fn resolve_macro( 218 pub(crate) fn add_diagnostics(
244 &self, 219 &self,
245 macro_call_id: MacroCallId, 220 db: &impl DefDatabase,
246 ) -> Option<(Crate, CrateMacroId)> { 221 module: CrateModuleId,
247 self.macro_resolutions.get(&macro_call_id).map(|&it| it) 222 sink: &mut DiagnosticSink,
223 ) {
224 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
248 } 225 }
249 226
250 pub(crate) fn find_module_by_source( 227 pub(crate) fn find_module_by_source(
251 &self, 228 &self,
252 file_id: HirFileId, 229 file_id: HirFileId,
253 decl_id: Option<SourceFileItemId>, 230 decl_id: Option<AstId<ast::Module>>,
254 ) -> Option<CrateModuleId> { 231 ) -> Option<CrateModuleId> {
255 let decl_id = decl_id.map(|it| it.with_file_id(file_id));
256 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { 232 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
257 if decl_id.is_some() { 233 if decl_id.is_some() {
258 module_data.declaration == decl_id 234 module_data.declaration == decl_id
@@ -452,3 +428,46 @@ impl CrateDefMap {
452 } 428 }
453 } 429 }
454} 430}
431
432mod diagnostics {
433 use relative_path::RelativePathBuf;
434 use ra_syntax::{AstPtr, ast};
435
436 use crate::{
437 AstId, DefDatabase,
438 nameres::CrateModuleId,
439 diagnostics::{DiagnosticSink, UnresolvedModule},
440};
441
442 #[derive(Debug, PartialEq, Eq)]
443 pub(super) enum DefDiagnostic {
444 UnresolvedModule {
445 module: CrateModuleId,
446 declaration: AstId<ast::Module>,
447 candidate: RelativePathBuf,
448 },
449 }
450
451 impl DefDiagnostic {
452 pub(super) fn add_to(
453 &self,
454 db: &impl DefDatabase,
455 target_module: CrateModuleId,
456 sink: &mut DiagnosticSink,
457 ) {
458 match self {
459 DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
460 if *module != target_module {
461 return;
462 }
463 let decl = declaration.to_node(db);
464 sink.push(UnresolvedModule {
465 file: declaration.file_id(),
466 decl: AstPtr::new(&decl),
467 candidate: candidate.clone(),
468 })
469 }
470 }
471 }
472 }
473}
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index c5b73cfbe..39cadc94a 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -3,17 +3,22 @@ use rustc_hash::FxHashMap;
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use test_utils::tested_by; 4use test_utils::tested_by;
5use ra_db::FileId; 5use ra_db::FileId;
6use ra_syntax::ast;
6 7
7use crate::{ 8use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 9 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 DefDatabase, HirFileId, Name, Path, Problem, Crate, 10 DefDatabase, HirFileId, Name, Path,
10 KnownName, 11 KnownName,
11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw}, 12 nameres::{
12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, 13 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
14 CrateDefMap, CrateModuleId, ModuleData,
15 diagnostics::DefDiagnostic,
16 raw,
17 },
18 ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId},
19 AstId,
13}; 20};
14 21
15use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId};
16
17pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 22pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
18 // populate external prelude 23 // populate external prelude
19 for dep in def_map.krate.dependencies(db) { 24 for dep in def_map.krate.dependencies(db) {
@@ -48,8 +53,8 @@ struct DefCollector<DB> {
48 def_map: CrateDefMap, 53 def_map: CrateDefMap,
49 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 54 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
50 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 55 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
51 unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>, 56 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>,
52 global_macro_scope: FxHashMap<Name, CrateMacroId>, 57 global_macro_scope: FxHashMap<Name, MacroDefId>,
53} 58}
54 59
55impl<'a, DB> DefCollector<&'a DB> 60impl<'a, DB> DefCollector<&'a DB>
@@ -59,7 +64,7 @@ where
59 fn collect(&mut self) { 64 fn collect(&mut self) {
60 let crate_graph = self.db.crate_graph(); 65 let crate_graph = self.db.crate_graph();
61 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id()); 66 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
62 let raw_items = self.db.raw_items(file_id); 67 let raw_items = self.db.raw_items(file_id.into());
63 let module_id = self.def_map.root; 68 let module_id = self.def_map.root;
64 self.def_map.modules[module_id].definition = Some(file_id); 69 self.def_map.modules[module_id].definition = Some(file_id);
65 ModCollector { 70 ModCollector {
@@ -90,14 +95,11 @@ where
90 } 95 }
91 } 96 }
92 97
93 fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) { 98 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) {
94 if let Ok(rules) = mbe::MacroRules::parse(tt) { 99 if export {
95 let macro_id = self.def_map.macros.alloc(rules); 100 self.def_map.public_macros.insert(name.clone(), macro_id);
96 if export {
97 self.def_map.public_macros.insert(name.clone(), macro_id);
98 }
99 self.global_macro_scope.insert(name, macro_id);
100 } 101 }
102 self.global_macro_scope.insert(name, macro_id);
101 } 103 }
102 104
103 fn resolve_imports(&mut self) -> ReachedFixedPoint { 105 fn resolve_imports(&mut self) -> ReachedFixedPoint {
@@ -293,7 +295,7 @@ where
293 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 295 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
294 let mut resolved = Vec::new(); 296 let mut resolved = Vec::new();
295 let mut res = ReachedFixedPoint::Yes; 297 let mut res = ReachedFixedPoint::Yes;
296 macros.retain(|(module_id, call_id, path, tt)| { 298 macros.retain(|(module_id, ast_id, path)| {
297 if path.segments.len() != 2 { 299 if path.segments.len() != 2 {
298 return true; 300 return true;
299 } 301 }
@@ -309,47 +311,23 @@ where
309 res = ReachedFixedPoint::No; 311 res = ReachedFixedPoint::No;
310 let def_map = self.db.crate_def_map(krate); 312 let def_map = self.db.crate_def_map(krate);
311 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() { 313 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() {
312 resolved.push((*module_id, *call_id, (krate, macro_id), tt.clone())); 314 let call_id = MacroCallLoc { def: macro_id, ast_id: *ast_id }.id(self.db);
315 resolved.push((*module_id, call_id));
313 } 316 }
314 false 317 false
315 }); 318 });
316 319
317 for (module_id, macro_call_id, macro_def_id, arg) in resolved { 320 for (module_id, macro_call_id) in resolved {
318 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id, arg); 321 self.collect_macro_expansion(module_id, macro_call_id);
319 } 322 }
320 res 323 res
321 } 324 }
322 325
323 fn collect_macro_expansion( 326 fn collect_macro_expansion(&mut self, module_id: CrateModuleId, macro_call_id: MacroCallId) {
324 &mut self, 327 let file_id: HirFileId = macro_call_id.into();
325 module_id: CrateModuleId, 328 let raw_items = self.db.raw_items(file_id);
326 macro_call_id: MacroCallId, 329 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
327 macro_def_id: (Crate, CrateMacroId), 330 .collect(raw_items.items())
328 macro_arg: tt::Subtree,
329 ) {
330 let (macro_krate, macro_id) = macro_def_id;
331 let dm;
332 let rules = if macro_krate == self.def_map.krate {
333 &self.def_map[macro_id]
334 } else {
335 dm = self.db.crate_def_map(macro_krate);
336 &dm[macro_id]
337 };
338 if let Ok(expansion) = rules.expand(&macro_arg) {
339 self.def_map.macro_resolutions.insert(macro_call_id, macro_def_id);
340 // XXX: this **does not** go through a database, because we can't
341 // identify macro_call without adding the whole state of name resolution
342 // as a parameter to the query.
343 //
344 // So, we run the queries "manually" and we must ensure that
345 // `db.hir_parse(macro_call_id)` returns the same source_file.
346 let file_id: HirFileId = macro_call_id.into();
347 let source_file = mbe::token_tree_to_ast_item_list(&expansion);
348
349 let raw_items = raw::RawItems::from_source_file(&source_file, file_id);
350 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
351 .collect(raw_items.items())
352 }
353 } 331 }
354 332
355 fn finish(self) -> CrateDefMap { 333 fn finish(self) -> CrateDefMap {
@@ -387,12 +365,9 @@ where
387 fn collect_module(&mut self, module: &raw::ModuleData) { 365 fn collect_module(&mut self, module: &raw::ModuleData) {
388 match module { 366 match module {
389 // inline module, just recurse 367 // inline module, just recurse
390 raw::ModuleData::Definition { name, items, source_item_id } => { 368 raw::ModuleData::Definition { name, items, ast_id } => {
391 let module_id = self.push_child_module( 369 let module_id =
392 name.clone(), 370 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None);
393 source_item_id.with_file_id(self.file_id),
394 None,
395 );
396 ModCollector { 371 ModCollector {
397 def_collector: &mut *self.def_collector, 372 def_collector: &mut *self.def_collector,
398 module_id, 373 module_id,
@@ -402,28 +377,29 @@ where
402 .collect(&*items); 377 .collect(&*items);
403 } 378 }
404 // out of line module, resovle, parse and recurse 379 // out of line module, resovle, parse and recurse
405 raw::ModuleData::Declaration { name, source_item_id } => { 380 raw::ModuleData::Declaration { name, ast_id } => {
406 let source_item_id = source_item_id.with_file_id(self.file_id); 381 let ast_id = ast_id.with_file_id(self.file_id);
407 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 382 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
408 let (file_ids, problem) = 383 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); 384 Ok(file_id) => {
410 385 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
411 if let Some(problem) = problem { 386 let raw_items = self.def_collector.db.raw_items(file_id.into());
412 self.def_collector.def_map.problems.add(source_item_id, problem) 387 ModCollector {
413 } 388 def_collector: &mut *self.def_collector,
414 389 module_id,
415 if let Some(&file_id) = file_ids.first() { 390 file_id: file_id.into(),
416 let module_id = 391 raw_items: &raw_items,
417 self.push_child_module(name.clone(), source_item_id, Some(file_id)); 392 }
418 let raw_items = self.def_collector.db.raw_items(file_id); 393 .collect(raw_items.items())
419 ModCollector {
420 def_collector: &mut *self.def_collector,
421 module_id,
422 file_id: file_id.into(),
423 raw_items: &raw_items,
424 } 394 }
425 .collect(raw_items.items()) 395 Err(candidate) => self.def_collector.def_map.diagnostics.push(
426 } 396 DefDiagnostic::UnresolvedModule {
397 module: self.module_id,
398 declaration: ast_id,
399 candidate,
400 },
401 ),
402 };
427 } 403 }
428 } 404 }
429 } 405 }
@@ -431,7 +407,7 @@ where
431 fn push_child_module( 407 fn push_child_module(
432 &mut self, 408 &mut self,
433 name: Name, 409 name: Name,
434 declaration: SourceItemId, 410 declaration: AstId<ast::Module>,
435 definition: Option<FileId>, 411 definition: Option<FileId>,
436 ) -> CrateModuleId { 412 ) -> CrateModuleId {
437 let modules = &mut self.def_collector.def_map.modules; 413 let modules = &mut self.def_collector.def_map.modules;
@@ -453,23 +429,24 @@ where
453 fn define_def(&mut self, def: &raw::DefData) { 429 fn define_def(&mut self, def: &raw::DefData) {
454 let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id }; 430 let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id };
455 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into()); 431 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into());
456 macro_rules! id { 432
457 () => { 433 macro_rules! def {
458 AstItemDef::from_source_item_id_unchecked(ctx, def.source_item_id) 434 ($kind:ident, $ast_id:ident) => {
435 $kind { id: AstItemDef::from_ast_id(ctx, $ast_id) }.into()
459 }; 436 };
460 } 437 }
461 let name = def.name.clone(); 438 let name = def.name.clone();
462 let def: PerNs<ModuleDef> = match def.kind { 439 let def: PerNs<ModuleDef> = match def.kind {
463 raw::DefKind::Function => PerNs::values(Function { id: id!() }.into()), 440 raw::DefKind::Function(ast_id) => PerNs::values(def!(Function, ast_id)),
464 raw::DefKind::Struct => { 441 raw::DefKind::Struct(ast_id) => {
465 let s = Struct { id: id!() }.into(); 442 let s = def!(Struct, ast_id);
466 PerNs::both(s, s) 443 PerNs::both(s, s)
467 } 444 }
468 raw::DefKind::Enum => PerNs::types(Enum { id: id!() }.into()), 445 raw::DefKind::Enum(ast_id) => PerNs::types(def!(Enum, ast_id)),
469 raw::DefKind::Const => PerNs::values(Const { id: id!() }.into()), 446 raw::DefKind::Const(ast_id) => PerNs::values(def!(Const, ast_id)),
470 raw::DefKind::Static => PerNs::values(Static { id: id!() }.into()), 447 raw::DefKind::Static(ast_id) => PerNs::values(def!(Static, ast_id)),
471 raw::DefKind::Trait => PerNs::types(Trait { id: id!() }.into()), 448 raw::DefKind::Trait(ast_id) => PerNs::types(def!(Trait, ast_id)),
472 raw::DefKind::TypeAlias => PerNs::types(TypeAlias { id: id!() }.into()), 449 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)),
473 }; 450 };
474 let resolution = Resolution { def, import: None }; 451 let resolution = Resolution { def, import: None };
475 self.def_collector.update(self.module_id, None, &[(name, resolution)]) 452 self.def_collector.update(self.module_id, None, &[(name, resolution)])
@@ -479,39 +456,27 @@ where
479 // Case 1: macro rules, define a macro in crate-global mutable scope 456 // Case 1: macro rules, define a macro in crate-global mutable scope
480 if is_macro_rules(&mac.path) { 457 if is_macro_rules(&mac.path) {
481 if let Some(name) = &mac.name { 458 if let Some(name) = &mac.name {
482 self.def_collector.define_macro(name.clone(), &mac.arg, mac.export) 459 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id));
460 self.def_collector.define_macro(name.clone(), macro_id, mac.export)
483 } 461 }
484 return; 462 return;
485 } 463 }
486 464
487 let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id }; 465 let ast_id = mac.ast_id.with_file_id(self.file_id);
488 let macro_call_id = MacroCallLoc {
489 module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id },
490 source_item_id,
491 }
492 .id(self.def_collector.db);
493 466
494 // Case 2: try to expand macro_rules from this crate, triggering 467 // Case 2: try to expand macro_rules from this crate, triggering
495 // recursive item collection. 468 // recursive item collection.
496 if let Some(&macro_id) = 469 if let Some(&macro_id) =
497 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name)) 470 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name))
498 { 471 {
499 self.def_collector.collect_macro_expansion( 472 let macro_call_id = MacroCallLoc { def: macro_id, ast_id }.id(self.def_collector.db);
500 self.module_id, 473
501 macro_call_id, 474 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id);
502 (self.def_collector.def_map.krate, macro_id),
503 mac.arg.clone(),
504 );
505 return; 475 return;
506 } 476 }
507 477
508 // Case 3: path to a macro from another crate, expand during name resolution 478 // Case 3: path to a macro from another crate, expand during name resolution
509 self.def_collector.unexpanded_macros.push(( 479 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone()))
510 self.module_id,
511 macro_call_id,
512 mac.path.clone(),
513 mac.arg.clone(),
514 ))
515 } 480 }
516} 481}
517 482
@@ -524,7 +489,7 @@ fn resolve_submodule(
524 file_id: HirFileId, 489 file_id: HirFileId,
525 name: &Name, 490 name: &Name,
526 is_root: bool, 491 is_root: bool,
527) -> (Vec<FileId>, Option<Problem>) { 492) -> Result<FileId, RelativePathBuf> {
528 // FIXME: handle submodules of inline modules properly 493 // FIXME: handle submodules of inline modules properly
529 let file_id = file_id.original_file(db); 494 let file_id = file_id.original_file(db);
530 let source_root_id = db.file_source_root(file_id); 495 let source_root_id = db.file_source_root(file_id);
@@ -545,17 +510,10 @@ fn resolve_submodule(
545 candidates.push(file_dir_mod.clone()); 510 candidates.push(file_dir_mod.clone());
546 }; 511 };
547 let sr = db.source_root(source_root_id); 512 let sr = db.source_root(source_root_id);
548 let points_to = candidates 513 let mut points_to = candidates.into_iter().filter_map(|path| sr.files.get(&path)).map(|&it| it);
549 .into_iter() 514 // FIXME: handle ambiguity
550 .filter_map(|path| sr.files.get(&path)) 515 match points_to.next() {
551 .map(|&it| it) 516 Some(file_id) => Ok(file_id),
552 .collect::<Vec<_>>(); 517 None => Err(if is_dir_owner { file_mod } else { file_dir_mod }),
553 let problem = if points_to.is_empty() { 518 }
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} 519}
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index f8ba398ec..0936229ac 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -4,7 +4,6 @@ use std::{
4}; 4};
5 5
6use test_utils::tested_by; 6use test_utils::tested_by;
7use ra_db::FileId;
8use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap}; 7use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
9use ra_syntax::{ 8use ra_syntax::{
10 AstNode, SourceFile, AstPtr, TreeArc, 9 AstNode, SourceFile, AstPtr, TreeArc,
@@ -13,9 +12,13 @@ use ra_syntax::{
13 12
14use crate::{ 13use crate::{
15 DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, 14 DefDatabase, Name, AsName, Path, HirFileId, ModuleSource,
16 ids::{SourceFileItemId, SourceFileItems}, 15 AstIdMap, FileAstId,
17}; 16};
18 17
18/// `RawItems` is a set of top-level items in a file (except for impls).
19///
20/// It is the input to name resolution algorithm. `RawItems` are not invalidated
21/// on most edits.
19#[derive(Debug, Default, PartialEq, Eq)] 22#[derive(Debug, Default, PartialEq, Eq)]
20pub struct RawItems { 23pub struct RawItems {
21 modules: Arena<Module, ModuleData>, 24 modules: Arena<Module, ModuleData>,
@@ -32,11 +35,11 @@ pub struct ImportSourceMap {
32} 35}
33 36
34impl ImportSourceMap { 37impl ImportSourceMap {
35 pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { 38 fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
36 self.map.insert(import, AstPtr::new(segment)) 39 self.map.insert(import, AstPtr::new(segment))
37 } 40 }
38 41
39 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { 42 pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
40 let file = match source { 43 let file = match source {
41 ModuleSource::SourceFile(file) => &*file, 44 ModuleSource::SourceFile(file) => &*file,
42 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), 45 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
@@ -47,40 +50,27 @@ impl ImportSourceMap {
47} 50}
48 51
49impl RawItems { 52impl RawItems {
50 pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: FileId) -> Arc<RawItems> { 53 pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
51 db.raw_items_with_source_map(file_id).0 54 db.raw_items_with_source_map(file_id).0
52 } 55 }
53 56
54 pub(crate) fn raw_items_with_source_map_query( 57 pub(crate) fn raw_items_with_source_map_query(
55 db: &impl DefDatabase, 58 db: &impl DefDatabase,
56 file_id: FileId, 59 file_id: HirFileId,
57 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { 60 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
58 let mut collector = RawItemsCollector { 61 let mut collector = RawItemsCollector {
59 raw_items: RawItems::default(), 62 raw_items: RawItems::default(),
60 source_file_items: db.file_items(file_id.into()), 63 source_ast_id_map: db.ast_id_map(file_id.into()),
61 source_map: ImportSourceMap::default(), 64 source_map: ImportSourceMap::default(),
62 }; 65 };
63 let source_file = db.parse(file_id); 66 let source_file = db.hir_parse(file_id);
64 collector.process_module(None, &*source_file); 67 collector.process_module(None, &*source_file);
65 (Arc::new(collector.raw_items), Arc::new(collector.source_map)) 68 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
66 } 69 }
67 70
68 pub(crate) fn items(&self) -> &[RawItem] { 71 pub(super) fn items(&self) -> &[RawItem] {
69 &self.items 72 &self.items
70 } 73 }
71
72 // We can't use queries during name resolution for fear of cycles, so this
73 // is a query-less variant of the above function.
74 pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems {
75 let source_file_items = SourceFileItems::from_source_file(source_file, file_id);
76 let mut collector = RawItemsCollector {
77 raw_items: RawItems::default(),
78 source_file_items: Arc::new(source_file_items),
79 source_map: ImportSourceMap::default(),
80 };
81 collector.process_module(None, &*source_file);
82 collector.raw_items
83 }
84} 74}
85 75
86impl Index<Module> for RawItems { 76impl Index<Module> for RawItems {
@@ -112,7 +102,7 @@ impl Index<Macro> for RawItems {
112} 102}
113 103
114#[derive(Debug, PartialEq, Eq, Clone, Copy)] 104#[derive(Debug, PartialEq, Eq, Clone, Copy)]
115pub(crate) enum RawItem { 105pub(super) enum RawItem {
116 Module(Module), 106 Module(Module),
117 Import(ImportId), 107 Import(ImportId),
118 Def(Def), 108 Def(Def),
@@ -120,13 +110,13 @@ pub(crate) enum RawItem {
120} 110}
121 111
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 112#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
123pub(crate) struct Module(RawId); 113pub(super) struct Module(RawId);
124impl_arena_id!(Module); 114impl_arena_id!(Module);
125 115
126#[derive(Debug, PartialEq, Eq)] 116#[derive(Debug, PartialEq, Eq)]
127pub(crate) enum ModuleData { 117pub(super) enum ModuleData {
128 Declaration { name: Name, source_item_id: SourceFileItemId }, 118 Declaration { name: Name, ast_id: FileAstId<ast::Module> },
129 Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> }, 119 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
130} 120}
131 121
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -135,51 +125,49 @@ impl_arena_id!(ImportId);
135 125
136#[derive(Debug, Clone, PartialEq, Eq)] 126#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct ImportData { 127pub struct ImportData {
138 pub(crate) path: Path, 128 pub(super) path: Path,
139 pub(crate) alias: Option<Name>, 129 pub(super) alias: Option<Name>,
140 pub(crate) is_glob: bool, 130 pub(super) is_glob: bool,
141 pub(crate) is_prelude: bool, 131 pub(super) is_prelude: bool,
142 pub(crate) is_extern_crate: bool, 132 pub(super) is_extern_crate: bool,
143} 133}
144 134
145#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
146pub(crate) struct Def(RawId); 136pub(super) struct Def(RawId);
147impl_arena_id!(Def); 137impl_arena_id!(Def);
148 138
149#[derive(Debug, PartialEq, Eq)] 139#[derive(Debug, PartialEq, Eq)]
150pub(crate) struct DefData { 140pub(super) struct DefData {
151 pub(crate) source_item_id: SourceFileItemId, 141 pub(super) name: Name,
152 pub(crate) name: Name, 142 pub(super) kind: DefKind,
153 pub(crate) kind: DefKind,
154} 143}
155 144
156#[derive(Debug, PartialEq, Eq, Clone, Copy)] 145#[derive(Debug, PartialEq, Eq, Clone, Copy)]
157pub(crate) enum DefKind { 146pub(super) enum DefKind {
158 Function, 147 Function(FileAstId<ast::FnDef>),
159 Struct, 148 Struct(FileAstId<ast::StructDef>),
160 Enum, 149 Enum(FileAstId<ast::EnumDef>),
161 Const, 150 Const(FileAstId<ast::ConstDef>),
162 Static, 151 Static(FileAstId<ast::StaticDef>),
163 Trait, 152 Trait(FileAstId<ast::TraitDef>),
164 TypeAlias, 153 TypeAlias(FileAstId<ast::TypeAliasDef>),
165} 154}
166 155
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
168pub(crate) struct Macro(RawId); 157pub(super) struct Macro(RawId);
169impl_arena_id!(Macro); 158impl_arena_id!(Macro);
170 159
171#[derive(Debug, PartialEq, Eq)] 160#[derive(Debug, PartialEq, Eq)]
172pub(crate) struct MacroData { 161pub(super) struct MacroData {
173 pub(crate) source_item_id: SourceFileItemId, 162 pub(super) ast_id: FileAstId<ast::MacroCall>,
174 pub(crate) path: Path, 163 pub(super) path: Path,
175 pub(crate) name: Option<Name>, 164 pub(super) name: Option<Name>,
176 pub(crate) arg: tt::Subtree, 165 pub(super) export: bool,
177 pub(crate) export: bool,
178} 166}
179 167
180struct RawItemsCollector { 168struct RawItemsCollector {
181 raw_items: RawItems, 169 raw_items: RawItems,
182 source_file_items: Arc<SourceFileItems>, 170 source_ast_id_map: Arc<AstIdMap>,
183 source_map: ImportSourceMap, 171 source_map: ImportSourceMap,
184} 172}
185 173
@@ -211,18 +199,31 @@ impl RawItemsCollector {
211 // impls don't participate in name resolution 199 // impls don't participate in name resolution
212 return; 200 return;
213 } 201 }
214 ast::ModuleItemKind::StructDef(it) => (DefKind::Struct, it.name()), 202 ast::ModuleItemKind::StructDef(it) => {
215 ast::ModuleItemKind::EnumDef(it) => (DefKind::Enum, it.name()), 203 (DefKind::Struct(self.source_ast_id_map.ast_id(it)), it.name())
216 ast::ModuleItemKind::FnDef(it) => (DefKind::Function, it.name()), 204 }
217 ast::ModuleItemKind::TraitDef(it) => (DefKind::Trait, it.name()), 205 ast::ModuleItemKind::EnumDef(it) => {
218 ast::ModuleItemKind::TypeAliasDef(it) => (DefKind::TypeAlias, it.name()), 206 (DefKind::Enum(self.source_ast_id_map.ast_id(it)), it.name())
219 ast::ModuleItemKind::ConstDef(it) => (DefKind::Const, it.name()), 207 }
220 ast::ModuleItemKind::StaticDef(it) => (DefKind::Static, it.name()), 208 ast::ModuleItemKind::FnDef(it) => {
209 (DefKind::Function(self.source_ast_id_map.ast_id(it)), it.name())
210 }
211 ast::ModuleItemKind::TraitDef(it) => {
212 (DefKind::Trait(self.source_ast_id_map.ast_id(it)), it.name())
213 }
214 ast::ModuleItemKind::TypeAliasDef(it) => {
215 (DefKind::TypeAlias(self.source_ast_id_map.ast_id(it)), it.name())
216 }
217 ast::ModuleItemKind::ConstDef(it) => {
218 (DefKind::Const(self.source_ast_id_map.ast_id(it)), it.name())
219 }
220 ast::ModuleItemKind::StaticDef(it) => {
221 (DefKind::Static(self.source_ast_id_map.ast_id(it)), it.name())
222 }
221 }; 223 };
222 if let Some(name) = name { 224 if let Some(name) = name {
223 let name = name.as_name(); 225 let name = name.as_name();
224 let source_item_id = self.source_file_items.id_of_unchecked(item.syntax()); 226 let def = self.raw_items.defs.alloc(DefData { name, kind });
225 let def = self.raw_items.defs.alloc(DefData { name, kind, source_item_id });
226 self.push_item(current_module, RawItem::Def(def)) 227 self.push_item(current_module, RawItem::Def(def))
227 } 228 }
228 } 229 }
@@ -232,10 +233,9 @@ impl RawItemsCollector {
232 Some(it) => it.as_name(), 233 Some(it) => it.as_name(),
233 None => return, 234 None => return,
234 }; 235 };
235 let source_item_id = self.source_file_items.id_of_unchecked(module.syntax()); 236 let ast_id = self.source_ast_id_map.ast_id(module);
236 if module.has_semi() { 237 if module.has_semi() {
237 let item = 238 let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id });
238 self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id });
239 self.push_item(current_module, RawItem::Module(item)); 239 self.push_item(current_module, RawItem::Module(item));
240 return; 240 return;
241 } 241 }
@@ -243,7 +243,7 @@ impl RawItemsCollector {
243 if let Some(item_list) = module.item_list() { 243 if let Some(item_list) = module.item_list() {
244 let item = self.raw_items.modules.alloc(ModuleData::Definition { 244 let item = self.raw_items.modules.alloc(ModuleData::Definition {
245 name, 245 name,
246 source_item_id, 246 ast_id,
247 items: Vec::new(), 247 items: Vec::new(),
248 }); 248 });
249 self.process_module(Some(item), item_list); 249 self.process_module(Some(item), item_list);
@@ -291,18 +291,15 @@ impl RawItemsCollector {
291 } 291 }
292 292
293 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) { 293 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
294 let (path, arg) = match ( 294 let path = match m.path().and_then(Path::from_ast) {
295 m.path().and_then(Path::from_ast), 295 Some(it) => it,
296 m.token_tree().and_then(mbe::ast_to_token_tree),
297 ) {
298 (Some(path), Some((token_tree, _token_map))) => (path, token_tree),
299 _ => return, 296 _ => return,
300 }; 297 };
301 298
302 let name = m.name().map(|it| it.as_name()); 299 let name = m.name().map(|it| it.as_name());
303 let source_item_id = self.source_file_items.id_of_unchecked(m.syntax()); 300 let ast_id = self.source_ast_id_map.ast_id(m);
304 let export = m.has_atom_attr("macro_export"); 301 let export = m.has_atom_attr("macro_export");
305 let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name, export }); 302 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
306 self.push_item(current_module, RawItem::Macro(m)); 303 self.push_item(current_module, RawItem::Macro(m));
307 } 304 }
308 305
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/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs
index 698781923..001f76ac3 100644
--- a/crates/ra_hir/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir/src/nameres/tests/incremental.rs
@@ -90,34 +90,44 @@ fn adding_inner_items_should_not_invalidate_def_map() {
90 ); 90 );
91} 91}
92 92
93// It would be awesome to make this work, but it's unclear how
94#[test] 93#[test]
95#[ignore] 94fn typing_inside_a_macro_should_not_invalidate_def_map() {
96fn typing_inside_a_function_inside_a_macro_should_not_invalidate_def_map() { 95 let (mut db, pos) = MockDatabase::with_position(
97 check_def_map_is_not_recomputed(
98 " 96 "
99 //- /lib.rs 97 //- /lib.rs
98 macro_rules! m {
99 ($ident:ident) => {
100 fn f() {
101 $ident + $ident;
102 };
103 }
104 }
100 mod foo; 105 mod foo;
101 106
102 use crate::foo::bar::Baz;
103
104 //- /foo/mod.rs 107 //- /foo/mod.rs
105 pub mod bar; 108 pub mod bar;
106 109
107 //- /foo/bar.rs 110 //- /foo/bar.rs
108 <|> 111 <|>
109 salsa::query_group! { 112 m!(X);
110 trait Baz {
111 fn foo() -> i32 { 1 + 1 }
112 }
113 }
114 ",
115 "
116 salsa::query_group! {
117 trait Baz {
118 fn foo() -> i32 { 92 }
119 }
120 }
121 ", 113 ",
122 ); 114 );
115 {
116 let events = db.log_executed(|| {
117 let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();
118 let decls = module.declarations(&db);
119 assert_eq!(decls.len(), 1);
120 });
121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
122 }
123 db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string()));
124
125 {
126 let events = db.log_executed(|| {
127 let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();
128 let decls = module.declarations(&db);
129 assert_eq!(decls.len(), 1);
130 });
131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
132 }
123} 133}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index f28154517..2609585b1 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -11,7 +11,7 @@ use crate::{
11 generics::GenericParams, 11 generics::GenericParams,
12 expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, 12 expr::{scope::{ExprScopes, ScopeId}, PatId, Body},
13 impl_block::ImplBlock, 13 impl_block::ImplBlock,
14 path::Path, 14 path::Path, Trait
15}; 15};
16 16
17#[derive(Debug, Clone, Default)] 17#[derive(Debug, Clone, Default)]
@@ -175,6 +175,21 @@ impl Resolver {
175 names 175 names
176 } 176 }
177 177
178 pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
179 // FIXME prelude
180 self.scopes
181 .iter()
182 .rev()
183 .flat_map(|scope| {
184 match scope {
185 Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()),
186 _ => None,
187 }
188 .into_iter()
189 })
190 .flatten()
191 }
192
178 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { 193 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
179 self.scopes.iter().rev().find_map(|scope| match scope { 194 self.scopes.iter().rev().find_map(|scope| match scope {
180 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), 195 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 3645b73b4..9dae4c3d1 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -15,8 +15,8 @@ use ra_syntax::{
15use crate::{ 15use crate::{
16 HirDatabase, Function, Struct, Enum, 16 HirDatabase, Function, Struct, Enum,
17 AsName, Module, HirFileId, Crate, Trait, Resolver, 17 AsName, Module, HirFileId, Crate, Trait, Resolver,
18 ids::{LocationCtx, SourceFileItemId}, 18 ids::LocationCtx,
19 expr 19 expr, AstId
20}; 20};
21 21
22/// Locates the module by `FileId`. Picks topmost module in the file. 22/// Locates the module by `FileId`. Picks topmost module in the file.
@@ -54,8 +54,8 @@ fn module_from_inline(
54) -> Option<Module> { 54) -> Option<Module> {
55 assert!(!module.has_semi()); 55 assert!(!module.has_semi());
56 let file_id = file_id.into(); 56 let file_id = file_id.into();
57 let file_items = db.file_items(file_id); 57 let ast_id_map = db.ast_id_map(file_id);
58 let item_id = file_items.id_of(file_id, module.syntax()); 58 let item_id = ast_id_map.ast_id(module).with_file_id(file_id);
59 module_from_source(db, file_id, Some(item_id)) 59 module_from_source(db, file_id, Some(item_id))
60} 60}
61 61
@@ -75,7 +75,7 @@ pub fn module_from_child_node(
75fn module_from_source( 75fn module_from_source(
76 db: &impl HirDatabase, 76 db: &impl HirDatabase,
77 file_id: HirFileId, 77 file_id: HirFileId,
78 decl_id: Option<SourceFileItemId>, 78 decl_id: Option<AstId<ast::Module>>,
79) -> Option<Module> { 79) -> Option<Module> {
80 let source_root_id = db.file_source_root(file_id.as_original_file()); 80 let source_root_id = db.file_source_root(file_id.as_original_file());
81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( 81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs
new file mode 100644
index 000000000..0a8fb6d32
--- /dev/null
+++ b/crates/ra_hir/src/source_id.rs
@@ -0,0 +1,150 @@
1use std::{marker::PhantomData, sync::Arc, hash::{Hash, Hasher}};
2
3use ra_arena::{Arena, RawId, impl_arena_id};
4use ra_syntax::{SyntaxNodePtr, TreeArc, SyntaxNode, SourceFile, AstNode, ast};
5
6use crate::{HirFileId, DefDatabase};
7
8/// `AstId` points to an AST node in any file.
9///
10/// It is stable across reparses, and can be used as salsa key/value.
11#[derive(Debug)]
12pub(crate) struct AstId<N: AstNode> {
13 file_id: HirFileId,
14 file_ast_id: FileAstId<N>,
15}
16
17impl<N: AstNode> Clone for AstId<N> {
18 fn clone(&self) -> AstId<N> {
19 *self
20 }
21}
22impl<N: AstNode> Copy for AstId<N> {}
23
24impl<N: AstNode> PartialEq for AstId<N> {
25 fn eq(&self, other: &Self) -> bool {
26 (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
27 }
28}
29impl<N: AstNode> Eq for AstId<N> {}
30impl<N: AstNode> Hash for AstId<N> {
31 fn hash<H: Hasher>(&self, hasher: &mut H) {
32 (self.file_id, self.file_ast_id).hash(hasher);
33 }
34}
35
36impl<N: AstNode> AstId<N> {
37 pub(crate) fn file_id(&self) -> HirFileId {
38 self.file_id
39 }
40
41 pub(crate) fn to_node(&self, db: &impl DefDatabase) -> TreeArc<N> {
42 let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.raw);
43 N::cast(&syntax_node).unwrap().to_owned()
44 }
45}
46
47/// `AstId` points to an AST node in a specific file.
48#[derive(Debug)]
49pub(crate) struct FileAstId<N: AstNode> {
50 raw: ErasedFileAstId,
51 _ty: PhantomData<N>,
52}
53
54impl<N: AstNode> Clone for FileAstId<N> {
55 fn clone(&self) -> FileAstId<N> {
56 *self
57 }
58}
59impl<N: AstNode> Copy for FileAstId<N> {}
60
61impl<N: AstNode> PartialEq for FileAstId<N> {
62 fn eq(&self, other: &Self) -> bool {
63 self.raw == other.raw
64 }
65}
66impl<N: AstNode> Eq for FileAstId<N> {}
67impl<N: AstNode> Hash for FileAstId<N> {
68 fn hash<H: Hasher>(&self, hasher: &mut H) {
69 self.raw.hash(hasher);
70 }
71}
72
73impl<N: AstNode> FileAstId<N> {
74 pub(crate) fn with_file_id(self, file_id: HirFileId) -> AstId<N> {
75 AstId { file_id, file_ast_id: self }
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
80pub struct ErasedFileAstId(RawId);
81impl_arena_id!(ErasedFileAstId);
82
83/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
84#[derive(Debug, PartialEq, Eq)]
85pub struct AstIdMap {
86 arena: Arena<ErasedFileAstId, SyntaxNodePtr>,
87}
88
89impl AstIdMap {
90 pub(crate) fn ast_id_map_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
91 let source_file = db.hir_parse(file_id);
92 Arc::new(AstIdMap::from_source_file(&source_file))
93 }
94
95 pub(crate) fn file_item_query(
96 db: &impl DefDatabase,
97 file_id: HirFileId,
98 ast_id: ErasedFileAstId,
99 ) -> TreeArc<SyntaxNode> {
100 let source_file = db.hir_parse(file_id);
101 db.ast_id_map(file_id).arena[ast_id].to_node(&source_file).to_owned()
102 }
103
104 pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> {
105 let ptr = SyntaxNodePtr::new(item.syntax());
106 let raw = match self.arena.iter().find(|(_id, i)| **i == ptr) {
107 Some((it, _)) => it,
108 None => panic!(
109 "Can't find {:?} in AstIdMap:\n{:?}",
110 item.syntax(),
111 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
112 ),
113 };
114
115 FileAstId { raw, _ty: PhantomData }
116 }
117
118 fn from_source_file(source_file: &SourceFile) -> AstIdMap {
119 let mut res = AstIdMap { arena: Arena::default() };
120 // By walking the tree in bread-first order we make sure that parents
121 // get lower ids then children. That is, adding a new child does not
122 // change parent's id. This means that, say, adding a new function to a
123 // trait does not change ids of top-level items, which helps caching.
124 bfs(source_file.syntax(), |it| {
125 if let Some(module_item) = ast::ModuleItem::cast(it) {
126 res.alloc(module_item.syntax());
127 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
128 res.alloc(macro_call.syntax());
129 }
130 });
131 res
132 }
133
134 fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
135 self.arena.alloc(SyntaxNodePtr::new(item))
136 }
137}
138
139/// Walks the subtree in bfs order, calling `f` for each node.
140fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
141 let mut curr_layer = vec![node];
142 let mut next_layer = vec![];
143 while !curr_layer.is_empty() {
144 curr_layer.drain(..).for_each(|node| {
145 next_layer.extend(node.children());
146 f(node);
147 });
148 std::mem::swap(&mut curr_layer, &mut next_layer);
149 }
150}
diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs
new file mode 100644
index 000000000..725bdd5cb
--- /dev/null
+++ b/crates/ra_hir/src/traits.rs
@@ -0,0 +1,52 @@
1//! HIR for trait definitions.
2
3use std::sync::Arc;
4
5use ra_syntax::ast::{self, NameOwner};
6
7use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationCtx, name::AsName};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct TraitData {
11 name: Option<Name>,
12 items: Vec<TraitItem>,
13}
14
15impl TraitData {
16 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: Trait) -> Arc<TraitData> {
17 let (file_id, node) = tr.source(db);
18 let name = node.name().map(|n| n.as_name());
19 let module = tr.module(db);
20 let ctx = LocationCtx::new(db, module, file_id);
21 let items = if let Some(item_list) = node.item_list() {
22 item_list
23 .impl_items()
24 .map(|item_node| match item_node.kind() {
25 ast::ImplItemKind::FnDef(it) => Function { id: ctx.to_def(it) }.into(),
26 ast::ImplItemKind::ConstDef(it) => Const { id: ctx.to_def(it) }.into(),
27 ast::ImplItemKind::TypeAliasDef(it) => TypeAlias { id: ctx.to_def(it) }.into(),
28 })
29 .collect()
30 } else {
31 Vec::new()
32 };
33 Arc::new(TraitData { name, items })
34 }
35
36 pub(crate) fn name(&self) -> &Option<Name> {
37 &self.name
38 }
39
40 pub(crate) fn items(&self) -> &[TraitItem] {
41 &self.items
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub enum TraitItem {
47 Function(Function),
48 Const(Const),
49 TypeAlias(TypeAlias),
50 // Existential
51}
52impl_froms!(TraitItem: Function, Const, TypeAlias);
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 7d25ade47..d42c61e9d 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -14,7 +14,7 @@ pub(crate) mod display;
14use std::sync::Arc; 14use std::sync::Arc;
15use std::{fmt, mem}; 15use std::{fmt, mem};
16 16
17use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase}; 17use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait};
18 18
19pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; 19pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig};
20pub(crate) use infer::{infer, InferenceResult, InferTy}; 20pub(crate) use infer::{infer, InferenceResult, InferTy};
@@ -91,7 +91,7 @@ pub enum TypeCtor {
91/// A nominal type with (maybe 0) type parameters. This might be a primitive 91/// A nominal type with (maybe 0) type parameters. This might be a primitive
92/// type like `bool`, a struct, tuple, function pointer, reference or 92/// type like `bool`, a struct, tuple, function pointer, reference or
93/// several other things. 93/// several other things.
94#[derive(Clone, PartialEq, Eq, Debug)] 94#[derive(Clone, PartialEq, Eq, Debug, Hash)]
95pub struct ApplicationTy { 95pub struct ApplicationTy {
96 pub ctor: TypeCtor, 96 pub ctor: TypeCtor,
97 pub parameters: Substs, 97 pub parameters: Substs,
@@ -103,7 +103,7 @@ pub struct ApplicationTy {
103/// the same thing (but in a different way). 103/// the same thing (but in a different way).
104/// 104///
105/// This should be cheap to clone. 105/// This should be cheap to clone.
106#[derive(Clone, PartialEq, Eq, Debug)] 106#[derive(Clone, PartialEq, Eq, Debug, Hash)]
107pub enum Ty { 107pub enum Ty {
108 /// A nominal type with (maybe 0) type parameters. This might be a primitive 108 /// A nominal type with (maybe 0) type parameters. This might be a primitive
109 /// type like `bool`, a struct, tuple, function pointer, reference or 109 /// type like `bool`, a struct, tuple, function pointer, reference or
@@ -132,7 +132,7 @@ pub enum Ty {
132} 132}
133 133
134/// A list of substitutions for generic parameters. 134/// A list of substitutions for generic parameters.
135#[derive(Clone, PartialEq, Eq, Debug)] 135#[derive(Clone, PartialEq, Eq, Debug, Hash)]
136pub struct Substs(Arc<[Ty]>); 136pub struct Substs(Arc<[Ty]>);
137 137
138impl Substs { 138impl Substs {
@@ -169,6 +169,21 @@ impl Substs {
169 } 169 }
170} 170}
171 171
172/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
173/// Name to be bikeshedded: TraitBound? TraitImplements?
174#[derive(Clone, PartialEq, Eq, Debug, Hash)]
175pub struct TraitRef {
176 /// FIXME name?
177 trait_: Trait,
178 substs: Substs,
179}
180
181impl TraitRef {
182 pub fn self_ty(&self) -> &Ty {
183 &self.substs.0[0]
184 }
185}
186
172/// A function signature as seen by type inference: Several parameter types and 187/// A function signature as seen by type inference: Several parameter types and
173/// one return type. 188/// one return type.
174#[derive(Clone, PartialEq, Eq, Debug)] 189#[derive(Clone, PartialEq, Eq, Debug)]
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index cff7e7481..573115321 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
@@ -807,7 +821,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
807 } 821 }
808 Expr::MethodCall { receiver, args, method_name, generic_args } => { 822 Expr::MethodCall { receiver, args, method_name, generic_args } => {
809 let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); 823 let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
810 let resolved = receiver_ty.clone().lookup_method(self.db, method_name); 824 let resolved =
825 receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver);
811 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 826 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
812 Some((ty, func)) => { 827 Some((ty, func)) => {
813 self.write_method_resolution(tgt_expr, func); 828 self.write_method_resolution(tgt_expr, func);
@@ -915,9 +930,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
915 Expr::StructLit { path, fields, spread } => { 930 Expr::StructLit { path, fields, spread } => {
916 let (ty, def_id) = self.resolve_variant(path.as_ref()); 931 let (ty, def_id) = self.resolve_variant(path.as_ref());
917 let substs = ty.substs().unwrap_or_else(Substs::empty); 932 let substs = ty.substs().unwrap_or_else(Substs::empty);
918 for field in fields { 933 for (field_idx, field) in fields.into_iter().enumerate() {
919 let field_ty = def_id 934 let field_ty = def_id
920 .and_then(|it| it.field(self.db, &field.name)) 935 .and_then(|it| match it.field(self.db, &field.name) {
936 Some(field) => Some(field),
937 None => {
938 self.diagnostics.push(InferenceDiagnostic::NoSuchField {
939 expr: tgt_expr,
940 field: field_idx,
941 });
942 None
943 }
944 })
921 .map_or(Ty::Unknown, |field| field.ty(self.db)) 945 .map_or(Ty::Unknown, |field| field.ty(self.db))
922 .subst(&substs); 946 .subst(&substs);
923 self.infer_expr(field.expr, &Expectation::has_type(field_ty)); 947 self.infer_expr(field.expr, &Expectation::has_type(field_ty));
@@ -1244,3 +1268,29 @@ impl Expectation {
1244 Expectation { ty: Ty::Unknown } 1268 Expectation { ty: Ty::Unknown }
1245 } 1269 }
1246} 1270}
1271
1272mod diagnostics {
1273 use crate::{expr::ExprId, diagnostics::{DiagnosticSink, NoSuchField}, HirDatabase, Function};
1274
1275 #[derive(Debug, PartialEq, Eq, Clone)]
1276 pub(super) enum InferenceDiagnostic {
1277 NoSuchField { expr: ExprId, field: usize },
1278 }
1279
1280 impl InferenceDiagnostic {
1281 pub(super) fn add_to(
1282 &self,
1283 db: &impl HirDatabase,
1284 owner: Function,
1285 sink: &mut DiagnosticSink,
1286 ) {
1287 match self {
1288 InferenceDiagnostic::NoSuchField { expr, field } => {
1289 let (file, _) = owner.source(db);
1290 let field = owner.body_source_map(db).field_syntax(*expr, *field);
1291 sink.push(NoSuchField { file, field })
1292 }
1293 }
1294 }
1295 }
1296}
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index b1684acf9..3ac8dc46b 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -8,12 +8,12 @@ use rustc_hash::FxHashMap;
8 8
9use crate::{ 9use crate::{
10 HirDatabase, Module, Crate, Name, Function, Trait, 10 HirDatabase, Module, Crate, Name, Function, Trait,
11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 11 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{Ty, TypeCtor}, 12 ty::{Ty, TypeCtor},
14 nameres::CrateModuleId, 13 nameres::CrateModuleId, resolve::Resolver, traits::TraitItem
15 14
16}; 15};
16use super::{ TraitRef, Substs};
17 17
18/// This is used as a key for indexing impls. 18/// This is used as a key for indexing impls.
19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -38,7 +38,7 @@ pub struct CrateImplBlocks {
38 /// To make sense of the CrateModuleIds, we need the source root. 38 /// To make sense of the CrateModuleIds, we need the source root.
39 krate: Crate, 39 krate: Crate,
40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, 40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
41 impls_by_trait: FxHashMap<TraitId, Vec<(CrateModuleId, ImplId)>>, 41 impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>,
42} 42}
43 43
44impl CrateImplBlocks { 44impl CrateImplBlocks {
@@ -56,8 +56,7 @@ impl CrateImplBlocks {
56 &'a self, 56 &'a self,
57 tr: &Trait, 57 tr: &Trait,
58 ) -> impl Iterator<Item = ImplBlock> + 'a { 58 ) -> impl Iterator<Item = ImplBlock> + 'a {
59 let id = tr.id; 59 self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map(
60 self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map(
61 move |(module_id, impl_id)| { 60 move |(module_id, impl_id)| {
62 let module = Module { krate: self.krate, module_id: *module_id }; 61 let module = Module { krate: self.krate, module_id: *module_id };
63 ImplBlock::from_id(module, *impl_id) 62 ImplBlock::from_id(module, *impl_id)
@@ -73,18 +72,18 @@ impl CrateImplBlocks {
73 72
74 let target_ty = impl_block.target_ty(db); 73 let target_ty = impl_block.target_ty(db);
75 74
76 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
77 self.impls
78 .entry(target_ty_fp)
79 .or_insert_with(Vec::new)
80 .push((module.module_id, impl_id));
81 }
82
83 if let Some(tr) = impl_block.target_trait(db) { 75 if let Some(tr) = impl_block.target_trait(db) {
84 self.impls_by_trait 76 self.impls_by_trait
85 .entry(tr.id) 77 .entry(tr)
86 .or_insert_with(Vec::new) 78 .or_insert_with(Vec::new)
87 .push((module.module_id, impl_id)); 79 .push((module.module_id, impl_id));
80 } else {
81 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
82 self.impls
83 .entry(target_ty_fp)
84 .or_insert_with(Vec::new)
85 .push((module.module_id, impl_id));
86 }
88 } 87 }
89 } 88 }
90 89
@@ -109,6 +108,20 @@ impl CrateImplBlocks {
109 } 108 }
110} 109}
111 110
111/// Rudimentary check whether an impl exists for a given type and trait; this
112/// will actually be done by chalk.
113pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool {
114 // FIXME use all trait impls in the whole crate graph
115 let krate = trait_ref.trait_.module(db).krate(db);
116 let krate = match krate {
117 Some(krate) => krate,
118 None => return false,
119 };
120 let crate_impl_blocks = db.impls_in_crate(krate);
121 let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_);
122 impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty())
123}
124
112fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { 125fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
113 match ty { 126 match ty {
114 Ty::Apply(a_ty) => match a_ty.ctor { 127 Ty::Apply(a_ty) => match a_ty.ctor {
@@ -120,20 +133,64 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
120} 133}
121 134
122impl Ty { 135impl Ty {
123 // FIXME: cache this as a query?
124 // - if so, what signature? (TyFingerprint, Name)?
125 // - or maybe cache all names and def_ids of methods per fingerprint?
126 /// Look up the method with the given name, returning the actual autoderefed 136 /// Look up the method with the given name, returning the actual autoderefed
127 /// receiver type (but without autoref applied yet). 137 /// receiver type (but without autoref applied yet).
128 pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { 138 pub fn lookup_method(
129 self.iterate_methods(db, |ty, f| { 139 self,
140 db: &impl HirDatabase,
141 name: &Name,
142 resolver: &Resolver,
143 ) -> Option<(Ty, Function)> {
144 // FIXME: trait methods should be used before autoderefs
145 let inherent_method = self.clone().iterate_methods(db, |ty, f| {
130 let sig = f.signature(db); 146 let sig = f.signature(db);
131 if sig.name() == name && sig.has_self_param() { 147 if sig.name() == name && sig.has_self_param() {
132 Some((ty.clone(), f)) 148 Some((ty.clone(), f))
133 } else { 149 } else {
134 None 150 None
135 } 151 }
136 }) 152 });
153 inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver))
154 }
155
156 fn lookup_trait_method(
157 self,
158 db: &impl HirDatabase,
159 name: &Name,
160 resolver: &Resolver,
161 ) -> Option<(Ty, Function)> {
162 let mut candidates = Vec::new();
163 for t in resolver.traits_in_scope() {
164 let data = t.trait_data(db);
165 for item in data.items() {
166 match item {
167 &TraitItem::Function(m) => {
168 let sig = m.signature(db);
169 if sig.name() == name && sig.has_self_param() {
170 candidates.push((t, m));
171 }
172 }
173 _ => {}
174 }
175 }
176 }
177 // FIXME:
178 // - we might not actually be able to determine fully that the type
179 // implements the trait here; it's enough if we (well, Chalk) determine
180 // that it's possible.
181 // - when the trait method is picked, we need to register an
182 // 'obligation' somewhere so that we later check that it's really
183 // implemented
184 // - both points go for additional requirements from where clauses as
185 // well (in fact, the 'implements' condition could just be considered a
186 // 'where Self: Trait' clause)
187 candidates.retain(|(t, _m)| {
188 let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) };
189 db.implements(trait_ref)
190 });
191 // FIXME if there's multiple candidates here, that's an ambiguity error
192 let (_chosen_trait, chosen_method) = candidates.first()?;
193 Some((self.clone(), *chosen_method))
137 } 194 }
138 195
139 // This would be nicer if it just returned an iterator, but that runs into 196 // This would be nicer if it just returned an iterator, but that runs into
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 5d8ad4aa7..655f3c522 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1272,8 +1272,8 @@ fn test() {
1272[241; 252) 'Struct::FOO': u32 1272[241; 252) 'Struct::FOO': u32
1273[262; 263) 'y': u32 1273[262; 263) 'y': u32
1274[266; 275) 'Enum::BAR': u32 1274[266; 275) 'Enum::BAR': u32
1275[285; 286) 'z': u32 1275[285; 286) 'z': {unknown}
1276[289; 302) 'TraitTest::ID': u32"### 1276[289; 302) 'TraitTest::ID': {unknown}"###
1277 ); 1277 );
1278} 1278}
1279 1279
@@ -1918,9 +1918,9 @@ fn test() {
1918[110; 114) 'self': &{unknown} 1918[110; 114) 'self': &{unknown}
1919[170; 228) '{ ...i128 }': () 1919[170; 228) '{ ...i128 }': ()
1920[176; 178) 'S1': S1 1920[176; 178) 'S1': S1
1921[176; 187) 'S1.method()': {unknown} 1921[176; 187) 'S1.method()': u32
1922[203; 205) 'S2': S2 1922[203; 205) 'S2': S2
1923[203; 214) 'S2.method()': {unknown}"### 1923[203; 214) 'S2.method()': i128"###
1924 ); 1924 );
1925} 1925}
1926 1926
@@ -1964,10 +1964,10 @@ mod bar_test {
1964[169; 173) 'self': &{unknown} 1964[169; 173) 'self': &{unknown}
1965[300; 337) '{ ... }': () 1965[300; 337) '{ ... }': ()
1966[310; 311) 'S': S 1966[310; 311) 'S': S
1967[310; 320) 'S.method()': {unknown} 1967[310; 320) 'S.method()': u32
1968[416; 454) '{ ... }': () 1968[416; 454) '{ ... }': ()
1969[426; 427) 'S': S 1969[426; 427) 'S': S
1970[426; 436) 'S.method()': {unknown}"### 1970[426; 436) 'S.method()': i128"###
1971 ); 1971 );
1972} 1972}
1973 1973
@@ -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/change.rs b/crates/ra_ide_api/src/change.rs
index 26fde91bc..a4a086931 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -220,8 +220,8 @@ impl RootDatabase {
220 self.query(ra_db::ParseQuery).sweep(sweep); 220 self.query(ra_db::ParseQuery).sweep(sweep);
221 221
222 self.query(hir::db::HirParseQuery).sweep(sweep); 222 self.query(hir::db::HirParseQuery).sweep(sweep);
223 self.query(hir::db::FileItemsQuery).sweep(sweep); 223 self.query(hir::db::AstIdMapQuery).sweep(sweep);
224 self.query(hir::db::FileItemQuery).sweep(sweep); 224 self.query(hir::db::AstIdToNodeQuery).sweep(sweep);
225 225
226 self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep); 226 self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep);
227 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); 227 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 156f28ca3..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) {
@@ -128,34 +149,12 @@ fn check_struct_shorthand_initialization(
128 Some(()) 149 Some(())
129} 150}
130 151
131fn check_module(
132 acc: &mut Vec<Diagnostic>,
133 db: &RootDatabase,
134 file_id: FileId,
135 module: hir::Module,
136) {
137 let source_root = db.file_source_root(file_id);
138 for (name_node, problem) in module.problems(db) {
139 let diag = match problem {
140 Problem::UnresolvedModule { candidate } => {
141 let create_file =
142 FileSystemEdit::CreateFile { source_root, path: candidate.clone() };
143 let fix = SourceChange::file_system_edit("create module", create_file);
144 Diagnostic {
145 range: name_node.range(),
146 message: "unresolved module".to_string(),
147 severity: Severity::Error,
148 fix: Some(fix),
149 }
150 }
151 };
152 acc.push(diag)
153 }
154}
155
156#[cfg(test)] 152#[cfg(test)]
157mod tests { 153mod tests {
158 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;
159 158
160 use super::*; 159 use super::*;
161 160
@@ -185,6 +184,34 @@ mod tests {
185 } 184 }
186 185
187 #[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]
188 fn test_check_unnecessary_braces_in_use_statement() { 215 fn test_check_unnecessary_braces_in_use_statement() {
189 check_not_applicable( 216 check_not_applicable(
190 " 217 "
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 8aa3eb088..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
@@ -388,7 +387,7 @@ impl Analysis {
388 /// file outline. 387 /// file outline.
389 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { 388 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
390 let file = self.db.parse(file_id); 389 let file = self.db.parse(file_id);
391 ra_ide_api_light::file_structure(&file) 390 structure::file_structure(&file)
392 } 391 }
393 392
394 /// Returns the set of folding ranges. 393 /// Returns the set of folding ranges.
diff --git a/crates/ra_ide_api/src/parent_module.rs b/crates/ra_ide_api/src/parent_module.rs
index 603c3db6a..27788c984 100644
--- a/crates/ra_ide_api/src/parent_module.rs
+++ b/crates/ra_ide_api/src/parent_module.rs
@@ -28,7 +28,11 @@ pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
28 28
29#[cfg(test)] 29#[cfg(test)]
30mod tests { 30mod tests {
31 use crate::mock_analysis::analysis_and_position; 31 use crate::{
32 AnalysisChange, CrateGraph,
33 mock_analysis::{analysis_and_position, MockAnalysis},
34 Edition::Edition2018,
35};
32 36
33 #[test] 37 #[test]
34 fn test_resolve_parent_module() { 38 fn test_resolve_parent_module() {
@@ -59,4 +63,28 @@ mod tests {
59 let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); 63 let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
60 nav.assert_match("baz MODULE FileId(1) [32; 44)"); 64 nav.assert_match("baz MODULE FileId(1) [32; 44)");
61 } 65 }
66
67 #[test]
68 fn test_resolve_crate_root() {
69 let mock = MockAnalysis::with_files(
70 "
71 //- /bar.rs
72 mod foo;
73 //- /foo.rs
74 // empty <|>
75 ",
76 );
77 let root_file = mock.id_of("/bar.rs");
78 let mod_file = mock.id_of("/foo.rs");
79 let mut host = mock.analysis_host();
80 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
81
82 let mut crate_graph = CrateGraph::default();
83 let crate_id = crate_graph.add_crate_root(root_file, Edition2018);
84 let mut change = AnalysisChange::new();
85 change.set_crate_graph(crate_graph);
86 host.apply_change(change);
87
88 assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
89 }
62} 90}
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 22741445a..20bbf11a3 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -216,10 +216,56 @@ mod tests {
216 use crate::{ 216 use crate::{
217 mock_analysis::single_file_with_position, 217 mock_analysis::single_file_with_position,
218 mock_analysis::analysis_and_position, 218 mock_analysis::analysis_and_position,
219 FileId 219 FileId, ReferenceSearchResult
220}; 220};
221 221
222 #[test] 222 #[test]
223 fn test_find_all_refs_for_local() {
224 let code = r#"
225 fn main() {
226 let mut i = 1;
227 let j = 1;
228 i = i<|> + j;
229
230 {
231 i = 0;
232 }
233
234 i = 5;
235 }"#;
236
237 let refs = get_all_refs(code);
238 assert_eq!(refs.len(), 5);
239 }
240
241 #[test]
242 fn test_find_all_refs_for_param_inside() {
243 let code = r#"
244 fn foo(i : u32) -> u32 {
245 i<|>
246 }"#;
247
248 let refs = get_all_refs(code);
249 assert_eq!(refs.len(), 2);
250 }
251
252 #[test]
253 fn test_find_all_refs_for_fn_param() {
254 let code = r#"
255 fn foo(i<|> : u32) -> u32 {
256 i
257 }"#;
258
259 let refs = get_all_refs(code);
260 assert_eq!(refs.len(), 2);
261 }
262
263 fn get_all_refs(text: &str) -> ReferenceSearchResult {
264 let (analysis, position) = single_file_with_position(text);
265 analysis.find_all_refs(position).unwrap().unwrap()
266 }
267
268 #[test]
223 fn test_rename_for_local() { 269 fn test_rename_for_local() {
224 test_rename( 270 test_rename(
225 r#" 271 r#"
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/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index 0978d164a..0eadc4e71 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -270,3 +270,61 @@ fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
270 container_name: None, 270 container_name: None,
271 }) 271 })
272} 272}
273
274#[cfg(test)]
275mod tests {
276 use ra_syntax::SmolStr;
277 use crate::{
278 navigation_target::NavigationTarget,
279 mock_analysis::single_file,
280 Query,
281};
282
283 #[test]
284 fn test_world_symbols_with_no_container() {
285 let code = r#"
286 enum FooInner { }
287 "#;
288
289 let mut symbols = get_symbols_matching(code, "FooInner");
290
291 let s = symbols.pop().unwrap();
292
293 assert_eq!(s.name(), "FooInner");
294 assert!(s.container_name().is_none());
295 }
296
297 #[test]
298 fn test_world_symbols_include_container_name() {
299 let code = r#"
300fn foo() {
301 enum FooInner { }
302}
303 "#;
304
305 let mut symbols = get_symbols_matching(code, "FooInner");
306
307 let s = symbols.pop().unwrap();
308
309 assert_eq!(s.name(), "FooInner");
310 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
311
312 let code = r#"
313mod foo {
314 struct FooInner;
315}
316 "#;
317
318 let mut symbols = get_symbols_matching(code, "FooInner");
319
320 let s = symbols.pop().unwrap();
321
322 assert_eq!(s.name(), "FooInner");
323 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
324 }
325
326 fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
327 let (analysis, _) = single_file(text);
328 analysis.symbol_search(Query::new(query.into())).unwrap()
329 }
330}
diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs
index bbe9222b4..276f8a8c8 100644
--- a/crates/ra_ide_api/src/syntax_tree.rs
+++ b/crates/ra_ide_api/src/syntax_tree.rs
@@ -85,3 +85,260 @@ fn syntax_tree_for_token<T: AstToken>(node: &T, text_range: TextRange) -> Option
85 85
86 None 86 None
87} 87}
88
89#[cfg(test)]
90mod tests {
91 use crate::mock_analysis::{single_file, single_file_with_range};
92
93 #[test]
94 fn test_syntax_tree_without_range() {
95 // Basic syntax
96 let (analysis, file_id) = single_file(r#"fn foo() {}"#);
97 let syn = analysis.syntax_tree(file_id, None);
98
99 assert_eq!(
100 syn.trim(),
101 r#"
102SOURCE_FILE@[0; 11)
103 FN_DEF@[0; 11)
104 FN_KW@[0; 2)
105 WHITESPACE@[2; 3)
106 NAME@[3; 6)
107 IDENT@[3; 6) "foo"
108 PARAM_LIST@[6; 8)
109 L_PAREN@[6; 7)
110 R_PAREN@[7; 8)
111 WHITESPACE@[8; 9)
112 BLOCK@[9; 11)
113 L_CURLY@[9; 10)
114 R_CURLY@[10; 11)
115 "#
116 .trim()
117 );
118
119 let (analysis, file_id) = single_file(
120 r#"
121fn test() {
122 assert!("
123 fn foo() {
124 }
125 ", "");
126}"#
127 .trim(),
128 );
129 let syn = analysis.syntax_tree(file_id, None);
130
131 assert_eq!(
132 syn.trim(),
133 r#"
134SOURCE_FILE@[0; 60)
135 FN_DEF@[0; 60)
136 FN_KW@[0; 2)
137 WHITESPACE@[2; 3)
138 NAME@[3; 7)
139 IDENT@[3; 7) "test"
140 PARAM_LIST@[7; 9)
141 L_PAREN@[7; 8)
142 R_PAREN@[8; 9)
143 WHITESPACE@[9; 10)
144 BLOCK@[10; 60)
145 L_CURLY@[10; 11)
146 WHITESPACE@[11; 16)
147 EXPR_STMT@[16; 58)
148 MACRO_CALL@[16; 57)
149 PATH@[16; 22)
150 PATH_SEGMENT@[16; 22)
151 NAME_REF@[16; 22)
152 IDENT@[16; 22) "assert"
153 EXCL@[22; 23)
154 TOKEN_TREE@[23; 57)
155 L_PAREN@[23; 24)
156 STRING@[24; 52)
157 COMMA@[52; 53)
158 WHITESPACE@[53; 54)
159 STRING@[54; 56)
160 R_PAREN@[56; 57)
161 SEMI@[57; 58)
162 WHITESPACE@[58; 59)
163 R_CURLY@[59; 60)
164 "#
165 .trim()
166 );
167 }
168
169 #[test]
170 fn test_syntax_tree_with_range() {
171 let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim());
172 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
173
174 assert_eq!(
175 syn.trim(),
176 r#"
177FN_DEF@[0; 11)
178 FN_KW@[0; 2)
179 WHITESPACE@[2; 3)
180 NAME@[3; 6)
181 IDENT@[3; 6) "foo"
182 PARAM_LIST@[6; 8)
183 L_PAREN@[6; 7)
184 R_PAREN@[7; 8)
185 WHITESPACE@[8; 9)
186 BLOCK@[9; 11)
187 L_CURLY@[9; 10)
188 R_CURLY@[10; 11)
189 "#
190 .trim()
191 );
192
193 let (analysis, range) = single_file_with_range(
194 r#"fn test() {
195 <|>assert!("
196 fn foo() {
197 }
198 ", "");<|>
199}"#
200 .trim(),
201 );
202 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
203
204 assert_eq!(
205 syn.trim(),
206 r#"
207EXPR_STMT@[16; 58)
208 MACRO_CALL@[16; 57)
209 PATH@[16; 22)
210 PATH_SEGMENT@[16; 22)
211 NAME_REF@[16; 22)
212 IDENT@[16; 22) "assert"
213 EXCL@[22; 23)
214 TOKEN_TREE@[23; 57)
215 L_PAREN@[23; 24)
216 STRING@[24; 52)
217 COMMA@[52; 53)
218 WHITESPACE@[53; 54)
219 STRING@[54; 56)
220 R_PAREN@[56; 57)
221 SEMI@[57; 58)
222 "#
223 .trim()
224 );
225 }
226
227 #[test]
228 fn test_syntax_tree_inside_string() {
229 let (analysis, range) = single_file_with_range(
230 r#"fn test() {
231 assert!("
232<|>fn foo() {
233}<|>
234fn bar() {
235}
236 ", "");
237}"#
238 .trim(),
239 );
240 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
241 assert_eq!(
242 syn.trim(),
243 r#"
244SOURCE_FILE@[0; 12)
245 FN_DEF@[0; 12)
246 FN_KW@[0; 2)
247 WHITESPACE@[2; 3)
248 NAME@[3; 6)
249 IDENT@[3; 6) "foo"
250 PARAM_LIST@[6; 8)
251 L_PAREN@[6; 7)
252 R_PAREN@[7; 8)
253 WHITESPACE@[8; 9)
254 BLOCK@[9; 12)
255 L_CURLY@[9; 10)
256 WHITESPACE@[10; 11)
257 R_CURLY@[11; 12)
258"#
259 .trim()
260 );
261
262 // With a raw string
263 let (analysis, range) = single_file_with_range(
264 r###"fn test() {
265 assert!(r#"
266<|>fn foo() {
267}<|>
268fn bar() {
269}
270 "#, "");
271}"###
272 .trim(),
273 );
274 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
275 assert_eq!(
276 syn.trim(),
277 r#"
278SOURCE_FILE@[0; 12)
279 FN_DEF@[0; 12)
280 FN_KW@[0; 2)
281 WHITESPACE@[2; 3)
282 NAME@[3; 6)
283 IDENT@[3; 6) "foo"
284 PARAM_LIST@[6; 8)
285 L_PAREN@[6; 7)
286 R_PAREN@[7; 8)
287 WHITESPACE@[8; 9)
288 BLOCK@[9; 12)
289 L_CURLY@[9; 10)
290 WHITESPACE@[10; 11)
291 R_CURLY@[11; 12)
292"#
293 .trim()
294 );
295
296 // With a raw string
297 let (analysis, range) = single_file_with_range(
298 r###"fn test() {
299 assert!(r<|>#"
300fn foo() {
301}
302fn bar() {
303}"<|>#, "");
304}"###
305 .trim(),
306 );
307 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
308 assert_eq!(
309 syn.trim(),
310 r#"
311SOURCE_FILE@[0; 25)
312 FN_DEF@[0; 12)
313 FN_KW@[0; 2)
314 WHITESPACE@[2; 3)
315 NAME@[3; 6)
316 IDENT@[3; 6) "foo"
317 PARAM_LIST@[6; 8)
318 L_PAREN@[6; 7)
319 R_PAREN@[7; 8)
320 WHITESPACE@[8; 9)
321 BLOCK@[9; 12)
322 L_CURLY@[9; 10)
323 WHITESPACE@[10; 11)
324 R_CURLY@[11; 12)
325 WHITESPACE@[12; 13)
326 FN_DEF@[13; 25)
327 FN_KW@[13; 15)
328 WHITESPACE@[15; 16)
329 NAME@[16; 19)
330 IDENT@[16; 19) "bar"
331 PARAM_LIST@[19; 21)
332 L_PAREN@[19; 20)
333 R_PAREN@[20; 21)
334 WHITESPACE@[21; 22)
335 BLOCK@[22; 25)
336 L_CURLY@[22; 23)
337 WHITESPACE@[23; 24)
338 R_CURLY@[24; 25)
339
340"#
341 .trim()
342 );
343 }
344}
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs
deleted file mode 100644
index 0f0766f62..000000000
--- a/crates/ra_ide_api/tests/test/main.rs
+++ /dev/null
@@ -1,392 +0,0 @@
1use insta::assert_debug_snapshot_matches;
2use ra_ide_api::{
3 mock_analysis::{single_file, single_file_with_position, single_file_with_range, MockAnalysis},
4 AnalysisChange, CrateGraph, Edition::Edition2018, Query, NavigationTarget,
5 ReferenceSearchResult,
6};
7use ra_syntax::SmolStr;
8
9#[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() {
26 let mock = MockAnalysis::with_files(
27 "
28 //- /bar.rs
29 mod foo;
30 //- /foo.rs
31 // empty <|>
32 ",
33 );
34 let root_file = mock.id_of("/bar.rs");
35 let mod_file = mock.id_of("/foo.rs");
36 let mut host = mock.analysis_host();
37 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
38
39 let mut crate_graph = CrateGraph::default();
40 let crate_id = crate_graph.add_crate_root(root_file, Edition2018);
41 let mut change = AnalysisChange::new();
42 change.set_crate_graph(crate_graph);
43 host.apply_change(change);
44
45 assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
46}
47
48fn get_all_refs(text: &str) -> ReferenceSearchResult {
49 let (analysis, position) = single_file_with_position(text);
50 analysis.find_all_refs(position).unwrap().unwrap()
51}
52
53fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
54 let (analysis, _) = single_file(text);
55 analysis.symbol_search(Query::new(query.into())).unwrap()
56}
57
58#[test]
59fn test_find_all_refs_for_local() {
60 let code = r#"
61 fn main() {
62 let mut i = 1;
63 let j = 1;
64 i = i<|> + j;
65
66 {
67 i = 0;
68 }
69
70 i = 5;
71 }"#;
72
73 let refs = get_all_refs(code);
74 assert_eq!(refs.len(), 5);
75}
76
77#[test]
78fn test_find_all_refs_for_param_inside() {
79 let code = r#"
80 fn foo(i : u32) -> u32 {
81 i<|>
82 }"#;
83
84 let refs = get_all_refs(code);
85 assert_eq!(refs.len(), 2);
86}
87
88#[test]
89fn test_find_all_refs_for_fn_param() {
90 let code = r#"
91 fn foo(i<|> : u32) -> u32 {
92 i
93 }"#;
94
95 let refs = get_all_refs(code);
96 assert_eq!(refs.len(), 2);
97}
98
99#[test]
100fn test_world_symbols_with_no_container() {
101 let code = r#"
102 enum FooInner { }
103 "#;
104
105 let mut symbols = get_symbols_matching(code, "FooInner");
106
107 let s = symbols.pop().unwrap();
108
109 assert_eq!(s.name(), "FooInner");
110 assert!(s.container_name().is_none());
111}
112
113#[test]
114fn test_world_symbols_include_container_name() {
115 let code = r#"
116fn foo() {
117 enum FooInner { }
118}
119 "#;
120
121 let mut symbols = get_symbols_matching(code, "FooInner");
122
123 let s = symbols.pop().unwrap();
124
125 assert_eq!(s.name(), "FooInner");
126 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
127
128 let code = r#"
129mod foo {
130 struct FooInner;
131}
132 "#;
133
134 let mut symbols = get_symbols_matching(code, "FooInner");
135
136 let s = symbols.pop().unwrap();
137
138 assert_eq!(s.name(), "FooInner");
139 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
140}
141
142#[test]
143fn test_syntax_tree_without_range() {
144 // Basic syntax
145 let (analysis, file_id) = single_file(r#"fn foo() {}"#);
146 let syn = analysis.syntax_tree(file_id, None);
147
148 assert_eq!(
149 syn.trim(),
150 r#"
151SOURCE_FILE@[0; 11)
152 FN_DEF@[0; 11)
153 FN_KW@[0; 2)
154 WHITESPACE@[2; 3)
155 NAME@[3; 6)
156 IDENT@[3; 6) "foo"
157 PARAM_LIST@[6; 8)
158 L_PAREN@[6; 7)
159 R_PAREN@[7; 8)
160 WHITESPACE@[8; 9)
161 BLOCK@[9; 11)
162 L_CURLY@[9; 10)
163 R_CURLY@[10; 11)
164 "#
165 .trim()
166 );
167
168 let (analysis, file_id) = single_file(
169 r#"
170fn test() {
171 assert!("
172 fn foo() {
173 }
174 ", "");
175}"#
176 .trim(),
177 );
178 let syn = analysis.syntax_tree(file_id, None);
179
180 assert_eq!(
181 syn.trim(),
182 r#"
183SOURCE_FILE@[0; 60)
184 FN_DEF@[0; 60)
185 FN_KW@[0; 2)
186 WHITESPACE@[2; 3)
187 NAME@[3; 7)
188 IDENT@[3; 7) "test"
189 PARAM_LIST@[7; 9)
190 L_PAREN@[7; 8)
191 R_PAREN@[8; 9)
192 WHITESPACE@[9; 10)
193 BLOCK@[10; 60)
194 L_CURLY@[10; 11)
195 WHITESPACE@[11; 16)
196 EXPR_STMT@[16; 58)
197 MACRO_CALL@[16; 57)
198 PATH@[16; 22)
199 PATH_SEGMENT@[16; 22)
200 NAME_REF@[16; 22)
201 IDENT@[16; 22) "assert"
202 EXCL@[22; 23)
203 TOKEN_TREE@[23; 57)
204 L_PAREN@[23; 24)
205 STRING@[24; 52)
206 COMMA@[52; 53)
207 WHITESPACE@[53; 54)
208 STRING@[54; 56)
209 R_PAREN@[56; 57)
210 SEMI@[57; 58)
211 WHITESPACE@[58; 59)
212 R_CURLY@[59; 60)
213 "#
214 .trim()
215 );
216}
217
218#[test]
219fn test_syntax_tree_with_range() {
220 let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim());
221 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
222
223 assert_eq!(
224 syn.trim(),
225 r#"
226FN_DEF@[0; 11)
227 FN_KW@[0; 2)
228 WHITESPACE@[2; 3)
229 NAME@[3; 6)
230 IDENT@[3; 6) "foo"
231 PARAM_LIST@[6; 8)
232 L_PAREN@[6; 7)
233 R_PAREN@[7; 8)
234 WHITESPACE@[8; 9)
235 BLOCK@[9; 11)
236 L_CURLY@[9; 10)
237 R_CURLY@[10; 11)
238 "#
239 .trim()
240 );
241
242 let (analysis, range) = single_file_with_range(
243 r#"fn test() {
244 <|>assert!("
245 fn foo() {
246 }
247 ", "");<|>
248}"#
249 .trim(),
250 );
251 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
252
253 assert_eq!(
254 syn.trim(),
255 r#"
256EXPR_STMT@[16; 58)
257 MACRO_CALL@[16; 57)
258 PATH@[16; 22)
259 PATH_SEGMENT@[16; 22)
260 NAME_REF@[16; 22)
261 IDENT@[16; 22) "assert"
262 EXCL@[22; 23)
263 TOKEN_TREE@[23; 57)
264 L_PAREN@[23; 24)
265 STRING@[24; 52)
266 COMMA@[52; 53)
267 WHITESPACE@[53; 54)
268 STRING@[54; 56)
269 R_PAREN@[56; 57)
270 SEMI@[57; 58)
271 "#
272 .trim()
273 );
274}
275
276#[test]
277fn test_syntax_tree_inside_string() {
278 let (analysis, range) = single_file_with_range(
279 r#"fn test() {
280 assert!("
281<|>fn foo() {
282}<|>
283fn bar() {
284}
285 ", "");
286}"#
287 .trim(),
288 );
289 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
290 assert_eq!(
291 syn.trim(),
292 r#"
293SOURCE_FILE@[0; 12)
294 FN_DEF@[0; 12)
295 FN_KW@[0; 2)
296 WHITESPACE@[2; 3)
297 NAME@[3; 6)
298 IDENT@[3; 6) "foo"
299 PARAM_LIST@[6; 8)
300 L_PAREN@[6; 7)
301 R_PAREN@[7; 8)
302 WHITESPACE@[8; 9)
303 BLOCK@[9; 12)
304 L_CURLY@[9; 10)
305 WHITESPACE@[10; 11)
306 R_CURLY@[11; 12)
307"#
308 .trim()
309 );
310
311 // With a raw string
312 let (analysis, range) = single_file_with_range(
313 r###"fn test() {
314 assert!(r#"
315<|>fn foo() {
316}<|>
317fn bar() {
318}
319 "#, "");
320}"###
321 .trim(),
322 );
323 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
324 assert_eq!(
325 syn.trim(),
326 r#"
327SOURCE_FILE@[0; 12)
328 FN_DEF@[0; 12)
329 FN_KW@[0; 2)
330 WHITESPACE@[2; 3)
331 NAME@[3; 6)
332 IDENT@[3; 6) "foo"
333 PARAM_LIST@[6; 8)
334 L_PAREN@[6; 7)
335 R_PAREN@[7; 8)
336 WHITESPACE@[8; 9)
337 BLOCK@[9; 12)
338 L_CURLY@[9; 10)
339 WHITESPACE@[10; 11)
340 R_CURLY@[11; 12)
341"#
342 .trim()
343 );
344
345 // With a raw string
346 let (analysis, range) = single_file_with_range(
347 r###"fn test() {
348 assert!(r<|>#"
349fn foo() {
350}
351fn bar() {
352}"<|>#, "");
353}"###
354 .trim(),
355 );
356 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
357 assert_eq!(
358 syn.trim(),
359 r#"
360SOURCE_FILE@[0; 25)
361 FN_DEF@[0; 12)
362 FN_KW@[0; 2)
363 WHITESPACE@[2; 3)
364 NAME@[3; 6)
365 IDENT@[3; 6) "foo"
366 PARAM_LIST@[6; 8)
367 L_PAREN@[6; 7)
368 R_PAREN@[7; 8)
369 WHITESPACE@[8; 9)
370 BLOCK@[9; 12)
371 L_CURLY@[9; 10)
372 WHITESPACE@[10; 11)
373 R_CURLY@[11; 12)
374 WHITESPACE@[12; 13)
375 FN_DEF@[13; 25)
376 FN_KW@[13; 15)
377 WHITESPACE@[15; 16)
378 NAME@[16; 19)
379 IDENT@[16; 19) "bar"
380 PARAM_LIST@[19; 21)
381 L_PAREN@[19; 20)
382 R_PAREN@[20; 21)
383 WHITESPACE@[21; 22)
384 BLOCK@[22; 25)
385 L_CURLY@[22; 23)
386 WHITESPACE@[23; 24)
387 R_CURLY@[24; 25)
388
389"#
390 .trim()
391 );
392}
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_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index e428faffb..b2ffeff8c 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -184,6 +184,10 @@ fn name_ref(p: &mut Parser) {
184 let m = p.start(); 184 let m = p.start();
185 p.bump(); 185 p.bump();
186 m.complete(p, NAME_REF); 186 m.complete(p, NAME_REF);
187 } else if p.at(SELF_KW) {
188 let m = p.start();
189 p.bump();
190 m.complete(p, SELF_KW);
187 } else { 191 } else {
188 p.err_and_bump("expected identifier"); 192 p.err_and_bump("expected identifier");
189 } 193 }
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 54b72f8c5..47a37e4d1 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -4061,7 +4061,11 @@ impl ast::NameOwner for TraitDef {}
4061impl ast::AttrsOwner for TraitDef {} 4061impl ast::AttrsOwner for TraitDef {}
4062impl ast::DocCommentsOwner for TraitDef {} 4062impl ast::DocCommentsOwner for TraitDef {}
4063impl ast::TypeParamsOwner for TraitDef {} 4063impl ast::TypeParamsOwner for TraitDef {}
4064impl TraitDef {} 4064impl TraitDef {
4065 pub fn item_list(&self) -> Option<&ItemList> {
4066 super::child_opt(self)
4067 }
4068}
4065 4069
4066// TrueKw 4070// TrueKw
4067#[derive(Debug, PartialEq, Eq, Hash)] 4071#[derive(Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 4f8e19bd0..ad6d74162 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -292,7 +292,10 @@ Grammar(
292 ], options: [["variant_list", "EnumVariantList"]] ), 292 ], options: [["variant_list", "EnumVariantList"]] ),
293 "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ), 293 "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ),
294 "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ), 294 "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ),
295 "TraitDef": ( traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"] ), 295 "TraitDef": (
296 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"],
297 options: ["ItemList"]
298 ),
296 "Module": ( 299 "Module": (
297 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner" ], 300 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner" ],
298 options: [ "ItemList" ] 301 options: [ "ItemList" ]
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/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.rs b/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.rs
index 3ce336676..ab81a608c 100644
--- a/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.rs
+++ b/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.rs
@@ -1,2 +1,3 @@
1extern crate foo; 1extern crate foo;
2extern crate foo as bar; 2extern crate foo as bar;
3extern crate self as baz;
diff --git a/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt b/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt
index 5558d952e..0176260c1 100644
--- a/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt
+++ b/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt
@@ -1,4 +1,4 @@
1SOURCE_FILE@[0; 43) 1SOURCE_FILE@[0; 69)
2 EXTERN_CRATE_ITEM@[0; 17) 2 EXTERN_CRATE_ITEM@[0; 17)
3 EXTERN_KW@[0; 6) 3 EXTERN_KW@[0; 6)
4 WHITESPACE@[6; 7) 4 WHITESPACE@[6; 7)
@@ -23,3 +23,18 @@ SOURCE_FILE@[0; 43)
23 IDENT@[38; 41) "bar" 23 IDENT@[38; 41) "bar"
24 SEMI@[41; 42) 24 SEMI@[41; 42)
25 WHITESPACE@[42; 43) 25 WHITESPACE@[42; 43)
26 EXTERN_CRATE_ITEM@[43; 68)
27 EXTERN_KW@[43; 49)
28 WHITESPACE@[49; 50)
29 CRATE_KW@[50; 55)
30 WHITESPACE@[55; 56)
31 SELF_KW@[56; 60)
32 SELF_KW@[56; 60)
33 WHITESPACE@[60; 61)
34 ALIAS@[61; 67)
35 AS_KW@[61; 63)
36 WHITESPACE@[63; 64)
37 NAME@[64; 67)
38 IDENT@[64; 67) "baz"
39 SEMI@[67; 68)
40 WHITESPACE@[68; 69)
diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs
index 1e29c63d4..11b52ccb7 100644
--- a/crates/tools/src/lib.rs
+++ b/crates/tools/src/lib.rs
@@ -115,7 +115,11 @@ pub fn install_rustfmt() -> Result<()> {
115} 115}
116 116
117pub fn install_format_hook() -> Result<()> { 117pub fn install_format_hook() -> Result<()> {
118 let result_path = Path::new("./.git/hooks/pre-commit"); 118 let result_path = Path::new(if cfg!(windows) {
119 "./.git/hooks/pre-commit.exe"
120 } else {
121 "./.git/hooks/pre-commit"
122 });
119 if !result_path.exists() { 123 if !result_path.exists() {
120 run("cargo build --package tools --bin pre-commit", ".")?; 124 run("cargo build --package tools --bin pre-commit", ".")?;
121 if cfg!(windows) { 125 if cfg!(windows) {
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.
diff --git a/docs/user/features.md b/docs/user/features.md
index b9d2aa84f..7173d88e9 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -210,7 +210,7 @@ fn main() {
210} 210}
211``` 211```
212 212
213-- Fill struct fields 213- Fill struct fields
214 214
215```rust 215```rust
216// before: 216// before:
@@ -270,7 +270,22 @@ fn foo() {
270} 270}
271``` 271```
272 272
273-- Remove `dbg!` 273- Inline local variable:
274
275```rust
276// before:
277fn foo() {
278 let a<|> = 1 + 1;
279 let b = a * 10;
280}
281
282// after:
283fn foo() {
284 let b = (1 + 1) * 10;
285}
286```
287
288- Remove `dbg!`
274 289
275```rust 290```rust
276// before: 291// before:
diff --git a/editors/emacs/ra-emacs-lsp.el b/editors/emacs/ra-emacs-lsp.el
index 955703edb..84c018b66 100644
--- a/editors/emacs/ra-emacs-lsp.el
+++ b/editors/emacs/ra-emacs-lsp.el
@@ -159,7 +159,7 @@
159 (interactive (list (rust-analyzer--select-runnable))) 159 (interactive (list (rust-analyzer--select-runnable)))
160 (-let (((&hash "env" "bin" "args" "label") runnable)) 160 (-let (((&hash "env" "bin" "args" "label") runnable))
161 (compilation-start 161 (compilation-start
162 (string-join (cons bin args) " ") 162 (string-join (append (list bin) args '()) " ")
163 ;; cargo-process-mode is nice, but try to work without it... 163 ;; cargo-process-mode is nice, but try to work without it...
164 (if (functionp 'cargo-process-mode) 'cargo-process-mode nil) 164 (if (functionp 'cargo-process-mode) 'cargo-process-mode nil)
165 (lambda (_) (concat "*" label "*"))) 165 (lambda (_) (concat "*" label "*")))