aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-04 12:45:27 +0000
committerSeivan Heidari <[email protected]>2019-11-04 12:45:27 +0000
commitdad9bc6caad71e6aebb92ad9883c08d30431e9b1 (patch)
tree6495d47108bc56ab0fbb358125fe65ebece8934f
parent1d8bb4c6c1fef1f8ea513e07d0a7d4c5483129d2 (diff)
parentcc2d75d0f88bdcb1b3e20db36decb6ee6eca517a (diff)
Merge branch 'master' into feature/themes
-rw-r--r--.gitattributes3
-rw-r--r--Cargo.lock59
-rw-r--r--crates/ra_assists/src/assists/early_return.rs219
-rw-r--r--crates/ra_db/Cargo.toml1
-rw-r--r--crates/ra_db/src/fixture.rs186
-rw-r--r--crates/ra_db/src/input.rs4
-rw-r--r--crates/ra_db/src/lib.rs3
-rw-r--r--crates/ra_hir/Cargo.toml7
-rw-r--r--crates/ra_hir/src/code_model.rs42
-rw-r--r--crates/ra_hir/src/code_model/src.rs6
-rw-r--r--crates/ra_hir/src/db.rs10
-rw-r--r--crates/ra_hir/src/diagnostics.rs102
-rw-r--r--crates/ra_hir/src/expr/validation.rs3
-rw-r--r--crates/ra_hir/src/from_id.rs63
-rw-r--r--crates/ra_hir/src/from_source.rs22
-rw-r--r--crates/ra_hir/src/lib.rs11
-rw-r--r--crates/ra_hir/src/marks.rs11
-rw-r--r--crates/ra_hir/src/mock.rs74
-rw-r--r--crates/ra_hir/src/nameres.rs557
-rw-r--r--crates/ra_hir/src/resolve.rs110
-rw-r--r--crates/ra_hir/src/source_binder.rs7
-rw-r--r--crates/ra_hir/src/ty/infer.rs12
-rw-r--r--crates/ra_hir/src/ty/infer/expr.rs3
-rw-r--r--crates/ra_hir/src/ty/lower.rs5
-rw-r--r--crates/ra_hir/src/ty/tests.rs84
-rw-r--r--crates/ra_hir_def/Cargo.toml4
-rw-r--r--crates/ra_hir_def/src/adt.rs14
-rw-r--r--crates/ra_hir_def/src/db.rs15
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs28
-rw-r--r--crates/ra_hir_def/src/lib.rs27
-rw-r--r--crates/ra_hir_def/src/marks.rs14
-rw-r--r--crates/ra_hir_def/src/nameres.rs540
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs (renamed from crates/ra_hir/src/nameres/collector.rs)161
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs3
-rw-r--r--crates/ra_hir_def/src/nameres/per_ns.rs (renamed from crates/ra_hir/src/nameres/per_ns.rs)24
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs (renamed from crates/ra_hir/src/nameres/tests.rs)152
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs (renamed from crates/ra_hir/src/nameres/tests/globs.rs)10
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs (renamed from crates/ra_hir/src/nameres/tests/incremental.rs)32
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs (renamed from crates/ra_hir/src/nameres/tests/macros.rs)83
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs (renamed from crates/ra_hir/src/nameres/tests/mod_resolution.rs)47
-rw-r--r--crates/ra_hir_def/src/nameres/tests/primitives.rs (renamed from crates/ra_hir/src/nameres/tests/primitives.rs)0
-rw-r--r--crates/ra_hir_def/src/test_db.rs75
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs85
-rw-r--r--crates/ra_hir_expand/src/lib.rs21
-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/completion/complete_path.rs8
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_literal.rs28
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs17
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs68
-rw-r--r--crates/ra_ide_api/src/db.rs5
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs3
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs2
-rw-r--r--crates/ra_ide_api/src/references/rename.rs3
-rw-r--r--crates/ra_ide_api/src/source_change.rs2
-rw-r--r--crates/ra_lsp_server/src/conv.rs1
-rw-r--r--crates/ra_syntax/src/ast/make.rs17
-rw-r--r--crates/ra_tt/src/buffer.rs4
-rw-r--r--rustfmt.toml1
-rw-r--r--xtask/tests/tidy-tests/docs.rs15
61 files changed, 1810 insertions, 1312 deletions
diff --git a/.gitattributes b/.gitattributes
index a77342d72..183e9b521 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,2 @@
1crates/ra_syntax/tests/data/** -text 1crates/ra_syntax/test_data/** -text eof=LF
2crates/ra_ide_api/src/snapshots/** -text eof=LF
diff --git a/Cargo.lock b/Cargo.lock
index 10f51403a..3879204d9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -126,7 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
126[[package]] 126[[package]]
127name = "chalk-derive" 127name = "chalk-derive"
128version = "0.1.0" 128version = "0.1.0"
129source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" 129source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05"
130dependencies = [ 130dependencies = [
131 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 131 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
132 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 132 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -136,9 +136,9 @@ dependencies = [
136[[package]] 136[[package]]
137name = "chalk-engine" 137name = "chalk-engine"
138version = "0.9.0" 138version = "0.9.0"
139source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" 139source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05"
140dependencies = [ 140dependencies = [
141 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 141 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
142 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 142 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
143 "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 143 "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
144] 144]
@@ -146,18 +146,18 @@ dependencies = [
146[[package]] 146[[package]]
147name = "chalk-ir" 147name = "chalk-ir"
148version = "0.1.0" 148version = "0.1.0"
149source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" 149source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05"
150dependencies = [ 150dependencies = [
151 "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 151 "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
152 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 152 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
153 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 153 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
154 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 154 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
155] 155]
156 156
157[[package]] 157[[package]]
158name = "chalk-macros" 158name = "chalk-macros"
159version = "0.1.1" 159version = "0.1.1"
160source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" 160source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05"
161dependencies = [ 161dependencies = [
162 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 162 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
163] 163]
@@ -165,23 +165,23 @@ dependencies = [
165[[package]] 165[[package]]
166name = "chalk-rust-ir" 166name = "chalk-rust-ir"
167version = "0.1.0" 167version = "0.1.0"
168source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" 168source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05"
169dependencies = [ 169dependencies = [
170 "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 170 "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
171 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 171 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
172 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 172 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
173 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 173 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
174] 174]
175 175
176[[package]] 176[[package]]
177name = "chalk-solve" 177name = "chalk-solve"
178version = "0.1.0" 178version = "0.1.0"
179source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" 179source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05"
180dependencies = [ 180dependencies = [
181 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 181 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
182 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 182 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
183 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 183 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
184 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 184 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
185 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 185 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
186 "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 186 "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
187 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 187 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -985,6 +985,7 @@ dependencies = [
985 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 985 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
986 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 986 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
987 "salsa 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", 987 "salsa 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
988 "test_utils 0.1.0",
988] 989]
989 990
990[[package]] 991[[package]]
@@ -1000,9 +1001,9 @@ name = "ra_hir"
1000version = "0.1.0" 1001version = "0.1.0"
1001dependencies = [ 1002dependencies = [
1002 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1003 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1003 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 1004 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
1004 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 1005 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
1005 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", 1006 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)",
1006 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 1007 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
1007 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 1008 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
1008 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 1009 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1018,7 +1019,6 @@ dependencies = [
1018 "ra_prof 0.1.0", 1019 "ra_prof 0.1.0",
1019 "ra_syntax 0.1.0", 1020 "ra_syntax 0.1.0",
1020 "ra_tt 0.1.0", 1021 "ra_tt 0.1.0",
1021 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1022 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1022 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1023 "test_utils 0.1.0", 1023 "test_utils 0.1.0",
1024] 1024]
@@ -1027,6 +1027,7 @@ dependencies = [
1027name = "ra_hir_def" 1027name = "ra_hir_def"
1028version = "0.1.0" 1028version = "0.1.0"
1029dependencies = [ 1029dependencies = [
1030 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
1030 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1031 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1031 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1032 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1032 "ra_arena 0.1.0", 1033 "ra_arena 0.1.0",
@@ -1037,7 +1038,6 @@ dependencies = [
1037 "ra_prof 0.1.0", 1038 "ra_prof 0.1.0",
1038 "ra_syntax 0.1.0", 1039 "ra_syntax 0.1.0",
1039 "ra_tt 0.1.0", 1040 "ra_tt 0.1.0",
1040 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1041 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1041 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1042 "test_utils 0.1.0", 1042 "test_utils 0.1.0",
1043] 1043]
@@ -1077,7 +1077,6 @@ dependencies = [
1077 "ra_text_edit 0.1.0", 1077 "ra_text_edit 0.1.0",
1078 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1078 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1079 "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1079 "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1080 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1081 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1080 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1082 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1081 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1083 "test_utils 0.1.0", 1082 "test_utils 0.1.0",
@@ -1849,12 +1848,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1849"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" 1848"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d"
1850"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" 1849"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c"
1851"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 1850"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
1852"checksum chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "<none>" 1851"checksum chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "<none>"
1853"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "<none>" 1852"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "<none>"
1854"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "<none>" 1853"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "<none>"
1855"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "<none>" 1854"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "<none>"
1856"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "<none>" 1855"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "<none>"
1857"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "<none>" 1856"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "<none>"
1858"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" 1857"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68"
1859"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 1858"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
1860"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1859"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs
index ad6c5695a..570a07a20 100644
--- a/crates/ra_assists/src/assists/early_return.rs
+++ b/crates/ra_assists/src/assists/early_return.rs
@@ -3,9 +3,10 @@ use std::ops::RangeInclusive;
3use hir::db::HirDatabase; 3use hir::db::HirDatabase;
4use ra_syntax::{ 4use ra_syntax::{
5 algo::replace_children, 5 algo::replace_children,
6 ast::{self, edit::IndentLevel, make}, 6 ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat},
7 AstNode, 7 AstNode,
8 SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, 8 SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
9 SyntaxNode,
9}; 10};
10 11
11use crate::{ 12use crate::{
@@ -37,7 +38,23 @@ use crate::{
37// ``` 38// ```
38pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 39pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
39 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; 40 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
40 let expr = if_expr.condition()?.expr()?; 41 let cond = if_expr.condition()?;
42 let mut if_let_ident: Option<String> = None;
43
44 // Check if there is an IfLet that we can handle.
45 match cond.pat() {
46 None => {} // No IfLet, supported.
47 Some(TupleStructPat(ref pat)) if pat.args().count() == 1usize => match &pat.path() {
48 Some(p) => match p.qualifier() {
49 None => if_let_ident = Some(p.syntax().text().to_string()),
50 _ => return None,
51 },
52 _ => return None,
53 },
54 _ => return None, // Unsupported IfLet.
55 };
56
57 let expr = cond.expr()?;
41 let then_block = if_expr.then_branch()?.block()?; 58 let then_block = if_expr.then_branch()?.block()?;
42 if if_expr.else_branch().is_some() { 59 if if_expr.else_branch().is_some() {
43 return None; 60 return None;
@@ -63,8 +80,8 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
63 let parent_container = parent_block.syntax().parent()?.parent()?; 80 let parent_container = parent_block.syntax().parent()?.parent()?;
64 81
65 let early_expression = match parent_container.kind() { 82 let early_expression = match parent_container.kind() {
66 WHILE_EXPR | LOOP_EXPR => Some("continue;"), 83 WHILE_EXPR | LOOP_EXPR => Some("continue"),
67 FN_DEF => Some("return;"), 84 FN_DEF => Some("return"),
68 _ => None, 85 _ => None,
69 }?; 86 }?;
70 87
@@ -77,34 +94,58 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
77 94
78 ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { 95 ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
79 let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); 96 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
80 let new_if_expr = 97 let new_block = match if_let_ident {
81 if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); 98 None => {
82 let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); 99 // If.
83 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); 100 let early_expression = &(early_expression.to_owned() + ";");
84 let end_of_then = 101 let new_expr =
85 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { 102 if_indent_level.increase_indent(make::if_expression(&expr, early_expression));
86 end_of_then.prev_sibling_or_token().unwrap() 103 replace(new_expr, &then_block, &parent_block, &if_expr)
87 } else { 104 }
88 end_of_then 105 Some(if_let_ident) => {
89 }; 106 // If-let.
90 let mut new_if_and_then_statements = new_if_expr.syntax().children_with_tokens().chain( 107 let new_expr = if_indent_level.increase_indent(make::let_match_early(
91 then_block_items 108 expr,
92 .syntax() 109 &if_let_ident,
93 .children_with_tokens() 110 early_expression,
94 .skip(1) 111 ));
95 .take_while(|i| *i != end_of_then), 112 replace(new_expr, &then_block, &parent_block, &if_expr)
96 ); 113 }
97 let new_block = replace_children( 114 };
98 &parent_block.syntax(),
99 RangeInclusive::new(
100 if_expr.clone().syntax().clone().into(),
101 if_expr.syntax().clone().into(),
102 ),
103 &mut new_if_and_then_statements,
104 );
105 edit.target(if_expr.syntax().text_range()); 115 edit.target(if_expr.syntax().text_range());
106 edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); 116 edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap());
107 edit.set_cursor(cursor_position); 117 edit.set_cursor(cursor_position);
118
119 fn replace(
120 new_expr: impl AstNode,
121 then_block: &Block,
122 parent_block: &Block,
123 if_expr: &ast::IfExpr,
124 ) -> SyntaxNode {
125 let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
126 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
127 let end_of_then =
128 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
129 end_of_then.prev_sibling_or_token().unwrap()
130 } else {
131 end_of_then
132 };
133 let mut then_statements = new_expr.syntax().children_with_tokens().chain(
134 then_block_items
135 .syntax()
136 .children_with_tokens()
137 .skip(1)
138 .take_while(|i| *i != end_of_then),
139 );
140 replace_children(
141 &parent_block.syntax(),
142 RangeInclusive::new(
143 if_expr.clone().syntax().clone().into(),
144 if_expr.syntax().clone().into(),
145 ),
146 &mut then_statements,
147 )
148 }
108 }) 149 })
109} 150}
110 151
@@ -144,6 +185,68 @@ mod tests {
144 } 185 }
145 186
146 #[test] 187 #[test]
188 fn convert_let_inside_fn() {
189 check_assist(
190 convert_to_guarded_return,
191 r#"
192 fn main(n: Option<String>) {
193 bar();
194 if<|> let Some(n) = n {
195 foo(n);
196
197 //comment
198 bar();
199 }
200 }
201 "#,
202 r#"
203 fn main(n: Option<String>) {
204 bar();
205 le<|>t n = match n {
206 Some(it) => it,
207 None => return,
208 };
209 foo(n);
210
211 //comment
212 bar();
213 }
214 "#,
215 );
216 }
217
218 #[test]
219 fn convert_let_ok_inside_fn() {
220 check_assist(
221 convert_to_guarded_return,
222 r#"
223 fn main(n: Option<String>) {
224 bar();
225 if<|> let Ok(n) = n {
226 foo(n);
227
228 //comment
229 bar();
230 }
231 }
232 "#,
233 r#"
234 fn main(n: Option<String>) {
235 bar();
236 le<|>t n = match n {
237 Ok(it) => it,
238 None => return,
239 };
240 foo(n);
241
242 //comment
243 bar();
244 }
245 "#,
246 );
247 }
248
249 #[test]
147 fn convert_inside_while() { 250 fn convert_inside_while() {
148 check_assist( 251 check_assist(
149 convert_to_guarded_return, 252 convert_to_guarded_return,
@@ -172,6 +275,35 @@ mod tests {
172 } 275 }
173 276
174 #[test] 277 #[test]
278 fn convert_let_inside_while() {
279 check_assist(
280 convert_to_guarded_return,
281 r#"
282 fn main() {
283 while true {
284 if<|> let Some(n) = n {
285 foo(n);
286 bar();
287 }
288 }
289 }
290 "#,
291 r#"
292 fn main() {
293 while true {
294 le<|>t n = match n {
295 Some(it) => it,
296 None => continue,
297 };
298 foo(n);
299 bar();
300 }
301 }
302 "#,
303 );
304 }
305
306 #[test]
175 fn convert_inside_loop() { 307 fn convert_inside_loop() {
176 check_assist( 308 check_assist(
177 convert_to_guarded_return, 309 convert_to_guarded_return,
@@ -200,6 +332,35 @@ mod tests {
200 } 332 }
201 333
202 #[test] 334 #[test]
335 fn convert_let_inside_loop() {
336 check_assist(
337 convert_to_guarded_return,
338 r#"
339 fn main() {
340 loop {
341 if<|> let Some(n) = n {
342 foo(n);
343 bar();
344 }
345 }
346 }
347 "#,
348 r#"
349 fn main() {
350 loop {
351 le<|>t n = match n {
352 Some(it) => it,
353 None => continue,
354 };
355 foo(n);
356 bar();
357 }
358 }
359 "#,
360 );
361 }
362
363 #[test]
203 fn ignore_already_converted_if() { 364 fn ignore_already_converted_if() {
204 check_assist_not_applicable( 365 check_assist_not_applicable(
205 convert_to_guarded_return, 366 convert_to_guarded_return,
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index 3394ae8ce..bf1f7920c 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -12,3 +12,4 @@ rustc-hash = "1.0"
12ra_syntax = { path = "../ra_syntax" } 12ra_syntax = { path = "../ra_syntax" }
13ra_cfg = { path = "../ra_cfg" } 13ra_cfg = { path = "../ra_cfg" }
14ra_prof = { path = "../ra_prof" } 14ra_prof = { path = "../ra_prof" }
15test_utils = { path = "../test_utils" }
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
new file mode 100644
index 000000000..f5dd59f84
--- /dev/null
+++ b/crates/ra_db/src/fixture.rs
@@ -0,0 +1,186 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use ra_cfg::CfgOptions;
6use rustc_hash::FxHashMap;
7use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
8
9use crate::{
10 CrateGraph, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, SourceRoot,
11 SourceRootId,
12};
13
14pub const WORKSPACE: SourceRootId = SourceRootId(0);
15
16pub trait WithFixture: Default + SourceDatabaseExt + 'static {
17 fn with_single_file(text: &str) -> (Self, FileId) {
18 let mut db = Self::default();
19 let file_id = with_single_file(&mut db, text);
20 (db, file_id)
21 }
22
23 fn with_files(fixture: &str) -> Self {
24 let mut db = Self::default();
25 let pos = with_files(&mut db, fixture);
26 assert!(pos.is_none());
27 db
28 }
29
30 fn with_position(fixture: &str) -> (Self, FilePosition) {
31 let mut db = Self::default();
32 let pos = with_files(&mut db, fixture);
33 (db, pos.unwrap())
34 }
35}
36
37impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {}
38
39fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId {
40 let file_id = FileId(0);
41 let rel_path: RelativePathBuf = "/main.rs".into();
42
43 let mut source_root = SourceRoot::default();
44 source_root.insert_file(rel_path.clone(), file_id);
45
46 let mut crate_graph = CrateGraph::default();
47 crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default());
48
49 db.set_file_text(file_id, Arc::new(text.to_string()));
50 db.set_file_relative_path(file_id, rel_path);
51 db.set_file_source_root(file_id, WORKSPACE);
52 db.set_source_root(WORKSPACE, Arc::new(source_root));
53 db.set_crate_graph(Arc::new(crate_graph));
54
55 file_id
56}
57
58fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosition> {
59 let fixture = parse_fixture(fixture);
60
61 let mut crate_graph = CrateGraph::default();
62 let mut crates = FxHashMap::default();
63 let mut crate_deps = Vec::new();
64 let mut default_crate_root: Option<FileId> = None;
65
66 let mut source_root = SourceRoot::default();
67 let mut source_root_id = WORKSPACE;
68 let mut source_root_prefix: RelativePathBuf = "/".into();
69 let mut file_id = FileId(0);
70
71 let mut file_position = None;
72
73 for entry in fixture.iter() {
74 let meta = match parse_meta(&entry.meta) {
75 ParsedMeta::Root { path } => {
76 let source_root = std::mem::replace(&mut source_root, SourceRoot::default());
77 db.set_source_root(source_root_id, Arc::new(source_root));
78 source_root_id.0 += 1;
79 source_root_prefix = path;
80 continue;
81 }
82 ParsedMeta::File(it) => it,
83 };
84 assert!(meta.path.starts_with(&source_root_prefix));
85
86 if let Some(krate) = meta.krate {
87 let crate_id = crate_graph.add_crate_root(file_id, meta.edition, meta.cfg);
88 let prev = crates.insert(krate.clone(), crate_id);
89 assert!(prev.is_none());
90 for dep in meta.deps {
91 crate_deps.push((krate.clone(), dep))
92 }
93 } else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
94 assert!(default_crate_root.is_none());
95 default_crate_root = Some(file_id);
96 }
97
98 let text = if entry.text.contains(CURSOR_MARKER) {
99 let (offset, text) = extract_offset(&entry.text);
100 assert!(file_position.is_none());
101 file_position = Some(FilePosition { file_id, offset });
102 text.to_string()
103 } else {
104 entry.text.to_string()
105 };
106
107 db.set_file_text(file_id, Arc::new(text));
108 db.set_file_relative_path(file_id, meta.path.clone());
109 db.set_file_source_root(file_id, source_root_id);
110 source_root.insert_file(meta.path, file_id);
111
112 file_id.0 += 1;
113 }
114
115 if crates.is_empty() {
116 let crate_root = default_crate_root.unwrap();
117 crate_graph.add_crate_root(crate_root, Edition::Edition2018, CfgOptions::default());
118 } else {
119 for (from, to) in crate_deps {
120 let from_id = crates[&from];
121 let to_id = crates[&to];
122 crate_graph.add_dep(from_id, to.into(), to_id).unwrap();
123 }
124 }
125
126 db.set_source_root(source_root_id, Arc::new(source_root));
127 db.set_crate_graph(Arc::new(crate_graph));
128
129 file_position
130}
131
132enum ParsedMeta {
133 Root { path: RelativePathBuf },
134 File(FileMeta),
135}
136
137struct FileMeta {
138 path: RelativePathBuf,
139 krate: Option<String>,
140 deps: Vec<String>,
141 cfg: CfgOptions,
142 edition: Edition,
143}
144
145//- /lib.rs crate:foo deps:bar,baz
146fn parse_meta(meta: &str) -> ParsedMeta {
147 let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
148
149 if components[0] == "root" {
150 let path: RelativePathBuf = components[1].into();
151 assert!(path.starts_with("/") && path.ends_with("/"));
152 return ParsedMeta::Root { path };
153 }
154
155 let path: RelativePathBuf = components[0].into();
156 assert!(path.starts_with("/"));
157
158 let mut krate = None;
159 let mut deps = Vec::new();
160 let mut edition = Edition::Edition2018;
161 let mut cfg = CfgOptions::default();
162 for component in components[1..].iter() {
163 let (key, value) = split1(component, ':').unwrap();
164 match key {
165 "crate" => krate = Some(value.to_string()),
166 "deps" => deps = value.split(',').map(|it| it.to_string()).collect(),
167 "edition" => edition = Edition::from_string(&value),
168 "cfg" => {
169 for key in value.split(',') {
170 match split1(key, '=') {
171 None => cfg.insert_atom(key.into()),
172 Some((k, v)) => cfg.insert_key_value(k.into(), v.into()),
173 }
174 }
175 }
176 _ => panic!("bad component: {:?}", component),
177 }
178 }
179
180 ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg })
181}
182
183fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> {
184 let idx = haystack.find(delim)?;
185 Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..]))
186}
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index eafa95921..60f7dc881 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -6,13 +6,14 @@
6//! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how 6//! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how
7//! actual IO is done and lowered to input. 7//! actual IO is done and lowered to input.
8 8
9use relative_path::{RelativePath, RelativePathBuf};
10use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
11 10
12use ra_cfg::CfgOptions; 11use ra_cfg::CfgOptions;
13use ra_syntax::SmolStr; 12use ra_syntax::SmolStr;
14use rustc_hash::FxHashSet; 13use rustc_hash::FxHashSet;
15 14
15use crate::{RelativePath, RelativePathBuf};
16
16/// `FileId` is an integer which uniquely identifies a file. File paths are 17/// `FileId` is an integer which uniquely identifies a file. File paths are
17/// messy and system-dependent, so most of the code should work directly with 18/// messy and system-dependent, so most of the code should work directly with
18/// `FileId`, without inspecting the path. The mapping between `FileId` and path 19/// `FileId`, without inspecting the path. The mapping between `FileId` and path
@@ -97,6 +98,7 @@ pub enum Edition {
97} 98}
98 99
99impl Edition { 100impl Edition {
101 //FIXME: replace with FromStr with proper error handling
100 pub fn from_string(s: &str) -> Edition { 102 pub fn from_string(s: &str) -> Edition {
101 match s { 103 match s {
102 "2015" => Edition::Edition2015, 104 "2015" => Edition::Edition2015,
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 0d1ab4843..b6bfd531d 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -1,17 +1,18 @@
1//! ra_db defines basic database traits. The concrete DB is defined by ra_ide_api. 1//! ra_db defines basic database traits. The concrete DB is defined by ra_ide_api.
2mod cancellation; 2mod cancellation;
3mod input; 3mod input;
4pub mod fixture;
4 5
5use std::{panic, sync::Arc}; 6use std::{panic, sync::Arc};
6 7
7use ra_prof::profile; 8use ra_prof::profile;
8use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; 9use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit};
9use relative_path::{RelativePath, RelativePathBuf};
10 10
11pub use crate::{ 11pub use crate::{
12 cancellation::Canceled, 12 cancellation::Canceled,
13 input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId}, 13 input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId},
14}; 14};
15pub use relative_path::{RelativePath, RelativePathBuf};
15pub use salsa; 16pub use salsa;
16 17
17pub trait CheckCanceled { 18pub trait CheckCanceled {
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 5df371bc0..324961328 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -7,7 +7,6 @@ authors = ["rust-analyzer developers"]
7[dependencies] 7[dependencies]
8arrayvec = "0.5.1" 8arrayvec = "0.5.1"
9log = "0.4.5" 9log = "0.4.5"
10relative-path = "1.0.0"
11rustc-hash = "1.0" 10rustc-hash = "1.0"
12parking_lot = "0.9.0" 11parking_lot = "0.9.0"
13ena = "0.13" 12ena = "0.13"
@@ -24,9 +23,9 @@ hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
24test_utils = { path = "../test_utils" } 23test_utils = { path = "../test_utils" }
25ra_prof = { path = "../ra_prof" } 24ra_prof = { path = "../ra_prof" }
26 25
27chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } 26chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" }
28chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } 27chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" }
29chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } 28chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" }
30lalrpop-intern = "0.15.1" 29lalrpop-intern = "0.15.1"
31 30
32[dev-dependencies] 31[dev-dependencies]
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index c97ea18a2..181c5d47a 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -9,16 +9,18 @@ use hir_def::{
9 adt::VariantData, 9 adt::VariantData,
10 builtin_type::BuiltinType, 10 builtin_type::BuiltinType,
11 type_ref::{Mutability, TypeRef}, 11 type_ref::{Mutability, TypeRef},
12 CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, 12 CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId,
13};
14use hir_expand::{
15 diagnostics::DiagnosticSink,
16 name::{self, AsName},
13}; 17};
14use hir_expand::name::{self, AsName};
15use ra_db::{CrateId, Edition}; 18use ra_db::{CrateId, Edition};
16use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 19use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
17 20
18use crate::{ 21use crate::{
19 adt::VariantDef, 22 adt::VariantDef,
20 db::{AstDatabase, DefDatabase, HirDatabase}, 23 db::{AstDatabase, DefDatabase, HirDatabase},
21 diagnostics::DiagnosticSink,
22 expr::{validation::ExprValidator, Body, BodySourceMap}, 24 expr::{validation::ExprValidator, Body, BodySourceMap},
23 generics::HasGenericParams, 25 generics::HasGenericParams,
24 ids::{ 26 ids::{
@@ -26,11 +28,10 @@ use crate::{
26 TypeAliasId, 28 TypeAliasId,
27 }, 29 },
28 impl_block::ImplBlock, 30 impl_block::ImplBlock,
29 nameres::{ImportId, ModuleScope, Namespace},
30 resolve::{Resolver, Scope, TypeNs}, 31 resolve::{Resolver, Scope, TypeNs},
31 traits::TraitData, 32 traits::TraitData,
32 ty::{InferenceResult, TraitRef}, 33 ty::{InferenceResult, TraitRef},
33 Either, HasSource, Name, Ty, 34 Either, HasSource, Name, ScopeDef, Ty, {ImportId, Namespace},
34}; 35};
35 36
36/// hir::Crate describes a single crate. It's the main interface with which 37/// hir::Crate describes a single crate. It's the main interface with which
@@ -64,7 +65,7 @@ impl Crate {
64 } 65 }
65 66
66 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> { 67 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> {
67 let module_id = db.crate_def_map(self).root(); 68 let module_id = db.crate_def_map(self.crate_id).root();
68 Some(Module::new(self, module_id)) 69 Some(Module::new(self, module_id))
69 } 70 }
70 71
@@ -118,7 +119,7 @@ impl Module {
118 119
119 /// Name of this module. 120 /// Name of this module.
120 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 121 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
121 let def_map = db.crate_def_map(self.krate()); 122 let def_map = db.crate_def_map(self.id.krate);
122 let parent = def_map[self.id.module_id].parent?; 123 let parent = def_map[self.id.module_id].parent?;
123 def_map[parent].children.iter().find_map(|(name, module_id)| { 124 def_map[parent].children.iter().find_map(|(name, module_id)| {
124 if *module_id == self.id.module_id { 125 if *module_id == self.id.module_id {
@@ -149,20 +150,20 @@ impl Module {
149 /// might be missing `krate`. This can happen if a module's file is not included 150 /// might be missing `krate`. This can happen if a module's file is not included
150 /// in the module tree of any target in `Cargo.toml`. 151 /// in the module tree of any target in `Cargo.toml`.
151 pub fn crate_root(self, db: &impl DefDatabase) -> Module { 152 pub fn crate_root(self, db: &impl DefDatabase) -> Module {
152 let def_map = db.crate_def_map(self.krate()); 153 let def_map = db.crate_def_map(self.id.krate);
153 self.with_module_id(def_map.root()) 154 self.with_module_id(def_map.root())
154 } 155 }
155 156
156 /// Finds a child module with the specified name. 157 /// Finds a child module with the specified name.
157 pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> { 158 pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> {
158 let def_map = db.crate_def_map(self.krate()); 159 let def_map = db.crate_def_map(self.id.krate);
159 let child_id = def_map[self.id.module_id].children.get(name)?; 160 let child_id = def_map[self.id.module_id].children.get(name)?;
160 Some(self.with_module_id(*child_id)) 161 Some(self.with_module_id(*child_id))
161 } 162 }
162 163
163 /// Iterates over all child modules. 164 /// Iterates over all child modules.
164 pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> { 165 pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> {
165 let def_map = db.crate_def_map(self.krate()); 166 let def_map = db.crate_def_map(self.id.krate);
166 let children = def_map[self.id.module_id] 167 let children = def_map[self.id.module_id]
167 .children 168 .children
168 .iter() 169 .iter()
@@ -173,7 +174,7 @@ impl Module {
173 174
174 /// Finds a parent module. 175 /// Finds a parent module.
175 pub fn parent(self, db: &impl DefDatabase) -> Option<Module> { 176 pub fn parent(self, db: &impl DefDatabase) -> Option<Module> {
176 let def_map = db.crate_def_map(self.krate()); 177 let def_map = db.crate_def_map(self.id.krate);
177 let parent_id = def_map[self.id.module_id].parent?; 178 let parent_id = def_map[self.id.module_id].parent?;
178 Some(self.with_module_id(parent_id)) 179 Some(self.with_module_id(parent_id))
179 } 180 }
@@ -189,12 +190,16 @@ impl Module {
189 } 190 }
190 191
191 /// Returns a `ModuleScope`: a set of items, visible in this module. 192 /// Returns a `ModuleScope`: a set of items, visible in this module.
192 pub fn scope(self, db: &impl HirDatabase) -> ModuleScope { 193 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<ImportId>)> {
193 db.crate_def_map(self.krate())[self.id.module_id].scope.clone() 194 db.crate_def_map(self.id.krate)[self.id.module_id]
195 .scope
196 .entries()
197 .map(|(name, res)| (name.clone(), res.def.into(), res.import))
198 .collect()
194 } 199 }
195 200
196 pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) { 201 pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
197 db.crate_def_map(self.krate()).add_diagnostics(db, self.id.module_id, sink); 202 db.crate_def_map(self.id.krate).add_diagnostics(db, self.id.module_id, sink);
198 for decl in self.declarations(db) { 203 for decl in self.declarations(db) {
199 match decl { 204 match decl {
200 crate::ModuleDef::Function(f) => f.diagnostics(db, sink), 205 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
@@ -218,12 +223,12 @@ impl Module {
218 } 223 }
219 224
220 pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver { 225 pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver {
221 let def_map = db.crate_def_map(self.krate()); 226 let def_map = db.crate_def_map(self.id.krate);
222 Resolver::default().push_module_scope(def_map, self.id.module_id) 227 Resolver::default().push_module_scope(def_map, self.id.module_id)
223 } 228 }
224 229
225 pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> { 230 pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> {
226 let def_map = db.crate_def_map(self.krate()); 231 let def_map = db.crate_def_map(self.id.krate);
227 def_map[self.id.module_id] 232 def_map[self.id.module_id]
228 .scope 233 .scope
229 .entries() 234 .entries()
@@ -231,6 +236,7 @@ impl Module {
231 .flat_map(|per_ns| { 236 .flat_map(|per_ns| {
232 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter()) 237 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
233 }) 238 })
239 .map(ModuleDef::from)
234 .collect() 240 .collect()
235 } 241 }
236 242
@@ -334,12 +340,12 @@ impl Struct {
334 340
335#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 341#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
336pub struct Union { 342pub struct Union {
337 pub(crate) id: StructId, 343 pub(crate) id: UnionId,
338} 344}
339 345
340impl Union { 346impl Union {
341 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 347 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
342 db.struct_data(self.id).name.clone() 348 db.union_data(self.id).name.clone()
343 } 349 }
344 350
345 pub fn module(self, db: &impl HirDatabase) -> Module { 351 pub fn module(self, db: &impl HirDatabase) -> Module {
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 0f4c78df7..6d116ee75 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -10,7 +10,7 @@ use crate::{
10 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, 10 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
11}; 11};
12 12
13pub use hir_def::Source; 13pub use hir_expand::Source;
14 14
15pub trait HasSource { 15pub trait HasSource {
16 type Ast; 16 type Ast;
@@ -22,7 +22,7 @@ pub trait HasSource {
22impl Module { 22impl Module {
23 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 23 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
24 pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> { 24 pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> {
25 let def_map = db.crate_def_map(self.krate()); 25 let def_map = db.crate_def_map(self.id.krate);
26 let decl_id = def_map[self.id.module_id].declaration; 26 let decl_id = def_map[self.id.module_id].declaration;
27 let file_id = def_map[self.id.module_id].definition; 27 let file_id = def_map[self.id.module_id].definition;
28 let ast = ModuleSource::new(db, file_id, decl_id); 28 let ast = ModuleSource::new(db, file_id, decl_id);
@@ -36,7 +36,7 @@ impl Module {
36 self, 36 self,
37 db: &(impl DefDatabase + AstDatabase), 37 db: &(impl DefDatabase + AstDatabase),
38 ) -> Option<Source<ast::Module>> { 38 ) -> Option<Source<ast::Module>> {
39 let def_map = db.crate_def_map(self.krate()); 39 let def_map = db.crate_def_map(self.id.krate);
40 let decl = def_map[self.id.module_id].declaration?; 40 let decl = def_map[self.id.module_id].declaration?;
41 let ast = decl.to_node(db); 41 let ast = decl.to_node(db);
42 Some(Source { file_id: decl.file_id(), ast }) 42 Some(Source { file_id: decl.file_id(), ast })
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 89ca4e39f..eb66325f7 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -11,20 +11,19 @@ use crate::{
11 ids, 11 ids,
12 impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, 12 impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks},
13 lang_item::{LangItemTarget, LangItems}, 13 lang_item::{LangItemTarget, LangItems},
14 nameres::{CrateDefMap, Namespace},
15 traits::TraitData, 14 traits::TraitData,
16 ty::{ 15 ty::{
17 method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, 16 method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate,
18 InferenceResult, Substs, Ty, TypableDef, TypeCtor, 17 InferenceResult, Substs, Ty, TypableDef, TypeCtor,
19 }, 18 },
20 type_alias::TypeAliasData, 19 type_alias::TypeAliasData,
21 Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static, 20 Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Namespace, Static,
22 StructField, Trait, TypeAlias, 21 StructField, Trait, TypeAlias,
23}; 22};
24 23
25pub use hir_def::db::{ 24pub use hir_def::db::{
26 DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, InternDatabaseStorage, 25 CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase,
27 RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, 26 InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery,
28}; 27};
29pub use hir_expand::db::{ 28pub use hir_expand::db::{
30 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 29 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
@@ -41,9 +40,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
41 #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] 40 #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)]
42 fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; 41 fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex;
43 42
44 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
45 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
46
47 #[salsa::invoke(ModuleImplBlocks::impls_in_module_with_source_map_query)] 43 #[salsa::invoke(ModuleImplBlocks::impls_in_module_with_source_map_query)]
48 fn impls_in_module_with_source_map( 44 fn impls_in_module_with_source_map(
49 &self, 45 &self,
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index 9acdaf8ed..1751e7be3 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -1,82 +1,13 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{any::Any, fmt}; 3use std::any::Any;
4
5use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange};
6use relative_path::RelativePathBuf;
7
8use crate::{db::HirDatabase, HirFileId, Name, Source};
9
10/// Diagnostic defines hir API for errors and warnings.
11///
12/// It is used as a `dyn` object, which you can downcast to a concrete
13/// diagnostic. DiagnosticSink are structured, meaning that they include rich
14/// information which can be used by IDE to create fixes. DiagnosticSink are
15/// expressed in terms of macro-expanded syntax tree nodes (so, it's a bad idea
16/// to diagnostic in a salsa value).
17///
18/// Internally, various subsystems of hir produce diagnostics specific to a
19/// subsystem (typically, an `enum`), which are safe to store in salsa but do not
20/// include source locations. Such internal diagnostic are transformed into an
21/// instance of `Diagnostic` on demand.
22pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
23 fn message(&self) -> String;
24 fn source(&self) -> Source<SyntaxNodePtr>;
25 fn highlight_range(&self) -> TextRange {
26 self.source().ast.range()
27 }
28 fn as_any(&self) -> &(dyn Any + Send + 'static);
29}
30
31pub trait AstDiagnostic {
32 type AST;
33 fn ast(&self, db: &impl HirDatabase) -> Self::AST;
34}
35 4
36impl dyn Diagnostic { 5use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
37 pub fn syntax_node(&self, db: &impl HirDatabase) -> SyntaxNode {
38 let node = db.parse_or_expand(self.source().file_id).unwrap();
39 self.source().ast.to_node(&node)
40 }
41 6
42 pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { 7use crate::{db::AstDatabase, HirFileId, Name, Source};
43 self.as_any().downcast_ref()
44 }
45}
46 8
47pub struct DiagnosticSink<'a> { 9pub use hir_def::diagnostics::UnresolvedModule;
48 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, 10pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
49 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
50}
51
52impl<'a> DiagnosticSink<'a> {
53 pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> {
54 DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) }
55 }
56
57 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> {
58 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
59 Some(d) => {
60 cb(d);
61 Ok(())
62 }
63 None => Err(()),
64 };
65 self.callbacks.push(Box::new(cb));
66 self
67 }
68
69 pub(crate) fn push(&mut self, d: impl Diagnostic) {
70 let d: &dyn Diagnostic = &d;
71 for cb in self.callbacks.iter_mut() {
72 match cb(d) {
73 Ok(()) => return,
74 Err(()) => (),
75 }
76 }
77 (self.default_callback)(d)
78 }
79}
80 11
81#[derive(Debug)] 12#[derive(Debug)]
82pub struct NoSuchField { 13pub struct NoSuchField {
@@ -99,25 +30,6 @@ impl Diagnostic for NoSuchField {
99} 30}
100 31
101#[derive(Debug)] 32#[derive(Debug)]
102pub struct UnresolvedModule {
103 pub file: HirFileId,
104 pub decl: AstPtr<ast::Module>,
105 pub candidate: RelativePathBuf,
106}
107
108impl Diagnostic for UnresolvedModule {
109 fn message(&self) -> String {
110 "unresolved module".to_string()
111 }
112 fn source(&self) -> Source<SyntaxNodePtr> {
113 Source { file_id: self.file, ast: self.decl.into() }
114 }
115 fn as_any(&self) -> &(dyn Any + Send + 'static) {
116 self
117 }
118}
119
120#[derive(Debug)]
121pub struct MissingFields { 33pub struct MissingFields {
122 pub file: HirFileId, 34 pub file: HirFileId,
123 pub field_list: AstPtr<ast::RecordFieldList>, 35 pub field_list: AstPtr<ast::RecordFieldList>,
@@ -139,7 +51,7 @@ impl Diagnostic for MissingFields {
139impl AstDiagnostic for MissingFields { 51impl AstDiagnostic for MissingFields {
140 type AST = ast::RecordFieldList; 52 type AST = ast::RecordFieldList;
141 53
142 fn ast(&self, db: &impl HirDatabase) -> Self::AST { 54 fn ast(&self, db: &impl AstDatabase) -> Self::AST {
143 let root = db.parse_or_expand(self.source().file_id).unwrap(); 55 let root = db.parse_or_expand(self.source().file_id).unwrap();
144 let node = self.source().ast.to_node(&root); 56 let node = self.source().ast.to_node(&root);
145 ast::RecordFieldList::cast(node).unwrap() 57 ast::RecordFieldList::cast(node).unwrap()
@@ -167,7 +79,7 @@ impl Diagnostic for MissingOkInTailExpr {
167impl AstDiagnostic for MissingOkInTailExpr { 79impl AstDiagnostic for MissingOkInTailExpr {
168 type AST = ast::Expr; 80 type AST = ast::Expr;
169 81
170 fn ast(&self, db: &impl HirDatabase) -> Self::AST { 82 fn ast(&self, db: &impl AstDatabase) -> Self::AST {
171 let root = db.parse_or_expand(self.file).unwrap(); 83 let root = db.parse_or_expand(self.file).unwrap();
172 let node = self.source().ast.to_node(&root); 84 let node = self.source().ast.to_node(&root);
173 ast::Expr::cast(node).unwrap() 85 ast::Expr::cast(node).unwrap()
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index c685edda1..3054f1dce 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -3,12 +3,13 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::path::known; 5use hir_def::path::known;
6use hir_expand::diagnostics::DiagnosticSink;
6use ra_syntax::ast; 7use ra_syntax::ast;
7use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
8 9
9use crate::{ 10use crate::{
10 db::HirDatabase, 11 db::HirDatabase,
11 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, 12 diagnostics::{MissingFields, MissingOkInTailExpr},
12 expr::AstPtr, 13 expr::AstPtr,
13 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, 14 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
14 Adt, Function, Name, Path, 15 Adt, Function, Name, Path,
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
new file mode 100644
index 000000000..089dbc908
--- /dev/null
+++ b/crates/ra_hir/src/from_id.rs
@@ -0,0 +1,63 @@
1//! Utility module for converting between hir_def ids and code_model wrappers.
2//!
3//! It's unclear if we need this long-term, but it's definitelly useful while we
4//! are splitting the hir.
5
6use hir_def::{AdtId, EnumVariantId, ModuleDefId};
7
8use crate::{Adt, EnumVariant, ModuleDef};
9
10macro_rules! from_id {
11 ($(($id:path, $ty:path)),*) => {$(
12 impl From<$id> for $ty {
13 fn from(id: $id) -> $ty {
14 $ty { id }
15 }
16 }
17 )*}
18}
19
20from_id![
21 (hir_def::ModuleId, crate::Module),
22 (hir_def::StructId, crate::Struct),
23 (hir_def::UnionId, crate::Union),
24 (hir_def::EnumId, crate::Enum),
25 (hir_def::TypeAliasId, crate::TypeAlias),
26 (hir_def::TraitId, crate::Trait),
27 (hir_def::StaticId, crate::Static),
28 (hir_def::ConstId, crate::Const),
29 (hir_def::FunctionId, crate::Function),
30 (hir_expand::MacroDefId, crate::MacroDef)
31];
32
33impl From<AdtId> for Adt {
34 fn from(id: AdtId) -> Self {
35 match id {
36 AdtId::StructId(it) => Adt::Struct(it.into()),
37 AdtId::UnionId(it) => Adt::Union(it.into()),
38 AdtId::EnumId(it) => Adt::Enum(it.into()),
39 }
40 }
41}
42
43impl From<EnumVariantId> for EnumVariant {
44 fn from(id: EnumVariantId) -> Self {
45 EnumVariant { parent: id.parent.into(), id: id.local_id }
46 }
47}
48
49impl From<ModuleDefId> for ModuleDef {
50 fn from(id: ModuleDefId) -> Self {
51 match id {
52 ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()),
53 ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()),
54 ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()),
55 ModuleDefId::EnumVariantId(it) => ModuleDef::EnumVariant(it.into()),
56 ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()),
57 ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()),
58 ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()),
59 ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()),
60 ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it),
61 }
62 }
63}
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index a9de01455..9899bdbbc 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -149,14 +149,20 @@ impl Module {
149 ModuleSource::SourceFile(_) => None, 149 ModuleSource::SourceFile(_) => None,
150 }; 150 };
151 151
152 db.relevant_crates(src.file_id.original_file(db)) 152 db.relevant_crates(src.file_id.original_file(db)).iter().find_map(|&crate_id| {
153 .iter() 153 let def_map = db.crate_def_map(crate_id);
154 .map(|&crate_id| Crate { crate_id }) 154
155 .find_map(|krate| { 155 let (module_id, _module_data) =
156 let def_map = db.crate_def_map(krate); 156 def_map.modules.iter().find(|(_module_id, module_data)| {
157 let module_id = def_map.find_module_by_source(src.file_id, decl_id)?; 157 if decl_id.is_some() {
158 Some(Module::new(krate, module_id)) 158 module_data.declaration == decl_id
159 }) 159 } else {
160 module_data.definition.map(|it| it.into()) == Some(src.file_id)
161 }
162 })?;
163
164 Some(Module::new(Crate { crate_id }, module_id))
165 })
160 } 166 }
161} 167}
162 168
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 40f5562b4..3ba99d92d 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -34,7 +34,6 @@ pub mod mock;
34pub mod source_binder; 34pub mod source_binder;
35 35
36mod ids; 36mod ids;
37mod nameres;
38mod adt; 37mod adt;
39mod traits; 38mod traits;
40mod type_alias; 39mod type_alias;
@@ -47,6 +46,7 @@ mod resolve;
47pub mod diagnostics; 46pub mod diagnostics;
48mod util; 47mod util;
49 48
49mod from_id;
50mod code_model; 50mod code_model;
51 51
52pub mod from_source; 52pub mod from_source;
@@ -62,7 +62,7 @@ pub use crate::{
62 adt::VariantDef, 62 adt::VariantDef,
63 code_model::{ 63 code_model::{
64 docs::{DocDef, Docs, Documentation}, 64 docs::{DocDef, Docs, Documentation},
65 src::{HasBodySource, HasSource, Source}, 65 src::{HasBodySource, HasSource},
66 Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, 66 Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
67 EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, 67 EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef,
68 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, 68 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
@@ -72,7 +72,6 @@ pub use crate::{
72 generics::{GenericDef, GenericParam, GenericParams, HasGenericParams}, 72 generics::{GenericDef, GenericParam, GenericParams, HasGenericParams},
73 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, 73 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile},
74 impl_block::ImplBlock, 74 impl_block::ImplBlock,
75 nameres::{ImportId, Namespace, PerNs},
76 resolve::ScopeDef, 75 resolve::ScopeDef,
77 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 76 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
78 ty::{ 77 ty::{
@@ -82,7 +81,11 @@ pub use crate::{
82 81
83pub use hir_def::{ 82pub use hir_def::{
84 builtin_type::BuiltinType, 83 builtin_type::BuiltinType,
84 nameres::{
85 per_ns::{Namespace, PerNs},
86 raw::ImportId,
87 },
85 path::{Path, PathKind}, 88 path::{Path, PathKind},
86 type_ref::Mutability, 89 type_ref::Mutability,
87}; 90};
88pub use hir_expand::{either::Either, name::Name}; 91pub use hir_expand::{either::Either, name::Name, Source};
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index b423489a1..0d4fa5b67 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -1,21 +1,10 @@
1//! See test_utils/src/marks.rs 1//! See test_utils/src/marks.rs
2 2
3test_utils::marks!( 3test_utils::marks!(
4 bogus_paths
5 // FIXME: restore this mark once hir is split
6 name_res_works_for_broken_modules
7 can_import_enum_variant
8 type_var_cycles_resolve_completely 4 type_var_cycles_resolve_completely
9 type_var_cycles_resolve_as_possible 5 type_var_cycles_resolve_as_possible
10 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
11 glob_enum
12 glob_across_crates
13 std_prelude
14 match_ergonomics_ref 7 match_ergonomics_ref
15 infer_while_let 8 infer_while_let
16 macro_rules_from_other_crates_are_visible_with_macro_use
17 prelude_is_macro_use
18 coerce_merge_fail_fallback 9 coerce_merge_fail_fallback
19 macro_dollar_crate_self
20 macro_dollar_crate_other
21); 10);
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 35dfaf3ba..ab97a09b9 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -2,17 +2,17 @@
2 2
3use std::{panic, sync::Arc}; 3use std::{panic, sync::Arc};
4 4
5use hir_expand::diagnostics::DiagnosticSink;
5use parking_lot::Mutex; 6use parking_lot::Mutex;
6use ra_cfg::CfgOptions; 7use ra_cfg::CfgOptions;
7use ra_db::{ 8use ra_db::{
8 salsa, CrateGraph, CrateId, Edition, FileId, FileLoader, FileLoaderDelegate, FilePosition, 9 salsa, CrateGraph, CrateId, Edition, FileId, FileLoader, FileLoaderDelegate, FilePosition,
9 SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, 10 RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
10}; 11};
11use relative_path::{RelativePath, RelativePathBuf};
12use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
13use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 13use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
14 14
15use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink}; 15use crate::{db, debug::HirDebugHelper};
16 16
17pub const WORKSPACE: SourceRootId = SourceRootId(0); 17pub const WORKSPACE: SourceRootId = SourceRootId(0);
18 18
@@ -77,12 +77,6 @@ impl MockDatabase {
77 (db, source_root, file_id) 77 (db, source_root, file_id)
78 } 78 }
79 79
80 pub fn with_position(fixture: &str) -> (MockDatabase, FilePosition) {
81 let (db, position) = MockDatabase::from_fixture(fixture);
82 let position = position.expect("expected a marker ( <|> )");
83 (db, position)
84 }
85
86 pub fn file_id_of(&self, path: &str) -> FileId { 80 pub fn file_id_of(&self, path: &str) -> FileId {
87 match self.files.get(path) { 81 match self.files.get(path) {
88 Some(it) => *it, 82 Some(it) => *it,
@@ -90,25 +84,6 @@ impl MockDatabase {
90 } 84 }
91 } 85 }
92 86
93 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) {
94 let mut ids = FxHashMap::default();
95 let mut crate_graph = CrateGraph::default();
96 for (crate_name, (crate_root, edition, cfg_options, _)) in graph.0.iter() {
97 let crate_root = self.file_id_of(&crate_root);
98 let crate_id = crate_graph.add_crate_root(crate_root, *edition, cfg_options.clone());
99 Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone());
100 ids.insert(crate_name, crate_id);
101 }
102 for (crate_name, (_, _, _, deps)) in graph.0.iter() {
103 let from = ids[crate_name];
104 for dep in deps {
105 let to = ids[dep];
106 crate_graph.add_dep(from, dep.as_str().into(), to).unwrap();
107 }
108 }
109 self.set_crate_graph(Arc::new(crate_graph))
110 }
111
112 pub fn diagnostics(&self) -> String { 87 pub fn diagnostics(&self) -> String {
113 let mut buf = String::new(); 88 let mut buf = String::new();
114 let mut files: Vec<FileId> = self.files.values().copied().collect(); 89 let mut files: Vec<FileId> = self.files.values().copied().collect();
@@ -285,46 +260,3 @@ impl MockDatabase {
285 .collect() 260 .collect()
286 } 261 }
287} 262}
288
289#[derive(Default)]
290pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, CfgOptions, Vec<String>))>);
291
292#[macro_export]
293macro_rules! crate_graph {
294 ($(
295 $crate_name:literal: (
296 $crate_path:literal,
297 $($edition:literal,)?
298 [$($dep:literal),*]
299 $(, cfg = {
300 $($key:literal $(= $value:literal)?),*
301 $(,)?
302 })?
303 ),
304 )*) => {{
305 let mut res = $crate::mock::CrateGraphFixture::default();
306 $(
307 #[allow(unused_mut, unused_assignments)]
308 let mut edition = ra_db::Edition::Edition2018;
309 $(edition = ra_db::Edition::from_string($edition);)?
310 let cfg_options = {
311 #[allow(unused_mut)]
312 let mut cfg = ::ra_cfg::CfgOptions::default();
313 $(
314 $(
315 if 0 == 0 $(+ { drop($value); 1})? {
316 cfg.insert_atom($key.into());
317 }
318 $(cfg.insert_key_value($key.into(), $value.into());)?
319 )*
320 )?
321 cfg
322 };
323 res.0.push((
324 $crate_name.to_string(),
325 ($crate_path.to_string(), edition, cfg_options, vec![$($dep.to_string()),*])
326 ));
327 )*
328 res
329 }}
330}
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
deleted file mode 100644
index 7ba031827..000000000
--- a/crates/ra_hir/src/nameres.rs
+++ /dev/null
@@ -1,557 +0,0 @@
1//! This module implements import-resolution/macro expansion algorithm.
2//!
3//! The result of this module is `CrateDefMap`: a data structure which contains:
4//!
5//! * a tree of modules for the crate
6//! * for each module, a set of items visible in the module (directly declared
7//! or imported)
8//!
9//! Note that `CrateDefMap` contains fully macro expanded code.
10//!
11//! Computing `CrateDefMap` can be partitioned into several logically
12//! independent "phases". The phases are mutually recursive though, there's no
13//! strict ordering.
14//!
15//! ## Collecting RawItems
16//!
17//! This happens in the `raw` module, which parses a single source file into a
18//! set of top-level items. Nested imports are desugared to flat imports in
19//! this phase. Macro calls are represented as a triple of (Path, Option<Name>,
20//! TokenTree).
21//!
22//! ## Collecting Modules
23//!
24//! This happens in the `collector` module. In this phase, we recursively walk
25//! tree of modules, collect raw items from submodules, populate module scopes
26//! with defined items (so, we assign item ids in this phase) and record the set
27//! of unresolved imports and macros.
28//!
29//! While we walk tree of modules, we also record macro_rules definitions and
30//! expand calls to macro_rules defined macros.
31//!
32//! ## Resolving Imports
33//!
34//! We maintain a list of currently unresolved imports. On every iteration, we
35//! try to resolve some imports from this list. If the import is resolved, we
36//! record it, by adding an item to current module scope and, if necessary, by
37//! recursively populating glob imports.
38//!
39//! ## Resolving Macros
40//!
41//! macro_rules from the same crate use a global mutable namespace. We expand
42//! them immediately, when we collect modules.
43//!
44//! Macros from other crates (including proc-macros) can be used with
45//! `foo::bar!` syntax. We handle them similarly to imports. There's a list of
46//! unexpanded macros. On every iteration, we try to resolve each macro call
47//! path and, upon success, we run macro expansion and "collect module" phase
48//! on the result
49
50mod per_ns;
51mod collector;
52#[cfg(test)]
53mod tests;
54
55use std::sync::Arc;
56
57use hir_def::{builtin_type::BuiltinType, CrateModuleId};
58use once_cell::sync::Lazy;
59use ra_arena::Arena;
60use ra_db::{Edition, FileId};
61use ra_prof::profile;
62use ra_syntax::ast;
63use rustc_hash::{FxHashMap, FxHashSet};
64use test_utils::tested_by;
65
66use crate::{
67 db::{AstDatabase, DefDatabase},
68 diagnostics::DiagnosticSink,
69 ids::MacroDefId,
70 nameres::diagnostics::DefDiagnostic,
71 Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait,
72};
73
74pub use self::per_ns::{Namespace, PerNs};
75
76pub use hir_def::nameres::raw::ImportId;
77
78/// Contains all top-level defs from a macro-expanded crate
79#[derive(Debug, PartialEq, Eq)]
80pub struct CrateDefMap {
81 krate: Crate,
82 edition: Edition,
83 /// The prelude module for this crate. This either comes from an import
84 /// marked with the `prelude_import` attribute, or (in the normal case) from
85 /// a dependency (`std` or `core`).
86 prelude: Option<Module>,
87 extern_prelude: FxHashMap<Name, ModuleDef>,
88 root: CrateModuleId,
89 modules: Arena<CrateModuleId, ModuleData>,
90
91 /// Some macros are not well-behavior, which leads to infinite loop
92 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
93 /// We mark it down and skip it in collector
94 ///
95 /// FIXME:
96 /// Right now it only handle a poison macro in a single crate,
97 /// such that if other crate try to call that macro,
98 /// the whole process will do again until it became poisoned in that crate.
99 /// We should handle this macro set globally
100 /// However, do we want to put it as a global variable?
101 poison_macros: FxHashSet<MacroDefId>,
102
103 diagnostics: Vec<DefDiagnostic>,
104}
105
106impl std::ops::Index<CrateModuleId> for CrateDefMap {
107 type Output = ModuleData;
108 fn index(&self, id: CrateModuleId) -> &ModuleData {
109 &self.modules[id]
110 }
111}
112
113#[derive(Default, Debug, PartialEq, Eq)]
114pub struct ModuleData {
115 pub(crate) parent: Option<CrateModuleId>,
116 pub(crate) children: FxHashMap<Name, CrateModuleId>,
117 pub(crate) scope: ModuleScope,
118 /// None for root
119 pub(crate) declaration: Option<AstId<ast::Module>>,
120 /// None for inline modules.
121 ///
122 /// Note that non-inline modules, by definition, live inside non-macro file.
123 pub(crate) definition: Option<FileId>,
124}
125
126#[derive(Debug, Default, PartialEq, Eq, Clone)]
127pub struct ModuleScope {
128 items: FxHashMap<Name, Resolution>,
129 /// Macros visable in current module in legacy textual scope
130 ///
131 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
132 /// If it yields no result, then it turns to module scoped `macros`.
133 /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
134 /// and only normal scoped `macros` will be searched in.
135 ///
136 /// Note that this automatically inherit macros defined textually before the definition of module itself.
137 ///
138 /// Module scoped macros will be inserted into `items` instead of here.
139 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
140 // be all resolved to the last one defined if shadowing happens.
141 legacy_macros: FxHashMap<Name, MacroDef>,
142}
143
144static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
145 BuiltinType::ALL
146 .iter()
147 .map(|(name, ty)| {
148 (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
149 })
150 .collect()
151});
152
153/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
154/// Other methods will only resolve values, types and module scoped macros only.
155impl ModuleScope {
156 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
157 //FIXME: shadowing
158 self.items.iter().chain(BUILTIN_SCOPE.iter())
159 }
160
161 /// Iterate over all module scoped macros
162 pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
163 self.items
164 .iter()
165 .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_)))
166 }
167
168 /// Iterate over all legacy textual scoped macros visable at the end of the module
169 pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
170 self.legacy_macros.iter().map(|(name, def)| (name, *def))
171 }
172
173 /// Get a name from current module scope, legacy macros are not included
174 pub fn get(&self, name: &Name) -> Option<&Resolution> {
175 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
176 }
177
178 pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
179 self.items.values().filter_map(|r| match r.def.take_types() {
180 Some(ModuleDef::Trait(t)) => Some(t),
181 _ => None,
182 })
183 }
184
185 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> {
186 self.legacy_macros.get(name).copied()
187 }
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Default)]
191pub struct Resolution {
192 /// None for unresolved
193 pub def: PerNs,
194 /// ident by which this is imported into local scope.
195 pub import: Option<ImportId>,
196}
197
198impl Resolution {
199 pub(crate) fn from_macro(macro_: MacroDef) -> Self {
200 Resolution { def: PerNs::macros(macro_), import: None }
201 }
202}
203
204#[derive(Debug, Clone)]
205struct ResolvePathResult {
206 resolved_def: PerNs,
207 segment_index: Option<usize>,
208 reached_fixedpoint: ReachedFixedPoint,
209}
210
211impl ResolvePathResult {
212 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
213 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
214 }
215
216 fn with(
217 resolved_def: PerNs,
218 reached_fixedpoint: ReachedFixedPoint,
219 segment_index: Option<usize>,
220 ) -> ResolvePathResult {
221 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226enum ResolveMode {
227 Import,
228 Other,
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq)]
232enum ReachedFixedPoint {
233 Yes,
234 No,
235}
236
237impl CrateDefMap {
238 pub(crate) fn crate_def_map_query(
239 // Note that this doesn't have `+ AstDatabase`!
240 // This gurantess that `CrateDefMap` is stable across reparses.
241 db: &impl DefDatabase,
242 krate: Crate,
243 ) -> Arc<CrateDefMap> {
244 let _p = profile("crate_def_map_query");
245 let def_map = {
246 let edition = krate.edition(db);
247 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
248 let root = modules.alloc(ModuleData::default());
249 CrateDefMap {
250 krate,
251 edition,
252 extern_prelude: FxHashMap::default(),
253 prelude: None,
254 root,
255 modules,
256 poison_macros: FxHashSet::default(),
257 diagnostics: Vec::new(),
258 }
259 };
260 let def_map = collector::collect_defs(db, def_map);
261 Arc::new(def_map)
262 }
263
264 pub(crate) fn krate(&self) -> Crate {
265 self.krate
266 }
267
268 pub(crate) fn root(&self) -> CrateModuleId {
269 self.root
270 }
271
272 pub(crate) fn prelude(&self) -> Option<Module> {
273 self.prelude
274 }
275
276 pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> {
277 &self.extern_prelude
278 }
279
280 pub(crate) fn add_diagnostics(
281 &self,
282 db: &(impl DefDatabase + AstDatabase),
283 module: CrateModuleId,
284 sink: &mut DiagnosticSink,
285 ) {
286 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
287 }
288
289 pub(crate) fn find_module_by_source(
290 &self,
291 file_id: HirFileId,
292 decl_id: Option<AstId<ast::Module>>,
293 ) -> Option<CrateModuleId> {
294 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
295 if decl_id.is_some() {
296 module_data.declaration == decl_id
297 } else {
298 module_data.definition.map(|it| it.into()) == Some(file_id)
299 }
300 })?;
301 Some(module_id)
302 }
303
304 pub(crate) fn resolve_path(
305 &self,
306 db: &impl DefDatabase,
307 original_module: CrateModuleId,
308 path: &Path,
309 ) -> (PerNs, Option<usize>) {
310 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
311 (res.resolved_def, res.segment_index)
312 }
313
314 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
315 // the result.
316 fn resolve_path_fp_with_macro(
317 &self,
318 db: &impl DefDatabase,
319 mode: ResolveMode,
320 original_module: CrateModuleId,
321 path: &Path,
322 ) -> ResolvePathResult {
323 let mut segments = path.segments.iter().enumerate();
324 let mut curr_per_ns: PerNs = match path.kind {
325 PathKind::DollarCrate(crate_id) => {
326 let krate = Crate { crate_id };
327 if krate == self.krate {
328 tested_by!(macro_dollar_crate_self);
329 PerNs::types(Module::new(self.krate, self.root).into())
330 } else {
331 match krate.root_module(db) {
332 Some(module) => {
333 tested_by!(macro_dollar_crate_other);
334 PerNs::types(module.into())
335 }
336 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
337 }
338 }
339 }
340 PathKind::Crate => PerNs::types(Module::new(self.krate, self.root).into()),
341 PathKind::Self_ => PerNs::types(Module::new(self.krate, original_module).into()),
342 // plain import or absolute path in 2015: crate-relative with
343 // fallback to extern prelude (with the simplification in
344 // rust-lang/rust#57745)
345 // FIXME there must be a nicer way to write this condition
346 PathKind::Plain | PathKind::Abs
347 if self.edition == Edition::Edition2015
348 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
349 {
350 let segment = match segments.next() {
351 Some((_, segment)) => segment,
352 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
353 };
354 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
355 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
356 }
357 PathKind::Plain => {
358 let segment = match segments.next() {
359 Some((_, segment)) => segment,
360 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
361 };
362 log::debug!("resolving {:?} in module", segment);
363 self.resolve_name_in_module(db, original_module, &segment.name)
364 }
365 PathKind::Super => {
366 if let Some(p) = self.modules[original_module].parent {
367 PerNs::types(Module::new(self.krate, p).into())
368 } else {
369 log::debug!("super path in root module");
370 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
371 }
372 }
373 PathKind::Abs => {
374 // 2018-style absolute path -- only extern prelude
375 let segment = match segments.next() {
376 Some((_, segment)) => segment,
377 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
378 };
379 if let Some(def) = self.extern_prelude.get(&segment.name) {
380 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
381 PerNs::types(*def)
382 } else {
383 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
384 }
385 }
386 PathKind::Type(_) => {
387 // This is handled in `infer::infer_path_expr`
388 // The result returned here does not matter
389 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
390 }
391 };
392
393 for (i, segment) in segments {
394 let curr = match curr_per_ns.take_types() {
395 Some(r) => r,
396 None => {
397 // we still have path segments left, but the path so far
398 // didn't resolve in the types namespace => no resolution
399 // (don't break here because `curr_per_ns` might contain
400 // something in the value namespace, and it would be wrong
401 // to return that)
402 return ResolvePathResult::empty(ReachedFixedPoint::No);
403 }
404 };
405 // resolve segment in curr
406
407 curr_per_ns = match curr {
408 ModuleDef::Module(module) => {
409 if module.krate() != self.krate {
410 let path =
411 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
412 log::debug!("resolving {:?} in other crate", path);
413 let defp_map = db.crate_def_map(module.krate());
414 let (def, s) = defp_map.resolve_path(db, module.id.module_id, &path);
415 return ResolvePathResult::with(
416 def,
417 ReachedFixedPoint::Yes,
418 s.map(|s| s + i),
419 );
420 }
421
422 // Since it is a qualified path here, it should not contains legacy macros
423 match self[module.id.module_id].scope.get(&segment.name) {
424 Some(res) => res.def,
425 _ => {
426 log::debug!("path segment {:?} not found", segment.name);
427 return ResolvePathResult::empty(ReachedFixedPoint::No);
428 }
429 }
430 }
431 ModuleDef::Adt(Adt::Enum(e)) => {
432 // enum variant
433 tested_by!(can_import_enum_variant);
434 match e.variant(db, &segment.name) {
435 Some(variant) => PerNs::both(variant.into(), variant.into()),
436 None => {
437 return ResolvePathResult::with(
438 PerNs::types(e.into()),
439 ReachedFixedPoint::Yes,
440 Some(i),
441 );
442 }
443 }
444 }
445 s => {
446 // could be an inherent method call in UFCS form
447 // (`Struct::method`), or some other kind of associated item
448 log::debug!(
449 "path segment {:?} resolved to non-module {:?}, but is not last",
450 segment.name,
451 curr,
452 );
453
454 return ResolvePathResult::with(
455 PerNs::types(s),
456 ReachedFixedPoint::Yes,
457 Some(i),
458 );
459 }
460 };
461 }
462 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
463 }
464
465 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
466 let from_crate_root =
467 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
468 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
469
470 from_crate_root.or(from_extern_prelude)
471 }
472
473 pub(crate) fn resolve_name_in_module(
474 &self,
475 db: &impl DefDatabase,
476 module: CrateModuleId,
477 name: &Name,
478 ) -> PerNs {
479 // Resolve in:
480 // - legacy scope of macro
481 // - current module / scope
482 // - extern prelude
483 // - std prelude
484 let from_legacy_macro =
485 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
486 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
487 let from_extern_prelude =
488 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
489 let from_prelude = self.resolve_in_prelude(db, name);
490
491 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
492 }
493
494 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
495 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
496 }
497
498 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
499 if let Some(prelude) = self.prelude {
500 let keep;
501 let def_map = if prelude.krate() == self.krate {
502 self
503 } else {
504 // Extend lifetime
505 keep = db.crate_def_map(prelude.krate());
506 &keep
507 };
508 def_map[prelude.id.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
509 } else {
510 PerNs::none()
511 }
512 }
513}
514
515mod diagnostics {
516 use ra_syntax::{ast, AstPtr};
517 use relative_path::RelativePathBuf;
518
519 use crate::{
520 db::{AstDatabase, DefDatabase},
521 diagnostics::{DiagnosticSink, UnresolvedModule},
522 nameres::CrateModuleId,
523 AstId,
524 };
525
526 #[derive(Debug, PartialEq, Eq)]
527 pub(super) enum DefDiagnostic {
528 UnresolvedModule {
529 module: CrateModuleId,
530 declaration: AstId<ast::Module>,
531 candidate: RelativePathBuf,
532 },
533 }
534
535 impl DefDiagnostic {
536 pub(super) fn add_to(
537 &self,
538 db: &(impl DefDatabase + AstDatabase),
539 target_module: CrateModuleId,
540 sink: &mut DiagnosticSink,
541 ) {
542 match self {
543 DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
544 if *module != target_module {
545 return;
546 }
547 let decl = declaration.to_node(db);
548 sink.push(UnresolvedModule {
549 file: declaration.file_id(),
550 decl: AstPtr::new(&decl),
551 candidate: candidate.clone(),
552 })
553 }
554 }
555 }
556 }
557}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 75b24d386..b932b0c8c 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -3,8 +3,9 @@ use std::sync::Arc;
3 3
4use hir_def::{ 4use hir_def::{
5 builtin_type::BuiltinType, 5 builtin_type::BuiltinType,
6 nameres::CrateDefMap,
6 path::{Path, PathKind}, 7 path::{Path, PathKind},
7 CrateModuleId, 8 AdtId, CrateModuleId, ModuleDefId,
8}; 9};
9use hir_expand::name::{self, Name}; 10use hir_expand::name::{self, Name};
10use rustc_hash::FxHashSet; 11use rustc_hash::FxHashSet;
@@ -18,8 +19,8 @@ use crate::{
18 }, 19 },
19 generics::GenericParams, 20 generics::GenericParams,
20 impl_block::ImplBlock, 21 impl_block::ImplBlock,
21 nameres::{CrateDefMap, PerNs}, 22 Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait,
22 Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias, 23 TypeAlias,
23}; 24};
24 25
25#[derive(Debug, Clone, Default)] 26#[derive(Debug, Clone, Default)]
@@ -90,7 +91,7 @@ impl Resolver {
90 pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option<Trait> { 91 pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option<Trait> {
91 let res = self.resolve_module_path(db, path).take_types()?; 92 let res = self.resolve_module_path(db, path).take_types()?;
92 match res { 93 match res {
93 ModuleDef::Trait(it) => Some(it), 94 ModuleDefId::TraitId(it) => Some(it.into()),
94 _ => None, 95 _ => None,
95 } 96 }
96 } 97 }
@@ -103,7 +104,7 @@ impl Resolver {
103 ) -> Option<Struct> { 104 ) -> Option<Struct> {
104 let res = self.resolve_module_path(db, path).take_types()?; 105 let res = self.resolve_module_path(db, path).take_types()?;
105 match res { 106 match res {
106 ModuleDef::Adt(Adt::Struct(it)) => Some(it), 107 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it.into()),
107 _ => None, 108 _ => None,
108 } 109 }
109 } 110 }
@@ -112,7 +113,7 @@ impl Resolver {
112 pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option<Enum> { 113 pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option<Enum> {
113 let res = self.resolve_module_path(db, path).take_types()?; 114 let res = self.resolve_module_path(db, path).take_types()?;
114 match res { 115 match res {
115 ModuleDef::Adt(Adt::Enum(it)) => Some(it), 116 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it.into()),
116 _ => None, 117 _ => None,
117 } 118 }
118 } 119 }
@@ -166,18 +167,18 @@ impl Resolver {
166 Scope::ModuleScope(m) => { 167 Scope::ModuleScope(m) => {
167 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); 168 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
168 let res = match module_def.take_types()? { 169 let res = match module_def.take_types()? {
169 ModuleDef::Adt(it) => TypeNs::Adt(it), 170 ModuleDefId::AdtId(it) => TypeNs::Adt(it.into()),
170 ModuleDef::EnumVariant(it) => TypeNs::EnumVariant(it), 171 ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariant(it.into()),
171 172
172 ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it), 173 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAlias(it.into()),
173 ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it), 174 ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
174 175
175 ModuleDef::Trait(it) => TypeNs::Trait(it), 176 ModuleDefId::TraitId(it) => TypeNs::Trait(it.into()),
176 177
177 ModuleDef::Function(_) 178 ModuleDefId::FunctionId(_)
178 | ModuleDef::Const(_) 179 | ModuleDefId::ConstId(_)
179 | ModuleDef::Static(_) 180 | ModuleDefId::StaticId(_)
180 | ModuleDef::Module(_) => return None, 181 | ModuleDefId::ModuleId(_) => return None,
181 }; 182 };
182 return Some((res, idx)); 183 return Some((res, idx));
183 } 184 }
@@ -261,33 +262,35 @@ impl Resolver {
261 return match idx { 262 return match idx {
262 None => { 263 None => {
263 let value = match module_def.take_values()? { 264 let value = match module_def.take_values()? {
264 ModuleDef::Function(it) => ValueNs::Function(it), 265 ModuleDefId::FunctionId(it) => ValueNs::Function(it.into()),
265 ModuleDef::Adt(Adt::Struct(it)) => ValueNs::Struct(it), 266 ModuleDefId::AdtId(AdtId::StructId(it)) => {
266 ModuleDef::EnumVariant(it) => ValueNs::EnumVariant(it), 267 ValueNs::Struct(it.into())
267 ModuleDef::Const(it) => ValueNs::Const(it), 268 }
268 ModuleDef::Static(it) => ValueNs::Static(it), 269 ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariant(it.into()),
269 270 ModuleDefId::ConstId(it) => ValueNs::Const(it.into()),
270 ModuleDef::Adt(Adt::Enum(_)) 271 ModuleDefId::StaticId(it) => ValueNs::Static(it.into()),
271 | ModuleDef::Adt(Adt::Union(_)) 272
272 | ModuleDef::Trait(_) 273 ModuleDefId::AdtId(AdtId::EnumId(_))
273 | ModuleDef::TypeAlias(_) 274 | ModuleDefId::AdtId(AdtId::UnionId(_))
274 | ModuleDef::BuiltinType(_) 275 | ModuleDefId::TraitId(_)
275 | ModuleDef::Module(_) => return None, 276 | ModuleDefId::TypeAliasId(_)
277 | ModuleDefId::BuiltinType(_)
278 | ModuleDefId::ModuleId(_) => return None,
276 }; 279 };
277 Some(ResolveValueResult::ValueNs(value)) 280 Some(ResolveValueResult::ValueNs(value))
278 } 281 }
279 Some(idx) => { 282 Some(idx) => {
280 let ty = match module_def.take_types()? { 283 let ty = match module_def.take_types()? {
281 ModuleDef::Adt(it) => TypeNs::Adt(it), 284 ModuleDefId::AdtId(it) => TypeNs::Adt(it.into()),
282 ModuleDef::Trait(it) => TypeNs::Trait(it), 285 ModuleDefId::TraitId(it) => TypeNs::Trait(it.into()),
283 ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it), 286 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAlias(it.into()),
284 ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it), 287 ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
285 288
286 ModuleDef::Module(_) 289 ModuleDefId::ModuleId(_)
287 | ModuleDef::Function(_) 290 | ModuleDefId::FunctionId(_)
288 | ModuleDef::EnumVariant(_) 291 | ModuleDefId::EnumVariantId(_)
289 | ModuleDef::Const(_) 292 | ModuleDefId::ConstId(_)
290 | ModuleDef::Static(_) => return None, 293 | ModuleDefId::StaticId(_) => return None,
291 }; 294 };
292 Some(ResolveValueResult::Partial(ty, idx)) 295 Some(ResolveValueResult::Partial(ty, idx))
293 } 296 }
@@ -315,7 +318,7 @@ impl Resolver {
315 path: &Path, 318 path: &Path,
316 ) -> Option<MacroDef> { 319 ) -> Option<MacroDef> {
317 let (item_map, module) = self.module()?; 320 let (item_map, module) = self.module()?;
318 item_map.resolve_path(db, module, path).0.get_macros() 321 item_map.resolve_path(db, module, path).0.get_macros().map(MacroDef::from)
319 } 322 }
320 323
321 pub(crate) fn process_all_names( 324 pub(crate) fn process_all_names(
@@ -333,10 +336,11 @@ impl Resolver {
333 for scope in &self.scopes { 336 for scope in &self.scopes {
334 if let Scope::ModuleScope(m) = scope { 337 if let Scope::ModuleScope(m) = scope {
335 if let Some(prelude) = m.crate_def_map.prelude() { 338 if let Some(prelude) = m.crate_def_map.prelude() {
336 let prelude_def_map = db.crate_def_map(prelude.krate()); 339 let prelude_def_map = db.crate_def_map(prelude.krate);
337 traits.extend(prelude_def_map[prelude.id.module_id].scope.traits()); 340 traits
341 .extend(prelude_def_map[prelude.module_id].scope.traits().map(Trait::from));
338 } 342 }
339 traits.extend(m.crate_def_map[m.module_id].scope.traits()); 343 traits.extend(m.crate_def_map[m.module_id].scope.traits().map(Trait::from));
340 } 344 }
341 } 345 }
342 traits 346 traits
@@ -351,7 +355,7 @@ impl Resolver {
351 } 355 }
352 356
353 pub(crate) fn krate(&self) -> Option<Crate> { 357 pub(crate) fn krate(&self) -> Option<Crate> {
354 self.module().map(|t| t.0.krate()) 358 self.module().map(|t| Crate { crate_id: t.0.krate() })
355 } 359 }
356 360
357 pub(crate) fn where_predicates_in_scope<'a>( 361 pub(crate) fn where_predicates_in_scope<'a>(
@@ -420,8 +424,10 @@ impl From<PerNs> for ScopeDef {
420 fn from(def: PerNs) -> Self { 424 fn from(def: PerNs) -> Self {
421 def.take_types() 425 def.take_types()
422 .or_else(|| def.take_values()) 426 .or_else(|| def.take_values())
423 .map(ScopeDef::ModuleDef) 427 .map(|module_def_id| ScopeDef::ModuleDef(module_def_id.into()))
424 .or_else(|| def.get_macros().map(ScopeDef::MacroDef)) 428 .or_else(|| {
429 def.get_macros().map(|macro_def_id| ScopeDef::MacroDef(macro_def_id.into()))
430 })
425 .unwrap_or(ScopeDef::Unknown) 431 .unwrap_or(ScopeDef::Unknown)
426 } 432 }
427} 433}
@@ -441,18 +447,16 @@ impl Scope {
441 f(name.clone(), res.def.into()); 447 f(name.clone(), res.def.into());
442 }); 448 });
443 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { 449 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
444 f(name.clone(), ScopeDef::MacroDef(macro_)); 450 f(name.clone(), ScopeDef::MacroDef(macro_.into()));
445 }); 451 });
446 m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { 452 m.crate_def_map.extern_prelude().iter().for_each(|(name, &def)| {
447 f(name.clone(), ScopeDef::ModuleDef(*def)); 453 f(name.clone(), ScopeDef::ModuleDef(def.into()));
448 }); 454 });
449 if let Some(prelude) = m.crate_def_map.prelude() { 455 if let Some(prelude) = m.crate_def_map.prelude() {
450 let prelude_def_map = db.crate_def_map(prelude.krate()); 456 let prelude_def_map = db.crate_def_map(prelude.krate);
451 prelude_def_map[prelude.id.module_id].scope.entries().for_each( 457 prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| {
452 |(name, res)| { 458 f(name.clone(), res.def.into());
453 f(name.clone(), res.def.into()); 459 });
454 },
455 );
456 } 460 }
457 } 461 }
458 Scope::GenericParams(gp) => { 462 Scope::GenericParams(gp) => {
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index a4ca59bba..66cb4b357 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -253,8 +253,11 @@ impl SourceAnalyzer {
253 Some(res) 253 Some(res)
254 }); 254 });
255 255
256 let items = 256 let items = self
257 self.resolver.resolve_module_path(db, &path).take_types().map(PathResolution::Def); 257 .resolver
258 .resolve_module_path(db, &path)
259 .take_types()
260 .map(|it| PathResolution::Def(it.into()));
258 types.or(values).or(items).or_else(|| { 261 types.or(values).or(items).or_else(|| {
259 self.resolver.resolve_path_as_macro(db, &path).map(|def| PathResolution::Macro(def)) 262 self.resolver.resolve_path_as_macro(db, &path).map(|def| PathResolution::Macro(def))
260 }) 263 })
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 6694467a3..2370e8d4f 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -25,7 +25,7 @@ use hir_def::{
25 path::known, 25 path::known,
26 type_ref::{Mutability, TypeRef}, 26 type_ref::{Mutability, TypeRef},
27}; 27};
28use hir_expand::name; 28use hir_expand::{diagnostics::DiagnosticSink, name};
29use ra_arena::map::ArenaMap; 29use ra_arena::map::ArenaMap;
30use ra_prof::profile; 30use ra_prof::profile;
31use test_utils::tested_by; 31use test_utils::tested_by;
@@ -40,7 +40,6 @@ use crate::{
40 adt::VariantDef, 40 adt::VariantDef,
41 code_model::TypeAlias, 41 code_model::TypeAlias,
42 db::HirDatabase, 42 db::HirDatabase,
43 diagnostics::DiagnosticSink,
44 expr::{BindingAnnotation, Body, ExprId, PatId}, 43 expr::{BindingAnnotation, Body, ExprId, PatId},
45 resolve::{Resolver, TypeNs}, 44 resolve::{Resolver, TypeNs},
46 ty::infer::diagnostics::InferenceDiagnostic, 45 ty::infer::diagnostics::InferenceDiagnostic,
@@ -719,12 +718,9 @@ impl Expectation {
719} 718}
720 719
721mod diagnostics { 720mod diagnostics {
722 use crate::{ 721 use hir_expand::diagnostics::DiagnosticSink;
723 db::HirDatabase, 722
724 diagnostics::{DiagnosticSink, NoSuchField}, 723 use crate::{db::HirDatabase, diagnostics::NoSuchField, expr::ExprId, Function, HasSource};
725 expr::ExprId,
726 Function, HasSource,
727 };
728 724
729 #[derive(Debug, PartialEq, Eq, Clone)] 725 #[derive(Debug, PartialEq, Eq, Clone)]
730 pub(super) enum InferenceDiagnostic { 726 pub(super) enum InferenceDiagnostic {
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs
index fed52df39..a09ef5c5d 100644
--- a/crates/ra_hir/src/ty/infer/expr.rs
+++ b/crates/ra_hir/src/ty/infer/expr.rs
@@ -11,12 +11,11 @@ use crate::{
11 db::HirDatabase, 11 db::HirDatabase,
12 expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 12 expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
13 generics::{GenericParams, HasGenericParams}, 13 generics::{GenericParams, HasGenericParams},
14 nameres::Namespace,
15 ty::{ 14 ty::{
16 autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation, 15 autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation,
17 ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 16 ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
18 }, 17 },
19 Adt, Name, 18 Adt, Name, Namespace,
20}; 19};
21 20
22impl<'a, D: HirDatabase> InferenceContext<'a, D> { 21impl<'a, D: HirDatabase> InferenceContext<'a, D> {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 8e2834307..e29ab8492 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -23,15 +23,14 @@ use crate::{
23 db::HirDatabase, 23 db::HirDatabase,
24 generics::HasGenericParams, 24 generics::HasGenericParams,
25 generics::{GenericDef, WherePredicate}, 25 generics::{GenericDef, WherePredicate},
26 nameres::Namespace,
27 resolve::{Resolver, TypeNs}, 26 resolve::{Resolver, TypeNs},
28 ty::{ 27 ty::{
29 primitive::{FloatTy, IntTy}, 28 primitive::{FloatTy, IntTy},
30 Adt, 29 Adt,
31 }, 30 },
32 util::make_mut_slice, 31 util::make_mut_slice,
33 Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, Trait, 32 Const, Enum, EnumVariant, Function, ModuleDef, Namespace, Path, Static, Struct, StructField,
34 TypeAlias, Union, 33 Trait, TypeAlias, Union,
35}; 34};
36 35
37impl Ty { 36impl Ty {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index bfef48b16..4b7e34878 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2,8 +2,7 @@ use std::fmt::Write;
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use insta::assert_snapshot; 4use insta::assert_snapshot;
5 5use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
6use ra_db::{salsa::Database, FilePosition, SourceDatabase};
7use ra_syntax::{ 6use ra_syntax::{
8 algo, 7 algo,
9 ast::{self, AstNode}, 8 ast::{self, AstNode},
@@ -25,9 +24,9 @@ mod coercion;
25 24
26#[test] 25#[test]
27fn cfg_impl_block() { 26fn cfg_impl_block() {
28 let (mut db, pos) = MockDatabase::with_position( 27 let (db, pos) = MockDatabase::with_position(
29 r#" 28 r#"
30//- /main.rs 29//- /main.rs crate:main deps:foo cfg:test
31use foo::S as T; 30use foo::S as T;
32struct S; 31struct S;
33 32
@@ -46,7 +45,7 @@ fn test() {
46 t<|>; 45 t<|>;
47} 46}
48 47
49//- /foo.rs 48//- /foo.rs crate:foo
50struct S; 49struct S;
51 50
52#[cfg(not(test))] 51#[cfg(not(test))]
@@ -60,18 +59,14 @@ impl S {
60} 59}
61"#, 60"#,
62 ); 61 );
63 db.set_crate_graph_from_fixture(crate_graph! {
64 "main": ("/main.rs", ["foo"], cfg = { "test" }),
65 "foo": ("/foo.rs", []),
66 });
67 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos)); 62 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
68} 63}
69 64
70#[test] 65#[test]
71fn infer_await() { 66fn infer_await() {
72 let (mut db, pos) = MockDatabase::with_position( 67 let (db, pos) = MockDatabase::with_position(
73 r#" 68 r#"
74//- /main.rs 69//- /main.rs crate:main deps:std
75 70
76struct IntFuture; 71struct IntFuture;
77 72
@@ -85,7 +80,7 @@ fn test() {
85 v<|>; 80 v<|>;
86} 81}
87 82
88//- /std.rs 83//- /std.rs crate:std
89#[prelude_import] use future::*; 84#[prelude_import] use future::*;
90mod future { 85mod future {
91 trait Future { 86 trait Future {
@@ -95,18 +90,14 @@ mod future {
95 90
96"#, 91"#,
97 ); 92 );
98 db.set_crate_graph_from_fixture(crate_graph! {
99 "main": ("/main.rs", ["std"]),
100 "std": ("/std.rs", []),
101 });
102 assert_eq!("u64", type_at_pos(&db, pos)); 93 assert_eq!("u64", type_at_pos(&db, pos));
103} 94}
104 95
105#[test] 96#[test]
106fn infer_box() { 97fn infer_box() {
107 let (mut db, pos) = MockDatabase::with_position( 98 let (db, pos) = MockDatabase::with_position(
108 r#" 99 r#"
109//- /main.rs 100//- /main.rs crate:main deps:std
110 101
111fn test() { 102fn test() {
112 let x = box 1; 103 let x = box 1;
@@ -114,7 +105,7 @@ fn test() {
114 t<|>; 105 t<|>;
115} 106}
116 107
117//- /std.rs 108//- /std.rs crate:std
118#[prelude_import] use prelude::*; 109#[prelude_import] use prelude::*;
119mod prelude {} 110mod prelude {}
120 111
@@ -126,10 +117,6 @@ mod boxed {
126 117
127"#, 118"#,
128 ); 119 );
129 db.set_crate_graph_from_fixture(crate_graph! {
130 "main": ("/main.rs", ["std"]),
131 "std": ("/std.rs", []),
132 });
133 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos)); 120 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos));
134} 121}
135 122
@@ -154,9 +141,9 @@ fn test() {
154 141
155#[test] 142#[test]
156fn infer_try() { 143fn infer_try() {
157 let (mut db, pos) = MockDatabase::with_position( 144 let (db, pos) = MockDatabase::with_position(
158 r#" 145 r#"
159//- /main.rs 146//- /main.rs crate:main deps:std
160 147
161fn test() { 148fn test() {
162 let r: Result<i32, u64> = Result::Ok(1); 149 let r: Result<i32, u64> = Result::Ok(1);
@@ -164,7 +151,7 @@ fn test() {
164 v<|>; 151 v<|>;
165} 152}
166 153
167//- /std.rs 154//- /std.rs crate:std
168 155
169#[prelude_import] use ops::*; 156#[prelude_import] use ops::*;
170mod ops { 157mod ops {
@@ -189,18 +176,14 @@ mod result {
189 176
190"#, 177"#,
191 ); 178 );
192 db.set_crate_graph_from_fixture(crate_graph! {
193 "main": ("/main.rs", ["std"]),
194 "std": ("/std.rs", []),
195 });
196 assert_eq!("i32", type_at_pos(&db, pos)); 179 assert_eq!("i32", type_at_pos(&db, pos));
197} 180}
198 181
199#[test] 182#[test]
200fn infer_for_loop() { 183fn infer_for_loop() {
201 let (mut db, pos) = MockDatabase::with_position( 184 let (db, pos) = MockDatabase::with_position(
202 r#" 185 r#"
203//- /main.rs 186//- /main.rs crate:main deps:std
204 187
205use std::collections::Vec; 188use std::collections::Vec;
206 189
@@ -212,7 +195,7 @@ fn test() {
212 } 195 }
213} 196}
214 197
215//- /std.rs 198//- /std.rs crate:std
216 199
217#[prelude_import] use iter::*; 200#[prelude_import] use iter::*;
218mod iter { 201mod iter {
@@ -234,10 +217,6 @@ mod collections {
234} 217}
235"#, 218"#,
236 ); 219 );
237 db.set_crate_graph_from_fixture(crate_graph! {
238 "main": ("/main.rs", ["std"]),
239 "std": ("/std.rs", []),
240 });
241 assert_eq!("&str", type_at_pos(&db, pos)); 220 assert_eq!("&str", type_at_pos(&db, pos));
242} 221}
243 222
@@ -2505,15 +2484,15 @@ pub fn main_loop() {
2505 2484
2506#[test] 2485#[test]
2507fn cross_crate_associated_method_call() { 2486fn cross_crate_associated_method_call() {
2508 let (mut db, pos) = MockDatabase::with_position( 2487 let (db, pos) = MockDatabase::with_position(
2509 r#" 2488 r#"
2510//- /main.rs 2489//- /main.rs crate:main deps:other_crate
2511fn test() { 2490fn test() {
2512 let x = other_crate::foo::S::thing(); 2491 let x = other_crate::foo::S::thing();
2513 x<|>; 2492 x<|>;
2514} 2493}
2515 2494
2516//- /lib.rs 2495//- /lib.rs crate:other_crate
2517mod foo { 2496mod foo {
2518 struct S; 2497 struct S;
2519 impl S { 2498 impl S {
@@ -2522,10 +2501,6 @@ mod foo {
2522} 2501}
2523"#, 2502"#,
2524 ); 2503 );
2525 db.set_crate_graph_from_fixture(crate_graph! {
2526 "main": ("/main.rs", ["other_crate"]),
2527 "other_crate": ("/lib.rs", []),
2528 });
2529 assert_eq!("i128", type_at_pos(&db, pos)); 2504 assert_eq!("i128", type_at_pos(&db, pos));
2530} 2505}
2531 2506
@@ -3403,16 +3378,15 @@ fn test() { S.foo()<|>; }
3403 3378
3404#[test] 3379#[test]
3405fn infer_macro_with_dollar_crate_is_correct_in_expr() { 3380fn infer_macro_with_dollar_crate_is_correct_in_expr() {
3406 covers!(macro_dollar_crate_other); 3381 let (db, pos) = MockDatabase::with_position(
3407 let (mut db, pos) = MockDatabase::with_position(
3408 r#" 3382 r#"
3409//- /main.rs 3383//- /main.rs crate:main deps:foo
3410fn test() { 3384fn test() {
3411 let x = (foo::foo!(1), foo::foo!(2)); 3385 let x = (foo::foo!(1), foo::foo!(2));
3412 x<|>; 3386 x<|>;
3413} 3387}
3414 3388
3415//- /lib.rs 3389//- /lib.rs crate:foo
3416#[macro_export] 3390#[macro_export]
3417macro_rules! foo { 3391macro_rules! foo {
3418 (1) => { $crate::bar!() }; 3392 (1) => { $crate::bar!() };
@@ -3427,10 +3401,6 @@ macro_rules! bar {
3427pub fn baz() -> usize { 31usize } 3401pub fn baz() -> usize { 31usize }
3428"#, 3402"#,
3429 ); 3403 );
3430 db.set_crate_graph_from_fixture(crate_graph! {
3431 "main": ("/main.rs", ["foo"]),
3432 "foo": ("/lib.rs", []),
3433 });
3434 assert_eq!("(i32, usize)", type_at_pos(&db, pos)); 3404 assert_eq!("(i32, usize)", type_at_pos(&db, pos));
3435} 3405}
3436 3406
@@ -3512,9 +3482,9 @@ fn test() { (&S).foo()<|>; }
3512 3482
3513#[test] 3483#[test]
3514fn method_resolution_trait_from_prelude() { 3484fn method_resolution_trait_from_prelude() {
3515 let (mut db, pos) = MockDatabase::with_position( 3485 let (db, pos) = MockDatabase::with_position(
3516 r#" 3486 r#"
3517//- /main.rs 3487//- /main.rs crate:main deps:other_crate
3518struct S; 3488struct S;
3519impl Clone for S {} 3489impl Clone for S {}
3520 3490
@@ -3522,7 +3492,7 @@ fn test() {
3522 S.clone()<|>; 3492 S.clone()<|>;
3523} 3493}
3524 3494
3525//- /lib.rs 3495//- /lib.rs crate:other_crate
3526#[prelude_import] use foo::*; 3496#[prelude_import] use foo::*;
3527 3497
3528mod foo { 3498mod foo {
@@ -3532,10 +3502,6 @@ mod foo {
3532} 3502}
3533"#, 3503"#,
3534 ); 3504 );
3535 db.set_crate_graph_from_fixture(crate_graph! {
3536 "main": ("/main.rs", ["other_crate"]),
3537 "other_crate": ("/lib.rs", []),
3538 });
3539 assert_eq!("S", type_at_pos(&db, pos)); 3505 assert_eq!("S", type_at_pos(&db, pos));
3540} 3506}
3541 3507
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index 746c907e8..21262be79 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -7,7 +7,6 @@ authors = ["rust-analyzer developers"]
7[dependencies] 7[dependencies]
8log = "0.4.5" 8log = "0.4.5"
9once_cell = "1.0.1" 9once_cell = "1.0.1"
10relative-path = "1.0.0"
11rustc-hash = "1.0" 10rustc-hash = "1.0"
12 11
13ra_arena = { path = "../ra_arena" } 12ra_arena = { path = "../ra_arena" }
@@ -19,3 +18,6 @@ test_utils = { path = "../test_utils" }
19mbe = { path = "../ra_mbe", package = "ra_mbe" } 18mbe = { path = "../ra_mbe", package = "ra_mbe" }
20ra_cfg = { path = "../ra_cfg" } 19ra_cfg = { path = "../ra_cfg" }
21tt = { path = "../ra_tt", package = "ra_tt" } 20tt = { path = "../ra_tt", package = "ra_tt" }
21
22[dev-dependencies]
23insta = "0.12.0"
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 22bd469f0..8f41e55d2 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -8,7 +8,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
8 8
9use crate::{ 9use crate::{
10 db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId, 10 db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId,
11 LocalStructFieldId, StructId, 11 LocalStructFieldId, StructId, UnionId,
12}; 12};
13 13
14/// Note that we use `StructData` for unions as well! 14/// Note that we use `StructData` for unions as well!
@@ -56,6 +56,13 @@ impl StructData {
56 let variant_data = Arc::new(variant_data); 56 let variant_data = Arc::new(variant_data);
57 Arc::new(StructData { name, variant_data }) 57 Arc::new(StructData { name, variant_data })
58 } 58 }
59 pub(crate) fn union_data_query(db: &impl DefDatabase2, struct_: UnionId) -> Arc<StructData> {
60 let src = struct_.source(db);
61 let name = src.ast.name().map(|n| n.as_name());
62 let variant_data = VariantData::new(src.ast.kind());
63 let variant_data = Arc::new(variant_data);
64 Arc::new(StructData { name, variant_data })
65 }
59} 66}
60 67
61impl EnumData { 68impl EnumData {
@@ -74,6 +81,11 @@ impl EnumData {
74 .collect(); 81 .collect();
75 Arc::new(EnumData { name, variants }) 82 Arc::new(EnumData { name, variants })
76 } 83 }
84
85 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
86 let (id, _) = self.variants.iter().find(|(_id, data)| data.name.as_ref() == Some(name))?;
87 Some(id)
88 }
77} 89}
78 90
79impl VariantData { 91impl VariantData {
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index f6027013f..a42348101 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -2,13 +2,16 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use hir_expand::{db::AstDatabase, HirFileId}; 4use hir_expand::{db::AstDatabase, HirFileId};
5use ra_db::{salsa, SourceDatabase}; 5use ra_db::{salsa, CrateId, SourceDatabase};
6use ra_syntax::ast; 6use ra_syntax::ast;
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
10 nameres::raw::{ImportSourceMap, RawItems}, 10 nameres::{
11 EnumId, StructId, 11 raw::{ImportSourceMap, RawItems},
12 CrateDefMap,
13 },
14 EnumId, StructId, UnionId,
12}; 15};
13 16
14#[salsa::query_group(InternDatabaseStorage)] 17#[salsa::query_group(InternDatabaseStorage)]
@@ -42,9 +45,15 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
42 #[salsa::invoke(RawItems::raw_items_query)] 45 #[salsa::invoke(RawItems::raw_items_query)]
43 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; 46 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
44 47
48 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
49 fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;
50
45 #[salsa::invoke(StructData::struct_data_query)] 51 #[salsa::invoke(StructData::struct_data_query)]
46 fn struct_data(&self, s: StructId) -> Arc<StructData>; 52 fn struct_data(&self, s: StructId) -> Arc<StructData>;
47 53
54 #[salsa::invoke(StructData::union_data_query)]
55 fn union_data(&self, s: UnionId) -> Arc<StructData>;
56
48 #[salsa::invoke(EnumData::enum_data_query)] 57 #[salsa::invoke(EnumData::enum_data_query)]
49 fn enum_data(&self, e: EnumId) -> Arc<EnumData>; 58 fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
50} 59}
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs
new file mode 100644
index 000000000..9843009a5
--- /dev/null
+++ b/crates/ra_hir_def/src/diagnostics.rs
@@ -0,0 +1,28 @@
1//! Diagnostics produced by `hir_def`.
2
3use std::any::Any;
4
5use hir_expand::diagnostics::Diagnostic;
6use ra_db::RelativePathBuf;
7use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
8
9use hir_expand::{HirFileId, Source};
10
11#[derive(Debug)]
12pub struct UnresolvedModule {
13 pub file: HirFileId,
14 pub decl: AstPtr<ast::Module>,
15 pub candidate: RelativePathBuf,
16}
17
18impl Diagnostic for UnresolvedModule {
19 fn message(&self) -> String {
20 "unresolved module".to_string()
21 }
22 fn source(&self) -> Source<SyntaxNodePtr> {
23 Source { file_id: self.file, ast: self.decl.into() }
24 }
25 fn as_any(&self) -> &(dyn Any + Send + 'static) {
26 self
27 }
28}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 76d5f1852..63ed2a098 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -13,25 +13,25 @@ pub mod path;
13pub mod type_ref; 13pub mod type_ref;
14pub mod builtin_type; 14pub mod builtin_type;
15pub mod adt; 15pub mod adt;
16pub mod diagnostics;
17
18#[cfg(test)]
19mod test_db;
20#[cfg(test)]
21mod marks;
16 22
17// FIXME: this should be private 23// FIXME: this should be private
18pub mod nameres; 24pub mod nameres;
19 25
20use std::hash::{Hash, Hasher}; 26use std::hash::{Hash, Hasher};
21 27
22use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; 28use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, Source};
23use ra_arena::{impl_arena_id, RawId}; 29use ra_arena::{impl_arena_id, RawId};
24use ra_db::{salsa, CrateId, FileId}; 30use ra_db::{salsa, CrateId, FileId};
25use ra_syntax::{ast, AstNode, SyntaxNode}; 31use ra_syntax::{ast, AstNode, SyntaxNode};
26 32
27use crate::{builtin_type::BuiltinType, db::InternDatabase}; 33use crate::{builtin_type::BuiltinType, db::InternDatabase};
28 34
29#[derive(Debug, PartialEq, Eq, Clone, Copy)]
30pub struct Source<T> {
31 pub file_id: HirFileId,
32 pub ast: T,
33}
34
35pub enum ModuleSource { 35pub enum ModuleSource {
36 SourceFile(ast::SourceFile), 36 SourceFile(ast::SourceFile),
37 Module(ast::Module), 37 Module(ast::Module),
@@ -94,15 +94,6 @@ impl ModuleSource {
94 } 94 }
95} 95}
96 96
97impl<T> Source<T> {
98 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
99 Source { file_id: self.file_id, ast: f(self.ast) }
100 }
101 pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
102 db.parse_or_expand(self.file_id).expect("source created from invalid file")
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 97#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
107pub struct ModuleId { 98pub struct ModuleId {
108 pub krate: CrateId, 99 pub krate: CrateId,
@@ -252,8 +243,8 @@ impl AstItemDef<ast::EnumDef> for EnumId {
252// FIXME: rename to `VariantId`, only enums can ave variants 243// FIXME: rename to `VariantId`, only enums can ave variants
253#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 244#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
254pub struct EnumVariantId { 245pub struct EnumVariantId {
255 parent: EnumId, 246 pub parent: EnumId,
256 local_id: LocalEnumVariantId, 247 pub local_id: LocalEnumVariantId,
257} 248}
258 249
259#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 250#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs
new file mode 100644
index 000000000..0b99eac71
--- /dev/null
+++ b/crates/ra_hir_def/src/marks.rs
@@ -0,0 +1,14 @@
1//! See test_utils/src/marks.rs
2
3test_utils::marks!(
4 bogus_paths
5 name_res_works_for_broken_modules
6 can_import_enum_variant
7 glob_enum
8 glob_across_crates
9 std_prelude
10 macro_rules_from_other_crates_are_visible_with_macro_use
11 prelude_is_macro_use
12 macro_dollar_crate_self
13 macro_dollar_crate_other
14);
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 11ba8a777..433bdde48 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -1,5 +1,543 @@
1//! FIXME: write short doc here 1//! This module implements import-resolution/macro expansion algorithm.
2//!
3//! The result of this module is `CrateDefMap`: a data structure which contains:
4//!
5//! * a tree of modules for the crate
6//! * for each module, a set of items visible in the module (directly declared
7//! or imported)
8//!
9//! Note that `CrateDefMap` contains fully macro expanded code.
10//!
11//! Computing `CrateDefMap` can be partitioned into several logically
12//! independent "phases". The phases are mutually recursive though, there's no
13//! strict ordering.
14//!
15//! ## Collecting RawItems
16//!
17//! This happens in the `raw` module, which parses a single source file into a
18//! set of top-level items. Nested imports are desugared to flat imports in
19//! this phase. Macro calls are represented as a triple of (Path, Option<Name>,
20//! TokenTree).
21//!
22//! ## Collecting Modules
23//!
24//! This happens in the `collector` module. In this phase, we recursively walk
25//! tree of modules, collect raw items from submodules, populate module scopes
26//! with defined items (so, we assign item ids in this phase) and record the set
27//! of unresolved imports and macros.
28//!
29//! While we walk tree of modules, we also record macro_rules definitions and
30//! expand calls to macro_rules defined macros.
31//!
32//! ## Resolving Imports
33//!
34//! We maintain a list of currently unresolved imports. On every iteration, we
35//! try to resolve some imports from this list. If the import is resolved, we
36//! record it, by adding an item to current module scope and, if necessary, by
37//! recursively populating glob imports.
38//!
39//! ## Resolving Macros
40//!
41//! macro_rules from the same crate use a global mutable namespace. We expand
42//! them immediately, when we collect modules.
43//!
44//! Macros from other crates (including proc-macros) can be used with
45//! `foo::bar!` syntax. We handle them similarly to imports. There's a list of
46//! unexpanded macros. On every iteration, we try to resolve each macro call
47//! path and, upon success, we run macro expansion and "collect module" phase
48//! on the result
2 49
3// FIXME: review privacy of submodules 50// FIXME: review privacy of submodules
4pub mod raw; 51pub mod raw;
52pub mod per_ns;
53pub mod collector;
5pub mod mod_resolution; 54pub mod mod_resolution;
55
56#[cfg(test)]
57mod tests;
58
59use std::sync::Arc;
60
61use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId};
62use once_cell::sync::Lazy;
63use ra_arena::Arena;
64use ra_db::{CrateId, Edition, FileId};
65use ra_prof::profile;
66use ra_syntax::ast;
67use rustc_hash::{FxHashMap, FxHashSet};
68use test_utils::tested_by;
69
70use crate::{
71 builtin_type::BuiltinType,
72 db::DefDatabase2,
73 nameres::{diagnostics::DefDiagnostic, per_ns::PerNs, raw::ImportId},
74 path::{Path, PathKind},
75 AdtId, AstId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, TraitId,
76};
77
78/// Contains all top-level defs from a macro-expanded crate
79#[derive(Debug, PartialEq, Eq)]
80pub struct CrateDefMap {
81 krate: CrateId,
82 edition: Edition,
83 /// The prelude module for this crate. This either comes from an import
84 /// marked with the `prelude_import` attribute, or (in the normal case) from
85 /// a dependency (`std` or `core`).
86 prelude: Option<ModuleId>,
87 extern_prelude: FxHashMap<Name, ModuleDefId>,
88 root: CrateModuleId,
89 pub modules: Arena<CrateModuleId, ModuleData>,
90
91 /// Some macros are not well-behavior, which leads to infinite loop
92 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
93 /// We mark it down and skip it in collector
94 ///
95 /// FIXME:
96 /// Right now it only handle a poison macro in a single crate,
97 /// such that if other crate try to call that macro,
98 /// the whole process will do again until it became poisoned in that crate.
99 /// We should handle this macro set globally
100 /// However, do we want to put it as a global variable?
101 poison_macros: FxHashSet<MacroDefId>,
102
103 diagnostics: Vec<DefDiagnostic>,
104}
105
106impl std::ops::Index<CrateModuleId> for CrateDefMap {
107 type Output = ModuleData;
108 fn index(&self, id: CrateModuleId) -> &ModuleData {
109 &self.modules[id]
110 }
111}
112
113#[derive(Default, Debug, PartialEq, Eq)]
114pub struct ModuleData {
115 pub parent: Option<CrateModuleId>,
116 pub children: FxHashMap<Name, CrateModuleId>,
117 pub scope: ModuleScope,
118 /// None for root
119 pub declaration: Option<AstId<ast::Module>>,
120 /// None for inline modules.
121 ///
122 /// Note that non-inline modules, by definition, live inside non-macro file.
123 pub definition: Option<FileId>,
124}
125
126#[derive(Debug, Default, PartialEq, Eq, Clone)]
127pub struct ModuleScope {
128 pub items: FxHashMap<Name, Resolution>,
129 /// Macros visable in current module in legacy textual scope
130 ///
131 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
132 /// If it yields no result, then it turns to module scoped `macros`.
133 /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
134 /// and only normal scoped `macros` will be searched in.
135 ///
136 /// Note that this automatically inherit macros defined textually before the definition of module itself.
137 ///
138 /// Module scoped macros will be inserted into `items` instead of here.
139 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
140 // be all resolved to the last one defined if shadowing happens.
141 legacy_macros: FxHashMap<Name, MacroDefId>,
142}
143
144static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
145 BuiltinType::ALL
146 .iter()
147 .map(|(name, ty)| {
148 (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
149 })
150 .collect()
151});
152
153/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
154/// Other methods will only resolve values, types and module scoped macros only.
155impl ModuleScope {
156 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
157 //FIXME: shadowing
158 self.items.iter().chain(BUILTIN_SCOPE.iter())
159 }
160
161 /// Iterate over all module scoped macros
162 pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
163 self.items
164 .iter()
165 .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_)))
166 }
167
168 /// Iterate over all legacy textual scoped macros visable at the end of the module
169 pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
170 self.legacy_macros.iter().map(|(name, def)| (name, *def))
171 }
172
173 /// Get a name from current module scope, legacy macros are not included
174 pub fn get(&self, name: &Name) -> Option<&Resolution> {
175 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
176 }
177
178 pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
179 self.items.values().filter_map(|r| match r.def.take_types() {
180 Some(ModuleDefId::TraitId(t)) => Some(t),
181 _ => None,
182 })
183 }
184
185 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
186 self.legacy_macros.get(name).copied()
187 }
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Default)]
191pub struct Resolution {
192 /// None for unresolved
193 pub def: PerNs,
194 /// ident by which this is imported into local scope.
195 pub import: Option<ImportId>,
196}
197
198impl Resolution {
199 pub(crate) fn from_macro(macro_: MacroDefId) -> Self {
200 Resolution { def: PerNs::macros(macro_), import: None }
201 }
202}
203
204#[derive(Debug, Clone)]
205struct ResolvePathResult {
206 resolved_def: PerNs,
207 segment_index: Option<usize>,
208 reached_fixedpoint: ReachedFixedPoint,
209}
210
211impl ResolvePathResult {
212 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
213 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
214 }
215
216 fn with(
217 resolved_def: PerNs,
218 reached_fixedpoint: ReachedFixedPoint,
219 segment_index: Option<usize>,
220 ) -> ResolvePathResult {
221 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226enum ResolveMode {
227 Import,
228 Other,
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq)]
232enum ReachedFixedPoint {
233 Yes,
234 No,
235}
236
237impl CrateDefMap {
238 pub(crate) fn crate_def_map_query(
239 // Note that this doesn't have `+ AstDatabase`!
240 // This gurantess that `CrateDefMap` is stable across reparses.
241 db: &impl DefDatabase2,
242 krate: CrateId,
243 ) -> Arc<CrateDefMap> {
244 let _p = profile("crate_def_map_query");
245 let def_map = {
246 let crate_graph = db.crate_graph();
247 let edition = crate_graph.edition(krate);
248 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
249 let root = modules.alloc(ModuleData::default());
250 CrateDefMap {
251 krate,
252 edition,
253 extern_prelude: FxHashMap::default(),
254 prelude: None,
255 root,
256 modules,
257 poison_macros: FxHashSet::default(),
258 diagnostics: Vec::new(),
259 }
260 };
261 let def_map = collector::collect_defs(db, def_map);
262 Arc::new(def_map)
263 }
264
265 pub fn krate(&self) -> CrateId {
266 self.krate
267 }
268
269 pub fn root(&self) -> CrateModuleId {
270 self.root
271 }
272
273 pub fn prelude(&self) -> Option<ModuleId> {
274 self.prelude
275 }
276
277 pub fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDefId> {
278 &self.extern_prelude
279 }
280
281 pub fn add_diagnostics(
282 &self,
283 db: &impl DefDatabase2,
284 module: CrateModuleId,
285 sink: &mut DiagnosticSink,
286 ) {
287 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
288 }
289
290 pub fn resolve_path(
291 &self,
292 db: &impl DefDatabase2,
293 original_module: CrateModuleId,
294 path: &Path,
295 ) -> (PerNs, Option<usize>) {
296 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
297 (res.resolved_def, res.segment_index)
298 }
299
300 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
301 // the result.
302 fn resolve_path_fp_with_macro(
303 &self,
304 db: &impl DefDatabase2,
305 mode: ResolveMode,
306 original_module: CrateModuleId,
307 path: &Path,
308 ) -> ResolvePathResult {
309 let mut segments = path.segments.iter().enumerate();
310 let mut curr_per_ns: PerNs = match path.kind {
311 PathKind::DollarCrate(krate) => {
312 if krate == self.krate {
313 tested_by!(macro_dollar_crate_self);
314 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
315 } else {
316 let def_map = db.crate_def_map(krate);
317 let module = ModuleId { krate, module_id: def_map.root };
318 tested_by!(macro_dollar_crate_other);
319 PerNs::types(module.into())
320 }
321 }
322 PathKind::Crate => {
323 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
324 }
325 PathKind::Self_ => {
326 PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into())
327 }
328 // plain import or absolute path in 2015: crate-relative with
329 // fallback to extern prelude (with the simplification in
330 // rust-lang/rust#57745)
331 // FIXME there must be a nicer way to write this condition
332 PathKind::Plain | PathKind::Abs
333 if self.edition == Edition::Edition2015
334 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
335 {
336 let segment = match segments.next() {
337 Some((_, segment)) => segment,
338 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
339 };
340 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
341 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
342 }
343 PathKind::Plain => {
344 let segment = match segments.next() {
345 Some((_, segment)) => segment,
346 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
347 };
348 log::debug!("resolving {:?} in module", segment);
349 self.resolve_name_in_module(db, original_module, &segment.name)
350 }
351 PathKind::Super => {
352 if let Some(p) = self.modules[original_module].parent {
353 PerNs::types(ModuleId { krate: self.krate, module_id: p }.into())
354 } else {
355 log::debug!("super path in root module");
356 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
357 }
358 }
359 PathKind::Abs => {
360 // 2018-style absolute path -- only extern prelude
361 let segment = match segments.next() {
362 Some((_, segment)) => segment,
363 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
364 };
365 if let Some(def) = self.extern_prelude.get(&segment.name) {
366 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
367 PerNs::types(*def)
368 } else {
369 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
370 }
371 }
372 PathKind::Type(_) => {
373 // This is handled in `infer::infer_path_expr`
374 // The result returned here does not matter
375 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
376 }
377 };
378
379 for (i, segment) in segments {
380 let curr = match curr_per_ns.take_types() {
381 Some(r) => r,
382 None => {
383 // we still have path segments left, but the path so far
384 // didn't resolve in the types namespace => no resolution
385 // (don't break here because `curr_per_ns` might contain
386 // something in the value namespace, and it would be wrong
387 // to return that)
388 return ResolvePathResult::empty(ReachedFixedPoint::No);
389 }
390 };
391 // resolve segment in curr
392
393 curr_per_ns = match curr {
394 ModuleDefId::ModuleId(module) => {
395 if module.krate != self.krate {
396 let path =
397 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
398 log::debug!("resolving {:?} in other crate", path);
399 let defp_map = db.crate_def_map(module.krate);
400 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
401 return ResolvePathResult::with(
402 def,
403 ReachedFixedPoint::Yes,
404 s.map(|s| s + i),
405 );
406 }
407
408 // Since it is a qualified path here, it should not contains legacy macros
409 match self[module.module_id].scope.get(&segment.name) {
410 Some(res) => res.def,
411 _ => {
412 log::debug!("path segment {:?} not found", segment.name);
413 return ResolvePathResult::empty(ReachedFixedPoint::No);
414 }
415 }
416 }
417 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
418 // enum variant
419 tested_by!(can_import_enum_variant);
420 let enum_data = db.enum_data(e);
421 match enum_data.variant(&segment.name) {
422 Some(local_id) => {
423 let variant = EnumVariantId { parent: e, local_id };
424 PerNs::both(variant.into(), variant.into())
425 }
426 None => {
427 return ResolvePathResult::with(
428 PerNs::types(e.into()),
429 ReachedFixedPoint::Yes,
430 Some(i),
431 );
432 }
433 }
434 }
435 s => {
436 // could be an inherent method call in UFCS form
437 // (`Struct::method`), or some other kind of associated item
438 log::debug!(
439 "path segment {:?} resolved to non-module {:?}, but is not last",
440 segment.name,
441 curr,
442 );
443
444 return ResolvePathResult::with(
445 PerNs::types(s),
446 ReachedFixedPoint::Yes,
447 Some(i),
448 );
449 }
450 };
451 }
452 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
453 }
454
455 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
456 let from_crate_root =
457 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
458 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
459
460 from_crate_root.or(from_extern_prelude)
461 }
462
463 pub(crate) fn resolve_name_in_module(
464 &self,
465 db: &impl DefDatabase2,
466 module: CrateModuleId,
467 name: &Name,
468 ) -> PerNs {
469 // Resolve in:
470 // - legacy scope of macro
471 // - current module / scope
472 // - extern prelude
473 // - std prelude
474 let from_legacy_macro =
475 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
476 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
477 let from_extern_prelude =
478 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
479 let from_prelude = self.resolve_in_prelude(db, name);
480
481 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
482 }
483
484 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
485 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
486 }
487
488 fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs {
489 if let Some(prelude) = self.prelude {
490 let keep;
491 let def_map = if prelude.krate == self.krate {
492 self
493 } else {
494 // Extend lifetime
495 keep = db.crate_def_map(prelude.krate);
496 &keep
497 };
498 def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
499 } else {
500 PerNs::none()
501 }
502 }
503}
504
505mod diagnostics {
506 use hir_expand::diagnostics::DiagnosticSink;
507 use ra_db::RelativePathBuf;
508 use ra_syntax::{ast, AstPtr};
509
510 use crate::{db::DefDatabase2, diagnostics::UnresolvedModule, nameres::CrateModuleId, AstId};
511
512 #[derive(Debug, PartialEq, Eq)]
513 pub(super) enum DefDiagnostic {
514 UnresolvedModule {
515 module: CrateModuleId,
516 declaration: AstId<ast::Module>,
517 candidate: RelativePathBuf,
518 },
519 }
520
521 impl DefDiagnostic {
522 pub(super) fn add_to(
523 &self,
524 db: &impl DefDatabase2,
525 target_module: CrateModuleId,
526 sink: &mut DiagnosticSink,
527 ) {
528 match self {
529 DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
530 if *module != target_module {
531 return;
532 }
533 let decl = declaration.to_node(db);
534 sink.push(UnresolvedModule {
535 file: declaration.file_id(),
536 decl: AstPtr::new(&decl),
537 candidate: candidate.clone(),
538 })
539 }
540 }
541 }
542 }
543}
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index ee0a4c99f..3b61d9895 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -1,45 +1,49 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{ 3use hir_expand::{
4 attr::Attr, 4 name::{self, AsName, Name},
5 nameres::{mod_resolution::ModDir, raw}, 5 HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind,
6}; 6};
7use hir_expand::name;
8use ra_cfg::CfgOptions; 7use ra_cfg::CfgOptions;
9use ra_db::FileId; 8use ra_db::{CrateId, FileId};
10use ra_syntax::{ast, SmolStr}; 9use ra_syntax::{ast, SmolStr};
11use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
12use test_utils::tested_by; 11use test_utils::tested_by;
13 12
14use crate::{ 13use crate::{
15 db::DefDatabase, 14 attr::Attr,
16 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 15 db::DefDatabase2,
17 nameres::{ 16 nameres::{
18 diagnostics::DefDiagnostic, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, 17 diagnostics::DefDiagnostic, mod_resolution::ModDir, per_ns::PerNs, raw, CrateDefMap,
19 PerNs, ReachedFixedPoint, Resolution, ResolveMode, 18 ModuleData, ReachedFixedPoint, Resolution, ResolveMode,
20 }, 19 },
21 Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, 20 path::{Path, PathKind},
22 Struct, Trait, TypeAlias, Union, 21 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId,
22 LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
23}; 23};
24 24
25pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 25pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap {
26 let crate_graph = db.crate_graph();
27
26 // populate external prelude 28 // populate external prelude
27 for dep in def_map.krate.dependencies(db) { 29 for dep in crate_graph.dependencies(def_map.krate) {
28 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate); 30 let dep_def_map = db.crate_def_map(dep.crate_id);
29 if let Some(module) = dep.krate.root_module(db) { 31 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
30 def_map.extern_prelude.insert(dep.name.clone(), module.into()); 32 def_map.extern_prelude.insert(
31 } 33 dep.as_name(),
34 ModuleId { krate: dep.crate_id, module_id: dep_def_map.root }.into(),
35 );
36
32 // look for the prelude 37 // look for the prelude
33 if def_map.prelude.is_none() { 38 if def_map.prelude.is_none() {
34 let map = db.crate_def_map(dep.krate); 39 let map = db.crate_def_map(dep.crate_id);
35 if map.prelude.is_some() { 40 if map.prelude.is_some() {
36 def_map.prelude = map.prelude; 41 def_map.prelude = map.prelude;
37 } 42 }
38 } 43 }
39 } 44 }
40 45
41 let crate_graph = db.crate_graph(); 46 let cfg_options = crate_graph.cfg_options(def_map.krate);
42 let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id());
43 47
44 let mut collector = DefCollector { 48 let mut collector = DefCollector {
45 db, 49 db,
@@ -101,11 +105,11 @@ struct DefCollector<'a, DB> {
101 105
102impl<DB> DefCollector<'_, DB> 106impl<DB> DefCollector<'_, DB>
103where 107where
104 DB: DefDatabase, 108 DB: DefDatabase2,
105{ 109{
106 fn collect(&mut self) { 110 fn collect(&mut self) {
107 let crate_graph = self.db.crate_graph(); 111 let crate_graph = self.db.crate_graph();
108 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id()); 112 let file_id = crate_graph.crate_root(self.def_map.krate);
109 let raw_items = self.db.raw_items(file_id.into()); 113 let raw_items = self.db.raw_items(file_id.into());
110 let module_id = self.def_map.root; 114 let module_id = self.def_map.root;
111 self.def_map.modules[module_id].definition = Some(file_id); 115 self.def_map.modules[module_id].definition = Some(file_id);
@@ -168,7 +172,7 @@ where
168 &mut self, 172 &mut self,
169 module_id: CrateModuleId, 173 module_id: CrateModuleId,
170 name: Name, 174 name: Name,
171 macro_: MacroDef, 175 macro_: MacroDefId,
172 export: bool, 176 export: bool,
173 ) { 177 ) {
174 // Textual scoping 178 // Textual scoping
@@ -189,7 +193,7 @@ where
189 /// the definition of current module. 193 /// the definition of current module.
190 /// And also, `macro_use` on a module will import all legacy macros visable inside to 194 /// And also, `macro_use` on a module will import all legacy macros visable inside to
191 /// current legacy scope, with possible shadowing. 195 /// current legacy scope, with possible shadowing.
192 fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) { 196 fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDefId) {
193 // Always shadowing 197 // Always shadowing
194 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); 198 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_);
195 } 199 }
@@ -213,9 +217,9 @@ where
213 .expect("extern crate should have been desugared to one-element path"), 217 .expect("extern crate should have been desugared to one-element path"),
214 ); 218 );
215 219
216 if let Some(ModuleDef::Module(m)) = res.take_types() { 220 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
217 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); 221 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
218 self.import_all_macros_exported(current_module_id, m.krate()); 222 self.import_all_macros_exported(current_module_id, m.krate);
219 } 223 }
220 } 224 }
221 225
@@ -224,7 +228,7 @@ where
224 /// Exported macros are just all macros in the root module scope. 228 /// Exported macros are just all macros in the root module scope.
225 /// Note that it contains not only all `#[macro_export]` macros, but also all aliases 229 /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
226 /// created by `use` in the root module, ignoring the visibility of `use`. 230 /// created by `use` in the root module, ignoring the visibility of `use`.
227 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) { 231 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: CrateId) {
228 let def_map = self.db.crate_def_map(krate); 232 let def_map = self.db.crate_def_map(krate);
229 for (name, def) in def_map[def_map.root].scope.macros() { 233 for (name, def) in def_map[def_map.root].scope.macros() {
230 // `macro_use` only bring things into legacy scope. 234 // `macro_use` only bring things into legacy scope.
@@ -288,15 +292,15 @@ where
288 if import.is_glob { 292 if import.is_glob {
289 log::debug!("glob import: {:?}", import); 293 log::debug!("glob import: {:?}", import);
290 match def.take_types() { 294 match def.take_types() {
291 Some(ModuleDef::Module(m)) => { 295 Some(ModuleDefId::ModuleId(m)) => {
292 if import.is_prelude { 296 if import.is_prelude {
293 tested_by!(std_prelude); 297 tested_by!(std_prelude);
294 self.def_map.prelude = Some(m); 298 self.def_map.prelude = Some(m);
295 } else if m.krate() != self.def_map.krate { 299 } else if m.krate != self.def_map.krate {
296 tested_by!(glob_across_crates); 300 tested_by!(glob_across_crates);
297 // glob import from other crate => we can just import everything once 301 // glob import from other crate => we can just import everything once
298 let item_map = self.db.crate_def_map(m.krate()); 302 let item_map = self.db.crate_def_map(m.krate);
299 let scope = &item_map[m.id.module_id].scope; 303 let scope = &item_map[m.module_id].scope;
300 304
301 // Module scoped macros is included 305 // Module scoped macros is included
302 let items = scope 306 let items = scope
@@ -310,7 +314,7 @@ where
310 // glob import from same crate => we do an initial 314 // glob import from same crate => we do an initial
311 // import, and then need to propagate any further 315 // import, and then need to propagate any further
312 // additions 316 // additions
313 let scope = &self.def_map[m.id.module_id].scope; 317 let scope = &self.def_map[m.module_id].scope;
314 318
315 // Module scoped macros is included 319 // Module scoped macros is included
316 let items = scope 320 let items = scope
@@ -322,23 +326,25 @@ where
322 self.update(module_id, Some(import_id), &items); 326 self.update(module_id, Some(import_id), &items);
323 // record the glob import in case we add further items 327 // record the glob import in case we add further items
324 self.glob_imports 328 self.glob_imports
325 .entry(m.id.module_id) 329 .entry(m.module_id)
326 .or_default() 330 .or_default()
327 .push((module_id, import_id)); 331 .push((module_id, import_id));
328 } 332 }
329 } 333 }
330 Some(ModuleDef::Adt(Adt::Enum(e))) => { 334 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
331 tested_by!(glob_enum); 335 tested_by!(glob_enum);
332 // glob import from enum => just import all the variants 336 // glob import from enum => just import all the variants
333 let variants = e.variants(self.db); 337 let enum_data = self.db.enum_data(e);
334 let resolutions = variants 338 let resolutions = enum_data
335 .into_iter() 339 .variants
336 .filter_map(|variant| { 340 .iter()
341 .filter_map(|(local_id, variant_data)| {
342 let name = variant_data.name.clone()?;
343 let variant = EnumVariantId { parent: e, local_id };
337 let res = Resolution { 344 let res = Resolution {
338 def: PerNs::both(variant.into(), variant.into()), 345 def: PerNs::both(variant.into(), variant.into()),
339 import: Some(import_id), 346 import: Some(import_id),
340 }; 347 };
341 let name = variant.name(self.db)?;
342 Some((name, res)) 348 Some((name, res))
343 }) 349 })
344 .collect::<Vec<_>>(); 350 .collect::<Vec<_>>();
@@ -451,8 +457,8 @@ where
451 ); 457 );
452 458
453 if let Some(def) = resolved_res.resolved_def.get_macros() { 459 if let Some(def) = resolved_res.resolved_def.get_macros() {
454 let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id: *ast_id }); 460 let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id: *ast_id });
455 resolved.push((*module_id, call_id, def.id)); 461 resolved.push((*module_id, call_id, def));
456 res = ReachedFixedPoint::No; 462 res = ReachedFixedPoint::No;
457 return false; 463 return false;
458 } 464 }
@@ -517,7 +523,7 @@ struct ModCollector<'a, D> {
517 523
518impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>> 524impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
519where 525where
520 DB: DefDatabase, 526 DB: DefDatabase2,
521{ 527{
522 fn collect(&mut self, items: &[raw::RawItem]) { 528 fn collect(&mut self, items: &[raw::RawItem]) {
523 // Note: don't assert that inserted value is fresh: it's simply not true 529 // Note: don't assert that inserted value is fresh: it's simply not true
@@ -526,10 +532,9 @@ where
526 532
527 // Prelude module is always considered to be `#[macro_use]`. 533 // Prelude module is always considered to be `#[macro_use]`.
528 if let Some(prelude_module) = self.def_collector.def_map.prelude { 534 if let Some(prelude_module) = self.def_collector.def_map.prelude {
529 if prelude_module.krate() != self.def_collector.def_map.krate { 535 if prelude_module.krate != self.def_collector.def_map.krate {
530 tested_by!(prelude_is_macro_use); 536 tested_by!(prelude_is_macro_use);
531 self.def_collector 537 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
532 .import_all_macros_exported(self.module_id, prelude_module.krate());
533 } 538 }
534 } 539 }
535 540
@@ -635,7 +640,9 @@ where
635 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); 640 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone();
636 modules[self.module_id].children.insert(name.clone(), res); 641 modules[self.module_id].children.insert(name.clone(), res);
637 let resolution = Resolution { 642 let resolution = Resolution {
638 def: PerNs::types(Module::new(self.def_collector.def_map.krate, res).into()), 643 def: PerNs::types(
644 ModuleId { krate: self.def_collector.def_map.krate, module_id: res }.into(),
645 ),
639 import: None, 646 import: None,
640 }; 647 };
641 self.def_collector.update(self.module_id, None, &[(name, resolution)]); 648 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
@@ -643,30 +650,32 @@ where
643 } 650 }
644 651
645 fn define_def(&mut self, def: &raw::DefData) { 652 fn define_def(&mut self, def: &raw::DefData) {
646 let module = Module::new(self.def_collector.def_map.krate, self.module_id); 653 let module =
647 let ctx = LocationCtx::new(self.def_collector.db, module.id, self.file_id); 654 ModuleId { krate: self.def_collector.def_map.krate, module_id: self.module_id };
655 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id);
648 656
649 macro_rules! def {
650 ($kind:ident, $ast_id:ident) => {
651 $kind { id: AstItemDef::from_ast_id(ctx, $ast_id) }.into()
652 };
653 }
654 let name = def.name.clone(); 657 let name = def.name.clone();
655 let def: PerNs = match def.kind { 658 let def: PerNs = match def.kind {
656 raw::DefKind::Function(ast_id) => PerNs::values(def!(Function, ast_id)), 659 raw::DefKind::Function(ast_id) => {
660 PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into())
661 }
657 raw::DefKind::Struct(ast_id) => { 662 raw::DefKind::Struct(ast_id) => {
658 let s = def!(Struct, ast_id); 663 let s = StructId::from_ast_id(ctx, ast_id).into();
659 PerNs::both(s, s) 664 PerNs::both(s, s)
660 } 665 }
661 raw::DefKind::Union(ast_id) => { 666 raw::DefKind::Union(ast_id) => {
662 let s = def!(Union, ast_id); 667 let s = UnionId::from_ast_id(ctx, ast_id).into();
663 PerNs::both(s, s) 668 PerNs::both(s, s)
664 } 669 }
665 raw::DefKind::Enum(ast_id) => PerNs::types(def!(Enum, ast_id)), 670 raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
666 raw::DefKind::Const(ast_id) => PerNs::values(def!(Const, ast_id)), 671 raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()),
667 raw::DefKind::Static(ast_id) => PerNs::values(def!(Static, ast_id)), 672 raw::DefKind::Static(ast_id) => {
668 raw::DefKind::Trait(ast_id) => PerNs::types(def!(Trait, ast_id)), 673 PerNs::values(StaticId::from_ast_id(ctx, ast_id).into())
669 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), 674 }
675 raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()),
676 raw::DefKind::TypeAlias(ast_id) => {
677 PerNs::types(TypeAliasId::from_ast_id(ctx, ast_id).into())
678 }
670 }; 679 };
671 let resolution = Resolution { def, import: None }; 680 let resolution = Resolution { def, import: None };
672 self.def_collector.update(self.module_id, None, &[(name, resolution)]) 681 self.def_collector.update(self.module_id, None, &[(name, resolution)])
@@ -678,10 +687,8 @@ where
678 // Case 1: macro rules, define a macro in crate-global mutable scope 687 // Case 1: macro rules, define a macro in crate-global mutable scope
679 if is_macro_rules(&mac.path) { 688 if is_macro_rules(&mac.path) {
680 if let Some(name) = &mac.name { 689 if let Some(name) = &mac.name {
681 let macro_id = 690 let macro_id = MacroDefId { ast_id, krate: self.def_collector.def_map.krate };
682 MacroDefId { ast_id, krate: self.def_collector.def_map.krate.crate_id }; 691 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
683 let macro_ = MacroDef { id: macro_id };
684 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
685 } 692 }
686 return; 693 return;
687 } 694 }
@@ -691,10 +698,10 @@ where
691 if let Some(macro_def) = mac.path.as_ident().and_then(|name| { 698 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
692 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) 699 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
693 }) { 700 }) {
694 let def = macro_def.id; 701 let macro_call_id =
695 let macro_call_id = self.def_collector.db.intern_macro(MacroCallLoc { def, ast_id }); 702 self.def_collector.db.intern_macro(MacroCallLoc { def: macro_def, ast_id });
696 703
697 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); 704 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def);
698 return; 705 return;
699 } 706 }
700 707
@@ -733,15 +740,16 @@ fn is_macro_rules(path: &Path) -> bool {
733 740
734#[cfg(test)] 741#[cfg(test)]
735mod tests { 742mod tests {
736 use ra_db::SourceDatabase;
737
738 use super::*;
739 use crate::{db::DefDatabase, mock::MockDatabase, Crate};
740 use ra_arena::Arena; 743 use ra_arena::Arena;
744 use ra_db::{fixture::WithFixture, SourceDatabase};
741 use rustc_hash::FxHashSet; 745 use rustc_hash::FxHashSet;
742 746
747 use crate::{db::DefDatabase2, test_db::TestDB};
748
749 use super::*;
750
743 fn do_collect_defs( 751 fn do_collect_defs(
744 db: &impl DefDatabase, 752 db: &impl DefDatabase2,
745 def_map: CrateDefMap, 753 def_map: CrateDefMap,
746 monitor: MacroStackMonitor, 754 monitor: MacroStackMonitor,
747 ) -> CrateDefMap { 755 ) -> CrateDefMap {
@@ -760,12 +768,11 @@ mod tests {
760 } 768 }
761 769
762 fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap { 770 fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap {
763 let (db, _source_root, _) = MockDatabase::with_single_file(&code); 771 let (db, _file_id) = TestDB::with_single_file(&code);
764 let crate_id = db.crate_graph().iter().next().unwrap(); 772 let krate = db.crate_graph().iter().next().unwrap();
765 let krate = Crate { crate_id };
766 773
767 let def_map = { 774 let def_map = {
768 let edition = krate.edition(&db); 775 let edition = db.crate_graph().edition(krate);
769 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default(); 776 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
770 let root = modules.alloc(ModuleData::default()); 777 let root = modules.alloc(ModuleData::default());
771 CrateDefMap { 778 CrateDefMap {
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs
index 7d7e2779a..f6b0b8fb1 100644
--- a/crates/ra_hir_def/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs
@@ -1,8 +1,7 @@
1//! This module resolves `mod foo;` declaration to file. 1//! This module resolves `mod foo;` declaration to file.
2use hir_expand::name::Name; 2use hir_expand::name::Name;
3use ra_db::FileId; 3use ra_db::{FileId, RelativePathBuf};
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
5use relative_path::RelativePathBuf;
6 5
7use crate::{db::DefDatabase2, HirFileId}; 6use crate::{db::DefDatabase2, HirFileId};
8 7
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir_def/src/nameres/per_ns.rs
index 0da6789de..298b0b0c7 100644
--- a/crates/ra_hir/src/nameres/per_ns.rs
+++ b/crates/ra_hir_def/src/nameres/per_ns.rs
@@ -1,6 +1,8 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use crate::{MacroDef, ModuleDef}; 3use hir_expand::MacroDefId;
4
5use crate::ModuleDefId;
4 6
5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub enum Namespace { 8pub enum Namespace {
@@ -12,11 +14,11 @@ pub enum Namespace {
12 14
13#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 15#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
14pub struct PerNs { 16pub struct PerNs {
15 pub types: Option<ModuleDef>, 17 pub types: Option<ModuleDefId>,
16 pub values: Option<ModuleDef>, 18 pub values: Option<ModuleDefId>,
17 /// Since macros has different type, many methods simply ignore it. 19 /// Since macros has different type, many methods simply ignore it.
18 /// We can only use special method like `get_macros` to access it. 20 /// We can only use special method like `get_macros` to access it.
19 pub macros: Option<MacroDef>, 21 pub macros: Option<MacroDefId>,
20} 22}
21 23
22impl Default for PerNs { 24impl Default for PerNs {
@@ -30,19 +32,19 @@ impl PerNs {
30 PerNs { types: None, values: None, macros: None } 32 PerNs { types: None, values: None, macros: None }
31 } 33 }
32 34
33 pub fn values(t: ModuleDef) -> PerNs { 35 pub fn values(t: ModuleDefId) -> PerNs {
34 PerNs { types: None, values: Some(t), macros: None } 36 PerNs { types: None, values: Some(t), macros: None }
35 } 37 }
36 38
37 pub fn types(t: ModuleDef) -> PerNs { 39 pub fn types(t: ModuleDefId) -> PerNs {
38 PerNs { types: Some(t), values: None, macros: None } 40 PerNs { types: Some(t), values: None, macros: None }
39 } 41 }
40 42
41 pub fn both(types: ModuleDef, values: ModuleDef) -> PerNs { 43 pub fn both(types: ModuleDefId, values: ModuleDefId) -> PerNs {
42 PerNs { types: Some(types), values: Some(values), macros: None } 44 PerNs { types: Some(types), values: Some(values), macros: None }
43 } 45 }
44 46
45 pub fn macros(macro_: MacroDef) -> PerNs { 47 pub fn macros(macro_: MacroDefId) -> PerNs {
46 PerNs { types: None, values: None, macros: Some(macro_) } 48 PerNs { types: None, values: None, macros: Some(macro_) }
47 } 49 }
48 50
@@ -54,15 +56,15 @@ impl PerNs {
54 self.types.is_some() && self.values.is_some() && self.macros.is_some() 56 self.types.is_some() && self.values.is_some() && self.macros.is_some()
55 } 57 }
56 58
57 pub fn take_types(self) -> Option<ModuleDef> { 59 pub fn take_types(self) -> Option<ModuleDefId> {
58 self.types 60 self.types
59 } 61 }
60 62
61 pub fn take_values(self) -> Option<ModuleDef> { 63 pub fn take_values(self) -> Option<ModuleDefId> {
62 self.values 64 self.values
63 } 65 }
64 66
65 pub fn get_macros(&self) -> Option<MacroDef> { 67 pub fn get_macros(&self) -> Option<MacroDefId> {
66 self.macros 68 self.macros
67 } 69 }
68 70
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 86c05d602..cb47fa317 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -14,6 +14,7 @@ use ra_syntax::{
14 ast::{self, AttrsOwner, NameOwner}, 14 ast::{self, AttrsOwner, NameOwner},
15 AstNode, AstPtr, SourceFile, 15 AstNode, AstPtr, SourceFile,
16}; 16};
17use test_utils::tested_by;
17 18
18use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, Source}; 19use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, Source};
19 20
@@ -297,8 +298,7 @@ impl RawItemsCollector {
297 self.push_item(current_module, attrs, RawItemKind::Module(item)); 298 self.push_item(current_module, attrs, RawItemKind::Module(item));
298 return; 299 return;
299 } 300 }
300 // FIXME: restore this mark once we complete hir splitting 301 tested_by!(name_res_works_for_broken_modules);
301 // tested_by!(name_res_works_for_broken_modules);
302 } 302 }
303 303
304 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { 304 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 8c6b40aaf..52bd0aa91 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -1,35 +1,31 @@
1mod macros;
2mod globs; 1mod globs;
3mod incremental; 2mod incremental;
4mod primitives; 3mod macros;
5mod mod_resolution; 4mod mod_resolution;
5mod primitives;
6 6
7use std::sync::Arc; 7use std::sync::Arc;
8 8
9use insta::assert_snapshot; 9use insta::assert_snapshot;
10use ra_db::SourceDatabase; 10use ra_db::{fixture::WithFixture, SourceDatabase};
11use test_utils::covers; 11use test_utils::covers;
12 12
13use crate::{ 13use crate::{db::DefDatabase2, nameres::*, test_db::TestDB, CrateModuleId};
14 mock::{CrateGraphFixture, MockDatabase},
15 Crate,
16};
17 14
18use super::*; 15fn def_map(fixtute: &str) -> String {
16 let dm = compute_crate_def_map(fixtute);
17 render_crate_def_map(&dm)
18}
19 19
20fn compute_crate_def_map(fixture: &str, graph: Option<CrateGraphFixture>) -> Arc<CrateDefMap> { 20fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
21 let mut db = MockDatabase::with_files(fixture); 21 let db = TestDB::with_files(fixture);
22 if let Some(graph) = graph { 22 let krate = db.crate_graph().iter().next().unwrap();
23 db.set_crate_graph_from_fixture(graph);
24 }
25 let crate_id = db.crate_graph().iter().next().unwrap();
26 let krate = Crate { crate_id };
27 db.crate_def_map(krate) 23 db.crate_def_map(krate)
28} 24}
29 25
30fn render_crate_def_map(map: &CrateDefMap) -> String { 26fn render_crate_def_map(map: &CrateDefMap) -> String {
31 let mut buf = String::new(); 27 let mut buf = String::new();
32 go(&mut buf, map, "\ncrate", map.root); 28 go(&mut buf, map, "\ncrate", map.root());
33 return buf.trim().to_string(); 29 return buf.trim().to_string();
34 30
35 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) { 31 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) {
@@ -70,16 +66,6 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
70 } 66 }
71} 67}
72 68
73fn def_map(fixtute: &str) -> String {
74 let dm = compute_crate_def_map(fixtute, None);
75 render_crate_def_map(&dm)
76}
77
78fn def_map_with_crate_graph(fixture: &str, graph: CrateGraphFixture) -> String {
79 let dm = compute_crate_def_map(fixture, Some(graph));
80 render_crate_def_map(&dm)
81}
82
83#[test] 69#[test]
84fn crate_def_map_smoke_test() { 70fn crate_def_map_smoke_test() {
85 let map = def_map( 71 let map = def_map(
@@ -234,12 +220,12 @@ fn re_exports() {
234#[test] 220#[test]
235fn std_prelude() { 221fn std_prelude() {
236 covers!(std_prelude); 222 covers!(std_prelude);
237 let map = def_map_with_crate_graph( 223 let map = def_map(
238 " 224 "
239 //- /main.rs 225 //- /main.rs crate:main deps:test_crate
240 use Foo::*; 226 use Foo::*;
241 227
242 //- /lib.rs 228 //- /lib.rs crate:test_crate
243 mod prelude; 229 mod prelude;
244 #[prelude_import] 230 #[prelude_import]
245 use prelude::*; 231 use prelude::*;
@@ -247,10 +233,6 @@ fn std_prelude() {
247 //- /prelude.rs 233 //- /prelude.rs
248 pub enum Foo { Bar, Baz }; 234 pub enum Foo { Bar, Baz };
249 ", 235 ",
250 crate_graph! {
251 "main": ("/main.rs", ["test_crate"]),
252 "test_crate": ("/lib.rs", []),
253 },
254 ); 236 );
255 assert_snapshot!(map, @r###" 237 assert_snapshot!(map, @r###"
256 â‹®crate 238 â‹®crate
@@ -279,9 +261,9 @@ fn can_import_enum_variant() {
279 261
280#[test] 262#[test]
281fn edition_2015_imports() { 263fn edition_2015_imports() {
282 let map = def_map_with_crate_graph( 264 let map = def_map(
283 " 265 "
284 //- /main.rs 266 //- /main.rs crate:main deps:other_crate edition:2015
285 mod foo; 267 mod foo;
286 mod bar; 268 mod bar;
287 269
@@ -292,13 +274,9 @@ fn edition_2015_imports() {
292 use bar::Bar; 274 use bar::Bar;
293 use other_crate::FromLib; 275 use other_crate::FromLib;
294 276
295 //- /lib.rs 277 //- /lib.rs crate:other_crate edition:2018
296 struct FromLib; 278 struct FromLib;
297 ", 279 ",
298 crate_graph! {
299 "main": ("/main.rs", "2015", ["other_crate"]),
300 "other_crate": ("/lib.rs", "2018", []),
301 },
302 ); 280 );
303 281
304 assert_snapshot!(map, @r###" 282 assert_snapshot!(map, @r###"
@@ -343,18 +321,14 @@ fn item_map_using_self() {
343 321
344#[test] 322#[test]
345fn item_map_across_crates() { 323fn item_map_across_crates() {
346 let map = def_map_with_crate_graph( 324 let map = def_map(
347 " 325 "
348 //- /main.rs 326 //- /main.rs crate:main deps:test_crate
349 use test_crate::Baz; 327 use test_crate::Baz;
350 328
351 //- /lib.rs 329 //- /lib.rs crate:test_crate
352 pub struct Baz; 330 pub struct Baz;
353 ", 331 ",
354 crate_graph! {
355 "main": ("/main.rs", ["test_crate"]),
356 "test_crate": ("/lib.rs", []),
357 },
358 ); 332 );
359 333
360 assert_snapshot!(map, @r###" 334 assert_snapshot!(map, @r###"
@@ -365,9 +339,9 @@ fn item_map_across_crates() {
365 339
366#[test] 340#[test]
367fn extern_crate_rename() { 341fn extern_crate_rename() {
368 let map = def_map_with_crate_graph( 342 let map = def_map(
369 " 343 "
370 //- /main.rs 344 //- /main.rs crate:main deps:alloc
371 extern crate alloc as alloc_crate; 345 extern crate alloc as alloc_crate;
372 346
373 mod alloc; 347 mod alloc;
@@ -376,13 +350,9 @@ fn extern_crate_rename() {
376 //- /sync.rs 350 //- /sync.rs
377 use alloc_crate::Arc; 351 use alloc_crate::Arc;
378 352
379 //- /lib.rs 353 //- /lib.rs crate:alloc
380 struct Arc; 354 struct Arc;
381 ", 355 ",
382 crate_graph! {
383 "main": ("/main.rs", ["alloc"]),
384 "alloc": ("/lib.rs", []),
385 },
386 ); 356 );
387 357
388 assert_snapshot!(map, @r###" 358 assert_snapshot!(map, @r###"
@@ -397,9 +367,9 @@ fn extern_crate_rename() {
397 367
398#[test] 368#[test]
399fn extern_crate_rename_2015_edition() { 369fn extern_crate_rename_2015_edition() {
400 let map = def_map_with_crate_graph( 370 let map = def_map(
401 " 371 "
402 //- /main.rs 372 //- /main.rs crate:main deps:alloc edition:2015
403 extern crate alloc as alloc_crate; 373 extern crate alloc as alloc_crate;
404 374
405 mod alloc; 375 mod alloc;
@@ -408,13 +378,9 @@ fn extern_crate_rename_2015_edition() {
408 //- /sync.rs 378 //- /sync.rs
409 use alloc_crate::Arc; 379 use alloc_crate::Arc;
410 380
411 //- /lib.rs 381 //- /lib.rs crate:alloc
412 struct Arc; 382 struct Arc;
413 ", 383 ",
414 crate_graph! {
415 "main": ("/main.rs", "2015", ["alloc"]),
416 "alloc": ("/lib.rs", []),
417 },
418 ); 384 );
419 385
420 assert_snapshot!(map, 386 assert_snapshot!(map,
@@ -431,24 +397,21 @@ fn extern_crate_rename_2015_edition() {
431 397
432#[test] 398#[test]
433fn import_across_source_roots() { 399fn import_across_source_roots() {
434 let map = def_map_with_crate_graph( 400 let map = def_map(
435 " 401 "
436 //- /lib.rs 402 //- /main.rs crate:main deps:test_crate
403 use test_crate::a::b::C;
404
405 //- root /test_crate/
406
407 //- /test_crate/lib.rs crate:test_crate
437 pub mod a { 408 pub mod a {
438 pub mod b { 409 pub mod b {
439 pub struct C; 410 pub struct C;
440 } 411 }
441 } 412 }
442 413
443 //- root /main/
444
445 //- /main/main.rs
446 use test_crate::a::b::C;
447 ", 414 ",
448 crate_graph! {
449 "main": ("/main/main.rs", ["test_crate"]),
450 "test_crate": ("/lib.rs", []),
451 },
452 ); 415 );
453 416
454 assert_snapshot!(map, @r###" 417 assert_snapshot!(map, @r###"
@@ -459,12 +422,12 @@ fn import_across_source_roots() {
459 422
460#[test] 423#[test]
461fn reexport_across_crates() { 424fn reexport_across_crates() {
462 let map = def_map_with_crate_graph( 425 let map = def_map(
463 " 426 "
464 //- /main.rs 427 //- /main.rs crate:main deps:test_crate
465 use test_crate::Baz; 428 use test_crate::Baz;
466 429
467 //- /lib.rs 430 //- /lib.rs crate:test_crate
468 pub use foo::Baz; 431 pub use foo::Baz;
469 432
470 mod foo; 433 mod foo;
@@ -472,10 +435,6 @@ fn reexport_across_crates() {
472 //- /foo.rs 435 //- /foo.rs
473 pub struct Baz; 436 pub struct Baz;
474 ", 437 ",
475 crate_graph! {
476 "main": ("/main.rs", ["test_crate"]),
477 "test_crate": ("/lib.rs", []),
478 },
479 ); 438 );
480 439
481 assert_snapshot!(map, @r###" 440 assert_snapshot!(map, @r###"
@@ -486,19 +445,15 @@ fn reexport_across_crates() {
486 445
487#[test] 446#[test]
488fn values_dont_shadow_extern_crates() { 447fn values_dont_shadow_extern_crates() {
489 let map = def_map_with_crate_graph( 448 let map = def_map(
490 " 449 "
491 //- /main.rs 450 //- /main.rs crate:main deps:foo
492 fn foo() {} 451 fn foo() {}
493 use foo::Bar; 452 use foo::Bar;
494 453
495 //- /foo/lib.rs 454 //- /foo/lib.rs crate:foo
496 pub struct Bar; 455 pub struct Bar;
497 ", 456 ",
498 crate_graph! {
499 "main": ("/main.rs", ["foo"]),
500 "foo": ("/foo/lib.rs", []),
501 },
502 ); 457 );
503 458
504 assert_snapshot!(map, @r###" 459 assert_snapshot!(map, @r###"
@@ -510,11 +465,12 @@ fn values_dont_shadow_extern_crates() {
510 465
511#[test] 466#[test]
512fn cfg_not_test() { 467fn cfg_not_test() {
513 let map = def_map_with_crate_graph( 468 let map = def_map(
514 r#" 469 r#"
515 //- /main.rs 470 //- /main.rs crate:main deps:std
516 use {Foo, Bar, Baz}; 471 use {Foo, Bar, Baz};
517 //- /lib.rs 472
473 //- /lib.rs crate:std
518 #[prelude_import] 474 #[prelude_import]
519 pub use self::prelude::*; 475 pub use self::prelude::*;
520 mod prelude { 476 mod prelude {
@@ -526,10 +482,6 @@ fn cfg_not_test() {
526 pub struct Baz; 482 pub struct Baz;
527 } 483 }
528 "#, 484 "#,
529 crate_graph! {
530 "main": ("/main.rs", ["std"]),
531 "std": ("/lib.rs", []),
532 },
533 ); 485 );
534 486
535 assert_snapshot!(map, @r###" 487 assert_snapshot!(map, @r###"
@@ -542,11 +494,12 @@ fn cfg_not_test() {
542 494
543#[test] 495#[test]
544fn cfg_test() { 496fn cfg_test() {
545 let map = def_map_with_crate_graph( 497 let map = def_map(
546 r#" 498 r#"
547 //- /main.rs 499 //- /main.rs crate:main deps:std
548 use {Foo, Bar, Baz}; 500 use {Foo, Bar, Baz};
549 //- /lib.rs 501
502 //- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42
550 #[prelude_import] 503 #[prelude_import]
551 pub use self::prelude::*; 504 pub use self::prelude::*;
552 mod prelude { 505 mod prelude {
@@ -558,15 +511,6 @@ fn cfg_test() {
558 pub struct Baz; 511 pub struct Baz;
559 } 512 }
560 "#, 513 "#,
561 crate_graph! {
562 "main": ("/main.rs", ["std"]),
563 "std": ("/lib.rs", [], cfg = {
564 "test",
565 "feature" = "foo",
566 "feature" = "bar",
567 "opt" = "42",
568 }),
569 },
570 ); 514 );
571 515
572 assert_snapshot!(map, @r###" 516 assert_snapshot!(map, @r###"
diff --git a/crates/ra_hir/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs
index 7ac22b47b..5b03fe365 100644
--- a/crates/ra_hir/src/nameres/tests/globs.rs
+++ b/crates/ra_hir_def/src/nameres/tests/globs.rs
@@ -76,18 +76,14 @@ fn glob_2() {
76#[test] 76#[test]
77fn glob_across_crates() { 77fn glob_across_crates() {
78 covers!(glob_across_crates); 78 covers!(glob_across_crates);
79 let map = def_map_with_crate_graph( 79 let map = def_map(
80 " 80 "
81 //- /main.rs 81 //- /main.rs crate:main deps:test_crate
82 use test_crate::*; 82 use test_crate::*;
83 83
84 //- /lib.rs 84 //- /lib.rs crate:test_crate
85 pub struct Baz; 85 pub struct Baz;
86 ", 86 ",
87 crate_graph! {
88 "main": ("/main.rs", ["test_crate"]),
89 "test_crate": ("/lib.rs", []),
90 },
91 ); 87 );
92 assert_snapshot!(map, @r###" 88 assert_snapshot!(map, @r###"
93 â‹®crate 89 â‹®crate
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index af9c39760..80dcec62f 100644
--- a/crates/ra_hir/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -1,13 +1,12 @@
1use super::*;
2
3use std::sync::Arc; 1use std::sync::Arc;
4 2
5use ra_db::{SourceDatabase, SourceDatabaseExt}; 3use ra_db::{SourceDatabase, SourceDatabaseExt};
6 4
5use super::*;
6
7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { 7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
8 let (mut db, pos) = MockDatabase::with_position(initial); 8 let (mut db, pos) = TestDB::with_position(initial);
9 let crate_id = db.crate_graph().iter().next().unwrap(); 9 let krate = db.crate_graph().iter().next().unwrap();
10 let krate = Crate { crate_id };
11 { 10 {
12 let events = db.log_executed(|| { 11 let events = db.log_executed(|| {
13 db.crate_def_map(krate); 12 db.crate_def_map(krate);
@@ -92,7 +91,7 @@ fn adding_inner_items_should_not_invalidate_def_map() {
92 91
93#[test] 92#[test]
94fn typing_inside_a_macro_should_not_invalidate_def_map() { 93fn typing_inside_a_macro_should_not_invalidate_def_map() {
95 let (mut db, pos) = MockDatabase::with_position( 94 let (mut db, pos) = TestDB::with_position(
96 " 95 "
97 //- /lib.rs 96 //- /lib.rs
98 macro_rules! m { 97 macro_rules! m {
@@ -112,15 +111,12 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
112 m!(X); 111 m!(X);
113 ", 112 ",
114 ); 113 );
114 let krate = db.crate_graph().iter().next().unwrap();
115 { 115 {
116 let events = db.log_executed(|| { 116 let events = db.log_executed(|| {
117 let src = crate::Source { 117 let crate_def_map = db.crate_def_map(krate);
118 file_id: pos.file_id.into(), 118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
119 ast: crate::ModuleSource::new(&db, Some(pos.file_id), None), 119 assert_eq!(module_data.scope.items.len(), 1);
120 };
121 let module = crate::Module::from_definition(&db, src).unwrap();
122 let decls = module.declarations(&db);
123 assert_eq!(decls.len(), 18);
124 }); 120 });
125 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
126 } 122 }
@@ -128,13 +124,9 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
128 124
129 { 125 {
130 let events = db.log_executed(|| { 126 let events = db.log_executed(|| {
131 let src = crate::Source { 127 let crate_def_map = db.crate_def_map(krate);
132 file_id: pos.file_id.into(), 128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
133 ast: crate::ModuleSource::new(&db, Some(pos.file_id), None), 129 assert_eq!(module_data.scope.items.len(), 1);
134 };
135 let module = crate::Module::from_definition(&db, src).unwrap();
136 let decls = module.declarations(&db);
137 assert_eq!(decls.len(), 18);
138 }); 130 });
139 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
140 } 132 }
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs
index 4f52ad2c5..704065633 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir_def/src/nameres/tests/macros.rs
@@ -71,16 +71,16 @@ fn macro_rules_can_define_modules() {
71 71
72#[test] 72#[test]
73fn macro_rules_from_other_crates_are_visible() { 73fn macro_rules_from_other_crates_are_visible() {
74 let map = def_map_with_crate_graph( 74 let map = def_map(
75 " 75 "
76 //- /main.rs 76 //- /main.rs crate:main deps:foo
77 foo::structs!(Foo, Bar) 77 foo::structs!(Foo, Bar)
78 mod bar; 78 mod bar;
79 79
80 //- /bar.rs 80 //- /bar.rs
81 use crate::*; 81 use crate::*;
82 82
83 //- /lib.rs 83 //- /lib.rs crate:foo
84 #[macro_export] 84 #[macro_export]
85 macro_rules! structs { 85 macro_rules! structs {
86 ($($i:ident),*) => { 86 ($($i:ident),*) => {
@@ -88,10 +88,6 @@ fn macro_rules_from_other_crates_are_visible() {
88 } 88 }
89 } 89 }
90 ", 90 ",
91 crate_graph! {
92 "main": ("/main.rs", ["foo"]),
93 "foo": ("/lib.rs", []),
94 },
95 ); 91 );
96 assert_snapshot!(map, @r###" 92 assert_snapshot!(map, @r###"
97 â‹®crate 93 â‹®crate
@@ -108,16 +104,16 @@ fn macro_rules_from_other_crates_are_visible() {
108 104
109#[test] 105#[test]
110fn macro_rules_export_with_local_inner_macros_are_visible() { 106fn macro_rules_export_with_local_inner_macros_are_visible() {
111 let map = def_map_with_crate_graph( 107 let map = def_map(
112 " 108 "
113 //- /main.rs 109 //- /main.rs crate:main deps:foo
114 foo::structs!(Foo, Bar) 110 foo::structs!(Foo, Bar)
115 mod bar; 111 mod bar;
116 112
117 //- /bar.rs 113 //- /bar.rs
118 use crate::*; 114 use crate::*;
119 115
120 //- /lib.rs 116 //- /lib.rs crate:foo
121 #[macro_export(local_inner_macros)] 117 #[macro_export(local_inner_macros)]
122 macro_rules! structs { 118 macro_rules! structs {
123 ($($i:ident),*) => { 119 ($($i:ident),*) => {
@@ -125,10 +121,6 @@ fn macro_rules_export_with_local_inner_macros_are_visible() {
125 } 121 }
126 } 122 }
127 ", 123 ",
128 crate_graph! {
129 "main": ("/main.rs", ["foo"]),
130 "foo": ("/lib.rs", []),
131 },
132 ); 124 );
133 assert_snapshot!(map, @r###" 125 assert_snapshot!(map, @r###"
134 â‹®crate 126 â‹®crate
@@ -145,9 +137,9 @@ fn macro_rules_export_with_local_inner_macros_are_visible() {
145 137
146#[test] 138#[test]
147fn unexpanded_macro_should_expand_by_fixedpoint_loop() { 139fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
148 let map = def_map_with_crate_graph( 140 let map = def_map(
149 " 141 "
150 //- /main.rs 142 //- /main.rs crate:main deps:foo
151 macro_rules! baz { 143 macro_rules! baz {
152 () => { 144 () => {
153 use foo::bar; 145 use foo::bar;
@@ -158,7 +150,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
158 bar!(); 150 bar!();
159 baz!(); 151 baz!();
160 152
161 //- /lib.rs 153 //- /lib.rs crate:foo
162 #[macro_export] 154 #[macro_export]
163 macro_rules! foo { 155 macro_rules! foo {
164 () => { 156 () => {
@@ -172,10 +164,6 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
172 } 164 }
173 } 165 }
174 ", 166 ",
175 crate_graph! {
176 "main": ("/main.rs", ["foo"]),
177 "foo": ("/lib.rs", []),
178 },
179 ); 167 );
180 assert_snapshot!(map, @r###" 168 assert_snapshot!(map, @r###"
181 â‹®crate 169 â‹®crate
@@ -188,9 +176,9 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
188#[test] 176#[test]
189fn macro_rules_from_other_crates_are_visible_with_macro_use() { 177fn macro_rules_from_other_crates_are_visible_with_macro_use() {
190 covers!(macro_rules_from_other_crates_are_visible_with_macro_use); 178 covers!(macro_rules_from_other_crates_are_visible_with_macro_use);
191 let map = def_map_with_crate_graph( 179 let map = def_map(
192 " 180 "
193 //- /main.rs 181 //- /main.rs crate:main deps:foo
194 structs!(Foo); 182 structs!(Foo);
195 structs_priv!(Bar); 183 structs_priv!(Bar);
196 structs_not_exported!(MacroNotResolved1); 184 structs_not_exported!(MacroNotResolved1);
@@ -205,7 +193,7 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
205 structs!(Baz); 193 structs!(Baz);
206 crate::structs!(MacroNotResolved3); 194 crate::structs!(MacroNotResolved3);
207 195
208 //- /lib.rs 196 //- /lib.rs crate:foo
209 #[macro_export] 197 #[macro_export]
210 macro_rules! structs { 198 macro_rules! structs {
211 ($i:ident) => { struct $i; } 199 ($i:ident) => { struct $i; }
@@ -222,10 +210,6 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
222 } 210 }
223 } 211 }
224 ", 212 ",
225 crate_graph! {
226 "main": ("/main.rs", ["foo"]),
227 "foo": ("/lib.rs", []),
228 },
229 ); 213 );
230 assert_snapshot!(map, @r###" 214 assert_snapshot!(map, @r###"
231 â‹®crate 215 â‹®crate
@@ -242,9 +226,9 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
242#[test] 226#[test]
243fn prelude_is_macro_use() { 227fn prelude_is_macro_use() {
244 covers!(prelude_is_macro_use); 228 covers!(prelude_is_macro_use);
245 let map = def_map_with_crate_graph( 229 let map = def_map(
246 " 230 "
247 //- /main.rs 231 //- /main.rs crate:main deps:foo
248 structs!(Foo); 232 structs!(Foo);
249 structs_priv!(Bar); 233 structs_priv!(Bar);
250 structs_outside!(Out); 234 structs_outside!(Out);
@@ -256,7 +240,7 @@ fn prelude_is_macro_use() {
256 structs!(Baz); 240 structs!(Baz);
257 crate::structs!(MacroNotResolved3); 241 crate::structs!(MacroNotResolved3);
258 242
259 //- /lib.rs 243 //- /lib.rs crate:foo
260 #[prelude_import] 244 #[prelude_import]
261 use self::prelude::*; 245 use self::prelude::*;
262 246
@@ -279,10 +263,6 @@ fn prelude_is_macro_use() {
279 ($i:ident) => { struct $i; } 263 ($i:ident) => { struct $i; }
280 } 264 }
281 ", 265 ",
282 crate_graph! {
283 "main": ("/main.rs", ["foo"]),
284 "foo": ("/lib.rs", []),
285 },
286 ); 266 );
287 assert_snapshot!(map, @r###" 267 assert_snapshot!(map, @r###"
288 â‹®crate 268 â‹®crate
@@ -447,16 +427,16 @@ fn type_value_macro_live_in_different_scopes() {
447 427
448#[test] 428#[test]
449fn macro_use_can_be_aliased() { 429fn macro_use_can_be_aliased() {
450 let map = def_map_with_crate_graph( 430 let map = def_map(
451 " 431 "
452 //- /main.rs 432 //- /main.rs crate:main deps:foo
453 #[macro_use] 433 #[macro_use]
454 extern crate foo; 434 extern crate foo;
455 435
456 foo!(Direct); 436 foo!(Direct);
457 bar!(Alias); 437 bar!(Alias);
458 438
459 //- /lib.rs 439 //- /lib.rs crate:foo
460 use crate::foo as bar; 440 use crate::foo as bar;
461 441
462 mod m { 442 mod m {
@@ -466,10 +446,6 @@ fn macro_use_can_be_aliased() {
466 } 446 }
467 } 447 }
468 ", 448 ",
469 crate_graph! {
470 "main": ("/main.rs", ["foo"]),
471 "foo": ("/lib.rs", []),
472 },
473 ); 449 );
474 assert_snapshot!(map, @r###" 450 assert_snapshot!(map, @r###"
475 â‹®crate 451 â‹®crate
@@ -533,9 +509,9 @@ fn path_qualified_macros() {
533fn macro_dollar_crate_is_correct_in_item() { 509fn macro_dollar_crate_is_correct_in_item() {
534 covers!(macro_dollar_crate_self); 510 covers!(macro_dollar_crate_self);
535 covers!(macro_dollar_crate_other); 511 covers!(macro_dollar_crate_other);
536 let map = def_map_with_crate_graph( 512 let map = def_map(
537 " 513 "
538 //- /main.rs 514 //- /main.rs crate:main deps:foo
539 #[macro_use] 515 #[macro_use]
540 extern crate foo; 516 extern crate foo;
541 517
@@ -554,7 +530,7 @@ fn macro_dollar_crate_is_correct_in_item() {
554 not_current1!(); 530 not_current1!();
555 foo::not_current2!(); 531 foo::not_current2!();
556 532
557 //- /lib.rs 533 //- /lib.rs crate:foo
558 mod m { 534 mod m {
559 #[macro_export] 535 #[macro_export]
560 macro_rules! not_current1 { 536 macro_rules! not_current1 {
@@ -574,10 +550,6 @@ fn macro_dollar_crate_is_correct_in_item() {
574 struct Bar; 550 struct Bar;
575 struct Baz; 551 struct Baz;
576 ", 552 ",
577 crate_graph! {
578 "main": ("/main.rs", ["foo"]),
579 "foo": ("/lib.rs", []),
580 },
581 ); 553 );
582 assert_snapshot!(map, @r###" 554 assert_snapshot!(map, @r###"
583 â‹®crate 555 â‹®crate
@@ -596,12 +568,12 @@ fn macro_dollar_crate_is_correct_in_item() {
596fn macro_dollar_crate_is_correct_in_indirect_deps() { 568fn macro_dollar_crate_is_correct_in_indirect_deps() {
597 covers!(macro_dollar_crate_other); 569 covers!(macro_dollar_crate_other);
598 // From std 570 // From std
599 let map = def_map_with_crate_graph( 571 let map = def_map(
600 r#" 572 r#"
601 //- /main.rs 573 //- /main.rs crate:main deps:std
602 foo!(); 574 foo!();
603 575
604 //- /std.rs 576 //- /std.rs crate:std deps:core
605 #[prelude_import] 577 #[prelude_import]
606 use self::prelude::*; 578 use self::prelude::*;
607 579
@@ -612,7 +584,7 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() {
612 #[macro_use] 584 #[macro_use]
613 mod std_macros; 585 mod std_macros;
614 586
615 //- /core.rs 587 //- /core.rs crate:core
616 #[macro_export] 588 #[macro_export]
617 macro_rules! foo { 589 macro_rules! foo {
618 () => { 590 () => {
@@ -622,11 +594,6 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() {
622 594
623 pub struct bar; 595 pub struct bar;
624 "#, 596 "#,
625 crate_graph! {
626 "main": ("/main.rs", ["std"]),
627 "std": ("/std.rs", ["core"]),
628 "core": ("/core.rs", []),
629 },
630 ); 597 );
631 assert_snapshot!(map, @r###" 598 assert_snapshot!(map, @r###"
632 â‹®crate 599 â‹®crate
diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
index abfe8b1c3..dee364a14 100644
--- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -2,7 +2,7 @@ use super::*;
2 2
3#[test] 3#[test]
4fn name_res_works_for_broken_modules() { 4fn name_res_works_for_broken_modules() {
5 // covers!(name_res_works_for_broken_modules); 5 covers!(name_res_works_for_broken_modules);
6 let map = def_map( 6 let map = def_map(
7 " 7 "
8 //- /lib.rs 8 //- /lib.rs
@@ -54,18 +54,15 @@ fn nested_module_resolution() {
54 54
55#[test] 55#[test]
56fn module_resolution_works_for_non_standard_filenames() { 56fn module_resolution_works_for_non_standard_filenames() {
57 let map = def_map_with_crate_graph( 57 let map = def_map(
58 " 58 "
59 //- /my_library.rs 59 //- /my_library.rs crate:my_library
60 mod foo; 60 mod foo;
61 use self::foo::Bar; 61 use self::foo::Bar;
62 62
63 //- /foo/mod.rs 63 //- /foo/mod.rs
64 pub struct Bar; 64 pub struct Bar;
65 ", 65 ",
66 crate_graph! {
67 "my_library": ("/my_library.rs", []),
68 },
69 ); 66 );
70 67
71 assert_snapshot!(map, @r###" 68 assert_snapshot!(map, @r###"
@@ -650,7 +647,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() {
650 647
651#[test] 648#[test]
652fn unresolved_module_diagnostics() { 649fn unresolved_module_diagnostics() {
653 let diagnostics = MockDatabase::with_files( 650 let db = TestDB::with_files(
654 r" 651 r"
655 //- /lib.rs 652 //- /lib.rs
656 mod foo; 653 mod foo;
@@ -658,11 +655,37 @@ fn unresolved_module_diagnostics() {
658 mod baz {} 655 mod baz {}
659 //- /foo.rs 656 //- /foo.rs
660 ", 657 ",
661 ) 658 );
662 .diagnostics(); 659 let krate = db.crate_graph().iter().next().unwrap();
663 660
664 assert_snapshot!(diagnostics, @r###" 661 let crate_def_map = db.crate_def_map(krate);
665 "mod bar;": unresolved module 662
663 insta::assert_debug_snapshot!(
664 crate_def_map.diagnostics,
665 @r###"
666 [
667 UnresolvedModule {
668 module: CrateModuleId(
669 0,
670 ),
671 declaration: AstId {
672 file_id: HirFileId(
673 FileId(
674 FileId(
675 0,
676 ),
677 ),
678 ),
679 file_ast_id: FileAstId {
680 raw: ErasedFileAstId(
681 1,
682 ),
683 _ty: PhantomData,
684 },
685 },
686 candidate: "bar.rs",
687 },
688 ]
666 "### 689 "###
667 ); 690 );
668} 691}
diff --git a/crates/ra_hir/src/nameres/tests/primitives.rs b/crates/ra_hir_def/src/nameres/tests/primitives.rs
index 0e2708658..0e2708658 100644
--- a/crates/ra_hir/src/nameres/tests/primitives.rs
+++ b/crates/ra_hir_def/src/nameres/tests/primitives.rs
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs
new file mode 100644
index 000000000..8ee8e40d0
--- /dev/null
+++ b/crates/ra_hir_def/src/test_db.rs
@@ -0,0 +1,75 @@
1//! Database used for testing `hir_def`.
2
3use std::{
4 panic,
5 sync::{Arc, Mutex},
6};
7
8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath};
9
10#[salsa::database(
11 ra_db::SourceDatabaseExtStorage,
12 ra_db::SourceDatabaseStorage,
13 hir_expand::db::AstDatabaseStorage,
14 crate::db::InternDatabaseStorage,
15 crate::db::DefDatabase2Storage
16)]
17#[derive(Debug, Default)]
18pub struct TestDB {
19 runtime: salsa::Runtime<TestDB>,
20 events: Mutex<Option<Vec<salsa::Event<TestDB>>>>,
21}
22
23impl salsa::Database for TestDB {
24 fn salsa_runtime(&self) -> &salsa::Runtime<Self> {
25 &self.runtime
26 }
27
28 fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) {
29 let mut events = self.events.lock().unwrap();
30 if let Some(events) = &mut *events {
31 events.push(event());
32 }
33 }
34}
35
36impl panic::RefUnwindSafe for TestDB {}
37
38impl FileLoader for TestDB {
39 fn file_text(&self, file_id: FileId) -> Arc<String> {
40 FileLoaderDelegate(self).file_text(file_id)
41 }
42 fn resolve_relative_path(
43 &self,
44 anchor: FileId,
45 relative_path: &RelativePath,
46 ) -> Option<FileId> {
47 FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
48 }
49 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
50 FileLoaderDelegate(self).relevant_crates(file_id)
51 }
52}
53
54impl TestDB {
55 pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> {
56 *self.events.lock().unwrap() = Some(Vec::new());
57 f();
58 self.events.lock().unwrap().take().unwrap()
59 }
60
61 pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> {
62 let events = self.log(f);
63 events
64 .into_iter()
65 .filter_map(|e| match e.kind {
66 // This pretty horrible, but `Debug` is the only way to inspect
67 // QueryDescriptor at the moment.
68 salsa::EventKind::WillExecute { database_key } => {
69 Some(format!("{:?}", database_key))
70 }
71 _ => None,
72 })
73 .collect()
74 }
75}
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
new file mode 100644
index 000000000..201884b95
--- /dev/null
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -0,0 +1,85 @@
1//! Semantic errors and warnings.
2//!
3//! The `Diagnostic` trait defines a trait object which can represent any
4//! diagnostic.
5//!
6//! `DiagnosticSink` struct is used as an emitter for diagnostic. When creating
7//! a `DiagnosticSink`, you supply a callback which can react to a `dyn
8//! Diagnostic` or to any concrete diagnostic (downcasting is sued internally).
9//!
10//! Because diagnostics store file offsets, it's a bad idea to store them
11//! directly in salsa. For this reason, every hir subsytem defines it's own
12//! strongly-typed closed set of diagnostics which use hir ids internally, are
13//! stored in salsa and do *not* implement the `Diagnostic` trait. Instead, a
14//! subsystem provides a separate, non-query-based API which can walk all stored
15//! values and transform them into instances of `Diagnostic`.
16
17use std::{any::Any, fmt};
18
19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange};
20
21use crate::{db::AstDatabase, Source};
22
23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn message(&self) -> String;
25 fn source(&self) -> Source<SyntaxNodePtr>;
26 fn highlight_range(&self) -> TextRange {
27 self.source().ast.range()
28 }
29 fn as_any(&self) -> &(dyn Any + Send + 'static);
30}
31
32pub trait AstDiagnostic {
33 type AST;
34 fn ast(&self, db: &impl AstDatabase) -> Self::AST;
35}
36
37impl dyn Diagnostic {
38 pub fn syntax_node(&self, db: &impl AstDatabase) -> SyntaxNode {
39 let node = db.parse_or_expand(self.source().file_id).unwrap();
40 self.source().ast.to_node(&node)
41 }
42
43 pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> {
44 self.as_any().downcast_ref()
45 }
46}
47
48pub struct DiagnosticSink<'a> {
49 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
50 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
51}
52
53impl<'a> DiagnosticSink<'a> {
54 /// FIXME: split `new` and `on` into a separate builder type
55 pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> {
56 DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) }
57 }
58
59 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> {
60 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
61 Some(d) => {
62 cb(d);
63 Ok(())
64 }
65 None => Err(()),
66 };
67 self.callbacks.push(Box::new(cb));
68 self
69 }
70
71 pub fn push(&mut self, d: impl Diagnostic) {
72 let d: &dyn Diagnostic = &d;
73 self._push(d);
74 }
75
76 fn _push(&mut self, d: &dyn Diagnostic) {
77 for cb in self.callbacks.iter_mut() {
78 match cb(d) {
79 Ok(()) => return,
80 Err(()) => (),
81 }
82 }
83 (self.default_callback)(d)
84 }
85}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 5a0e5a19c..dd07a16b4 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -9,11 +9,15 @@ pub mod ast_id_map;
9pub mod either; 9pub mod either;
10pub mod name; 10pub mod name;
11pub mod hygiene; 11pub mod hygiene;
12pub mod diagnostics;
12 13
13use std::hash::{Hash, Hasher}; 14use std::hash::{Hash, Hasher};
14 15
15use ra_db::{salsa, CrateId, FileId}; 16use ra_db::{salsa, CrateId, FileId};
16use ra_syntax::ast::{self, AstNode}; 17use ra_syntax::{
18 ast::{self, AstNode},
19 SyntaxNode,
20};
17 21
18use crate::ast_id_map::FileAstId; 22use crate::ast_id_map::FileAstId;
19 23
@@ -151,3 +155,18 @@ impl<N: AstNode> AstId<N> {
151 db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) 155 db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
152 } 156 }
153} 157}
158
159#[derive(Debug, PartialEq, Eq, Clone, Copy)]
160pub struct Source<T> {
161 pub file_id: HirFileId,
162 pub ast: T,
163}
164
165impl<T> Source<T> {
166 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
167 Source { file_id: self.file_id, ast: f(self.ast) }
168 }
169 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
170 db.parse_or_expand(self.file_id).expect("source created from invalid file")
171 }
172}
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml
index bf6ef12f3..fa353b5dd 100644
--- a/crates/ra_ide_api/Cargo.toml
+++ b/crates/ra_ide_api/Cargo.toml
@@ -12,7 +12,6 @@ format-buf = "1.0.0"
12itertools = "0.8.0" 12itertools = "0.8.0"
13join_to_string = "0.1.3" 13join_to_string = "0.1.3"
14log = "0.4.5" 14log = "0.4.5"
15relative-path = "1.0.0"
16rayon = "1.0.2" 15rayon = "1.0.2"
17fst = { version = "0.3.1", default-features = false } 16fst = { version = "0.3.1", default-features = false }
18rustc-hash = "1.0" 17rustc-hash = "1.0"
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 39c5946c7..4416421ae 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -4,13 +4,13 @@ use std::{fmt, sync::Arc, time};
4 4
5use ra_db::{ 5use ra_db::{
6 salsa::{Database, Durability, SweepStrategy}, 6 salsa::{Database, Durability, SweepStrategy},
7 CrateGraph, CrateId, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, 7 CrateGraph, CrateId, FileId, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot,
8 SourceRootId,
8}; 9};
9use ra_prof::{memory_usage, profile, Bytes}; 10use ra_prof::{memory_usage, profile, Bytes};
10use ra_syntax::SourceFile; 11use ra_syntax::SourceFile;
11#[cfg(not(feature = "wasm"))] 12#[cfg(not(feature = "wasm"))]
12use rayon::prelude::*; 13use rayon::prelude::*;
13use relative_path::RelativePathBuf;
14use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
15 15
16use crate::{ 16use crate::{
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index 9ac9768af..09ca40179 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -18,15 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
18 match def { 18 match def {
19 hir::ModuleDef::Module(module) => { 19 hir::ModuleDef::Module(module) => {
20 let module_scope = module.scope(ctx.db); 20 let module_scope = module.scope(ctx.db);
21 for (name, res) in module_scope.entries() { 21 for (name, def, import) in module_scope {
22 if let Some(hir::ModuleDef::BuiltinType(..)) = res.def.take_types() { 22 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
23 if ctx.use_item_syntax.is_some() { 23 if ctx.use_item_syntax.is_some() {
24 tested_by!(dont_complete_primitive_in_use); 24 tested_by!(dont_complete_primitive_in_use);
25 continue; 25 continue;
26 } 26 }
27 } 27 }
28 if Some(module) == ctx.module { 28 if Some(module) == ctx.module {
29 if let Some(import) = res.import { 29 if let Some(import) = import {
30 if let Either::A(use_tree) = module.import_source(ctx.db, import) { 30 if let Either::A(use_tree) = module.import_source(ctx.db, import) {
31 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) { 31 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
32 // for `use self::foo<|>`, don't suggest `foo` as a completion 32 // for `use self::foo<|>`, don't suggest `foo` as a completion
@@ -36,7 +36,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
36 } 36 }
37 } 37 }
38 } 38 }
39 acc.add_resolution(ctx, name.to_string(), &res.def.into()); 39 acc.add_resolution(ctx, name.to_string(), &def);
40 } 40 }
41 } 41 }
42 hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { 42 hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => {
diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs
index 4406695d5..0295b8101 100644
--- a/crates/ra_ide_api/src/completion/complete_record_literal.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs
@@ -32,6 +32,34 @@ mod tests {
32 } 32 }
33 33
34 #[test] 34 #[test]
35 fn test_record_literal_deprecated_field() {
36 let completions = complete(
37 r"
38 struct A {
39 #[deprecated]
40 the_field: u32,
41 }
42 fn foo() {
43 A { the<|> }
44 }
45 ",
46 );
47 assert_debug_snapshot!(completions, @r###"
48 â‹®[
49 â‹® CompletionItem {
50 â‹® label: "the_field",
51 â‹® source_range: [142; 145),
52 â‹® delete: [142; 145),
53 â‹® insert: "the_field",
54 â‹® kind: Field,
55 â‹® detail: "u32",
56 â‹® deprecated: true,
57 â‹® },
58 â‹®]
59 "###);
60 }
61
62 #[test]
35 fn test_record_literal_field() { 63 fn test_record_literal_field() {
36 let completions = complete( 64 let completions = complete(
37 r" 65 r"
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index 5c9c44704..93f336370 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -44,6 +44,9 @@ pub struct CompletionItem {
44 /// Additional info to show in the UI pop up. 44 /// Additional info to show in the UI pop up.
45 detail: Option<String>, 45 detail: Option<String>,
46 documentation: Option<Documentation>, 46 documentation: Option<Documentation>,
47
48 /// Whether this item is marked as deprecated
49 deprecated: bool,
47} 50}
48 51
49// We use custom debug for CompletionItem to make `insta`'s diffs more readable. 52// We use custom debug for CompletionItem to make `insta`'s diffs more readable.
@@ -70,6 +73,9 @@ impl fmt::Debug for CompletionItem {
70 if let Some(documentation) = self.documentation() { 73 if let Some(documentation) = self.documentation() {
71 s.field("documentation", &documentation); 74 s.field("documentation", &documentation);
72 } 75 }
76 if self.deprecated {
77 s.field("deprecated", &true);
78 }
73 s.finish() 79 s.finish()
74 } 80 }
75} 81}
@@ -132,6 +138,7 @@ impl CompletionItem {
132 lookup: None, 138 lookup: None,
133 kind: None, 139 kind: None,
134 text_edit: None, 140 text_edit: None,
141 deprecated: None,
135 } 142 }
136 } 143 }
137 /// What user sees in pop-up in the UI. 144 /// What user sees in pop-up in the UI.
@@ -166,6 +173,10 @@ impl CompletionItem {
166 pub fn kind(&self) -> Option<CompletionItemKind> { 173 pub fn kind(&self) -> Option<CompletionItemKind> {
167 self.kind 174 self.kind
168 } 175 }
176
177 pub fn deprecated(&self) -> bool {
178 self.deprecated
179 }
169} 180}
170 181
171/// A helper to make `CompletionItem`s. 182/// A helper to make `CompletionItem`s.
@@ -181,6 +192,7 @@ pub(crate) struct Builder {
181 lookup: Option<String>, 192 lookup: Option<String>,
182 kind: Option<CompletionItemKind>, 193 kind: Option<CompletionItemKind>,
183 text_edit: Option<TextEdit>, 194 text_edit: Option<TextEdit>,
195 deprecated: Option<bool>,
184} 196}
185 197
186impl Builder { 198impl Builder {
@@ -208,6 +220,7 @@ impl Builder {
208 lookup: self.lookup, 220 lookup: self.lookup,
209 kind: self.kind, 221 kind: self.kind,
210 completion_kind: self.completion_kind, 222 completion_kind: self.completion_kind,
223 deprecated: self.deprecated.unwrap_or(false),
211 } 224 }
212 } 225 }
213 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder { 226 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
@@ -254,6 +267,10 @@ impl Builder {
254 self.documentation = docs.map(Into::into); 267 self.documentation = docs.map(Into::into);
255 self 268 self
256 } 269 }
270 pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder {
271 self.deprecated = Some(deprecated);
272 self
273 }
257} 274}
258 275
259impl<'a> Into<CompletionItem> for Builder { 276impl<'a> Into<CompletionItem> for Builder {
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 65bb639ed..cb55d1875 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -2,7 +2,7 @@
2 2
3use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; 3use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
4use join_to_string::join; 4use join_to_string::join;
5use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::{AttrsOwner, NameOwner};
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{ 8use crate::completion::{
@@ -18,6 +18,11 @@ impl Completions {
18 field: hir::StructField, 18 field: hir::StructField,
19 substs: &hir::Substs, 19 substs: &hir::Substs,
20 ) { 20 ) {
21 let ast_node = field.source(ctx.db).ast;
22 let is_deprecated = match ast_node {
23 hir::FieldSource::Named(m) => is_deprecated(m),
24 hir::FieldSource::Pos(m) => is_deprecated(m),
25 };
21 CompletionItem::new( 26 CompletionItem::new(
22 CompletionKind::Reference, 27 CompletionKind::Reference,
23 ctx.source_range(), 28 ctx.source_range(),
@@ -26,6 +31,7 @@ impl Completions {
26 .kind(CompletionItemKind::Field) 31 .kind(CompletionItemKind::Field)
27 .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string()) 32 .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string())
28 .set_documentation(field.docs(ctx.db)) 33 .set_documentation(field.docs(ctx.db))
34 .set_deprecated(is_deprecated)
29 .add_to(self); 35 .add_to(self);
30 } 36 }
31 37
@@ -179,6 +185,7 @@ impl Completions {
179 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), &macro_declaration) 185 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), &macro_declaration)
180 .kind(CompletionItemKind::Macro) 186 .kind(CompletionItemKind::Macro)
181 .set_documentation(docs.clone()) 187 .set_documentation(docs.clone())
188 .set_deprecated(is_deprecated(ast_node))
182 .detail(detail); 189 .detail(detail);
183 190
184 builder = if ctx.use_item_syntax.is_some() { 191 builder = if ctx.use_item_syntax.is_some() {
@@ -211,6 +218,7 @@ impl Completions {
211 CompletionItemKind::Function 218 CompletionItemKind::Function
212 }) 219 })
213 .set_documentation(func.docs(ctx.db)) 220 .set_documentation(func.docs(ctx.db))
221 .set_deprecated(is_deprecated(ast_node))
214 .detail(detail); 222 .detail(detail);
215 223
216 // Add `<>` for generic types 224 // Add `<>` for generic types
@@ -242,6 +250,7 @@ impl Completions {
242 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) 250 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
243 .kind(CompletionItemKind::Const) 251 .kind(CompletionItemKind::Const)
244 .set_documentation(constant.docs(ctx.db)) 252 .set_documentation(constant.docs(ctx.db))
253 .set_deprecated(is_deprecated(ast_node))
245 .detail(detail) 254 .detail(detail)
246 .add_to(self); 255 .add_to(self);
247 } 256 }
@@ -257,11 +266,13 @@ impl Completions {
257 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) 266 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
258 .kind(CompletionItemKind::TypeAlias) 267 .kind(CompletionItemKind::TypeAlias)
259 .set_documentation(type_alias.docs(ctx.db)) 268 .set_documentation(type_alias.docs(ctx.db))
269 .set_deprecated(is_deprecated(type_def))
260 .detail(detail) 270 .detail(detail)
261 .add_to(self); 271 .add_to(self);
262 } 272 }
263 273
264 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { 274 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
275 let is_deprecated = is_deprecated(variant.source(ctx.db).ast);
265 let name = match variant.name(ctx.db) { 276 let name = match variant.name(ctx.db) {
266 Some(it) => it, 277 Some(it) => it,
267 None => return, 278 None => return,
@@ -274,11 +285,16 @@ impl Completions {
274 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 285 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
275 .kind(CompletionItemKind::EnumVariant) 286 .kind(CompletionItemKind::EnumVariant)
276 .set_documentation(variant.docs(ctx.db)) 287 .set_documentation(variant.docs(ctx.db))
288 .set_deprecated(is_deprecated)
277 .detail(detail) 289 .detail(detail)
278 .add_to(self); 290 .add_to(self);
279 } 291 }
280} 292}
281 293
294fn is_deprecated(node: impl AttrsOwner) -> bool {
295 node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated")
296}
297
282fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { 298fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {
283 let subst = db.generic_defaults(def); 299 let subst = db.generic_defaults(def);
284 subst.iter().any(|ty| ty == &Ty::Unknown) 300 subst.iter().any(|ty| ty == &Ty::Unknown)
@@ -296,6 +312,56 @@ mod tests {
296 } 312 }
297 313
298 #[test] 314 #[test]
315 fn sets_deprecated_flag_in_completion_items() {
316 assert_debug_snapshot!(
317 do_reference_completion(
318 r#"
319 #[deprecated]
320 fn something_deprecated() {}
321
322 #[deprecated(since = "1.0.0")]
323 fn something_else_deprecated() {}
324
325 fn main() { som<|> }
326 "#,
327 ),
328 @r###"
329 [
330 CompletionItem {
331 label: "main()",
332 source_range: [203; 206),
333 delete: [203; 206),
334 insert: "main()$0",
335 kind: Function,
336 lookup: "main",
337 detail: "fn main()",
338 },
339 CompletionItem {
340 label: "something_deprecated()",
341 source_range: [203; 206),
342 delete: [203; 206),
343 insert: "something_deprecated()$0",
344 kind: Function,
345 lookup: "something_deprecated",
346 detail: "fn something_deprecated()",
347 deprecated: true,
348 },
349 CompletionItem {
350 label: "something_else_deprecated()",
351 source_range: [203; 206),
352 delete: [203; 206),
353 insert: "something_else_deprecated()$0",
354 kind: Function,
355 lookup: "something_else_deprecated",
356 detail: "fn something_else_deprecated()",
357 deprecated: true,
358 },
359 ]
360 "###
361 );
362 }
363
364 #[test]
299 fn inserts_parens_for_function_calls() { 365 fn inserts_parens_for_function_calls() {
300 covers!(inserts_parens_for_function_calls); 366 covers!(inserts_parens_for_function_calls);
301 assert_debug_snapshot!( 367 assert_debug_snapshot!(
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index 785e71808..c96465b6a 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -4,10 +4,9 @@ use std::sync::Arc;
4 4
5use ra_db::{ 5use ra_db::{
6 salsa::{self, Database, Durability}, 6 salsa::{self, Database, Durability},
7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, 7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath,
8 SourceDatabaseExt, SourceRootId, 8 SourceDatabase, SourceDatabaseExt, SourceRootId,
9}; 9};
10use relative_path::RelativePath;
11use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
12 11
13use crate::{ 12use crate::{
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 1f1f5cd74..2890a3d2b 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -4,7 +4,7 @@ use std::cell::RefCell;
4 4
5use hir::diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink}; 5use hir::diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink};
6use itertools::Itertools; 6use itertools::Itertools;
7use ra_db::{SourceDatabase, SourceDatabaseExt}; 7use ra_db::{RelativePath, SourceDatabase, SourceDatabaseExt};
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{ 9use ra_syntax::{
10 algo, 10 algo,
@@ -12,7 +12,6 @@ use ra_syntax::{
12 Location, SyntaxNode, TextRange, T, 12 Location, SyntaxNode, TextRange, T,
13}; 13};
14use ra_text_edit::{TextEdit, TextEditBuilder}; 14use ra_text_edit::{TextEdit, TextEditBuilder};
15use relative_path::RelativePath;
16 15
17use crate::{db::RootDatabase, Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit}; 16use crate::{db::RootDatabase, Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit};
18 17
diff --git a/crates/ra_ide_api/src/mock_analysis.rs b/crates/ra_ide_api/src/mock_analysis.rs
index 80b71894c..2b1c96dbf 100644
--- a/crates/ra_ide_api/src/mock_analysis.rs
+++ b/crates/ra_ide_api/src/mock_analysis.rs
@@ -3,7 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use ra_cfg::CfgOptions; 5use ra_cfg::CfgOptions;
6use relative_path::RelativePathBuf; 6use ra_db::RelativePathBuf;
7use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; 7use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
8 8
9use crate::{ 9use crate::{
diff --git a/crates/ra_ide_api/src/references/rename.rs b/crates/ra_ide_api/src/references/rename.rs
index a8783d7a0..11f81cbb3 100644
--- a/crates/ra_ide_api/src/references/rename.rs
+++ b/crates/ra_ide_api/src/references/rename.rs
@@ -1,10 +1,9 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::ModuleSource; 3use hir::ModuleSource;
4use ra_db::{SourceDatabase, SourceDatabaseExt}; 4use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt};
5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; 5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode};
6use ra_text_edit::TextEdit; 6use ra_text_edit::TextEdit;
7use relative_path::{RelativePath, RelativePathBuf};
8 7
9use crate::{ 8use crate::{
10 db::RootDatabase, FileId, FilePosition, FileSystemEdit, RangeInfo, SourceChange, 9 db::RootDatabase, FileId, FilePosition, FileSystemEdit, RangeInfo, SourceChange,
diff --git a/crates/ra_ide_api/src/source_change.rs b/crates/ra_ide_api/src/source_change.rs
index 4e63bbf6f..f5f7f8807 100644
--- a/crates/ra_ide_api/src/source_change.rs
+++ b/crates/ra_ide_api/src/source_change.rs
@@ -3,8 +3,8 @@
3//! 3//!
4//! It can be viewed as a dual for `AnalysisChange`. 4//! It can be viewed as a dual for `AnalysisChange`.
5 5
6use ra_db::RelativePathBuf;
6use ra_text_edit::TextEdit; 7use ra_text_edit::TextEdit;
7use relative_path::RelativePathBuf;
8 8
9use crate::{FileId, FilePosition, SourceRootId, TextUnit}; 9use crate::{FileId, FilePosition, SourceRootId, TextUnit};
10 10
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index ee503633d..94ed619fa 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -127,6 +127,7 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem {
127 text_edit: Some(text_edit), 127 text_edit: Some(text_edit),
128 additional_text_edits: Some(additional_text_edits), 128 additional_text_edits: Some(additional_text_edits),
129 documentation: self.documentation().map(|it| it.conv()), 129 documentation: self.documentation().map(|it| it.conv()),
130 deprecated: Some(self.deprecated()),
130 ..Default::default() 131 ..Default::default()
131 }; 132 };
132 res.insert_text_format = Some(match self.insert_text_format() { 133 res.insert_text_format = Some(match self.insert_text_format() {
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 3d5f18bfa..95062ef6c 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -110,6 +110,23 @@ pub fn match_arm_list(arms: impl Iterator<Item = ast::MatchArm>) -> ast::MatchAr
110 } 110 }
111} 111}
112 112
113pub fn let_match_early(expr: ast::Expr, path: &str, early_expression: &str) -> ast::LetStmt {
114 return from_text(&format!(
115 r#"let {} = match {} {{
116 {}(it) => it,
117 None => {},
118}};"#,
119 expr.syntax().text(),
120 expr.syntax().text(),
121 path,
122 early_expression
123 ));
124
125 fn from_text(text: &str) -> ast::LetStmt {
126 ast_from_text(&format!("fn f() {{ {} }}", text))
127 }
128}
129
113pub fn where_pred(path: ast::Path, bounds: impl Iterator<Item = ast::TypeBound>) -> ast::WherePred { 130pub fn where_pred(path: ast::Path, bounds: impl Iterator<Item = ast::TypeBound>) -> ast::WherePred {
114 let bounds = bounds.map(|b| b.syntax().to_string()).join(" + "); 131 let bounds = bounds.map(|b| b.syntax().to_string()).join(" + ");
115 return from_text(&format!("{}: {}", path.syntax(), bounds)); 132 return from_text(&format!("{}: {}", path.syntax(), bounds));
diff --git a/crates/ra_tt/src/buffer.rs b/crates/ra_tt/src/buffer.rs
index ef3f2323c..14b3f707d 100644
--- a/crates/ra_tt/src/buffer.rs
+++ b/crates/ra_tt/src/buffer.rs
@@ -111,7 +111,7 @@ impl<'a> Cursor<'a> {
111 111
112 /// If the cursor is pointing at the end of a subtree, returns 112 /// If the cursor is pointing at the end of a subtree, returns
113 /// the parent subtree 113 /// the parent subtree
114 pub fn end(self) -> Option<(&'a Subtree)> { 114 pub fn end(self) -> Option<&'a Subtree> {
115 match self.entry() { 115 match self.entry() {
116 Some(Entry::End(Some(ptr))) => { 116 Some(Entry::End(Some(ptr))) => {
117 let idx = ptr.1; 117 let idx = ptr.1;
@@ -127,7 +127,7 @@ impl<'a> Cursor<'a> {
127 } 127 }
128 } 128 }
129 129
130 fn entry(self) -> Option<(&'a Entry<'a>)> { 130 fn entry(self) -> Option<&'a Entry<'a>> {
131 self.buffer.entry(&self.ptr) 131 self.buffer.entry(&self.ptr)
132 } 132 }
133 133
diff --git a/rustfmt.toml b/rustfmt.toml
index f2e164618..71007de81 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,3 +1,2 @@
1reorder_modules = false 1reorder_modules = false
2use_small_heuristics = "Max" 2use_small_heuristics = "Max"
3newline_style = "Unix"
diff --git a/xtask/tests/tidy-tests/docs.rs b/xtask/tests/tidy-tests/docs.rs
index 6a629ce63..227937f46 100644
--- a/xtask/tests/tidy-tests/docs.rs
+++ b/xtask/tests/tidy-tests/docs.rs
@@ -36,6 +36,7 @@ fn is_hidden(entry: &DirEntry) -> bool {
36fn no_docs_comments() { 36fn no_docs_comments() {
37 let crates = project_root().join("crates"); 37 let crates = project_root().join("crates");
38 let iter = WalkDir::new(crates); 38 let iter = WalkDir::new(crates);
39 let mut missing_docs = Vec::new();
39 for f in iter.into_iter().filter_entry(|e| !is_hidden(e)) { 40 for f in iter.into_iter().filter_entry(|e| !is_hidden(e)) {
40 let f = f.unwrap(); 41 let f = f.unwrap();
41 if f.file_type().is_dir() { 42 if f.file_type().is_dir() {
@@ -54,12 +55,14 @@ fn no_docs_comments() {
54 let mut line = String::new(); 55 let mut line = String::new();
55 reader.read_line(&mut line).unwrap(); 56 reader.read_line(&mut line).unwrap();
56 if !line.starts_with("//!") { 57 if !line.starts_with("//!") {
57 panic!( 58 missing_docs.push(f.path().display().to_string());
58 "\nMissing docs strings\n\
59 module: {}\n\
60 Need add doc for module\n",
61 f.path().display()
62 )
63 } 59 }
64 } 60 }
61 if !missing_docs.is_empty() {
62 panic!(
63 "\nMissing docs strings\n\n\
64 modules:\n{}\n\n",
65 missing_docs.join("\n")
66 )
67 }
65} 68}