aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock32
-rw-r--r--README.md5
-rw-r--r--crates/ra_assists/src/add_missing_impl_members.rs283
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_db/src/input.rs4
-rw-r--r--crates/ra_hir/src/code_model_api.rs23
-rw-r--r--crates/ra_hir/src/code_model_impl/krate.rs4
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs104
-rw-r--r--crates/ra_hir/src/db.rs44
-rw-r--r--crates/ra_hir/src/ids.rs64
-rw-r--r--crates/ra_hir/src/impl_block.rs5
-rw-r--r--crates/ra_hir/src/lib.rs7
-rw-r--r--crates/ra_hir/src/macros.rs135
-rw-r--r--crates/ra_hir/src/marks.rs3
-rw-r--r--crates/ra_hir/src/module_tree.rs331
-rw-r--r--crates/ra_hir/src/name.rs3
-rw-r--r--crates/ra_hir/src/nameres.rs743
-rw-r--r--crates/ra_hir/src/nameres/collector.rs564
-rw-r--r--crates/ra_hir/src/nameres/lower.rs222
-rw-r--r--crates/ra_hir/src/nameres/per_ns.rs78
-rw-r--r--crates/ra_hir/src/nameres/raw.rs322
-rw-r--r--crates/ra_hir/src/nameres/tests.rs784
-rw-r--r--crates/ra_hir/src/nameres/tests/globs.rs118
-rw-r--r--crates/ra_hir/src/nameres/tests/incremental.rs123
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs94
-rw-r--r--crates/ra_hir/src/resolve.rs36
-rw-r--r--crates/ra_hir/src/source_binder.rs46
-rw-r--r--crates/ra_hir/src/ty.rs173
-rw-r--r--crates/ra_hir/src/ty/display.rs56
-rw-r--r--crates/ra_hir/src/ty/infer.rs31
-rw-r--r--crates/ra_hir/src/ty/lower.rs99
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs10
-rw-r--r--crates/ra_hir/src/ty/primitive.rs64
-rw-r--r--crates/ra_hir/src/ty/tests.rs5
-rw-r--r--crates/ra_ide_api/src/change.rs2
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs11
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs46
-rw-r--r--crates/ra_ide_api/src/hover.rs5
-rw-r--r--crates/ra_ide_api/src/impls.rs3
-rw-r--r--crates/ra_ide_api/src/runnables.rs2
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs11
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs36
-rw-r--r--crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap2
-rw-r--r--crates/ra_mbe/src/lib.rs20
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs14
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs121
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs30
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs2
-rw-r--r--crates/ra_syntax/src/ast.rs9
-rw-r--r--crates/ra_syntax/src/ast/generated.rs1
-rw-r--r--crates/ra_syntax/src/grammar.ron2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt52
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt28
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt156
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.rs3
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.txt45
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.rs27
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.txt320
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.rs17
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt200
-rw-r--r--crates/test_utils/src/marks.rs4
-rw-r--r--editors/README.md2
-rw-r--r--editors/code/package.json3
-rw-r--r--editors/emacs/ra-emacs-lsp.el9
64 files changed, 3458 insertions, 2342 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0314735da..6f4c4f767 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -62,7 +62,7 @@ name = "backtrace-sys"
62version = "0.1.28" 62version = "0.1.28"
63source = "registry+https://github.com/rust-lang/crates.io-index" 63source = "registry+https://github.com/rust-lang/crates.io-index"
64dependencies = [ 64dependencies = [
65 "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", 65 "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
66 "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 66 "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
67] 67]
68 68
@@ -118,7 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
118 118
119[[package]] 119[[package]]
120name = "cargo_metadata" 120name = "cargo_metadata"
121version = "0.7.1" 121version = "0.7.3"
122source = "registry+https://github.com/rust-lang/crates.io-index" 122source = "registry+https://github.com/rust-lang/crates.io-index"
123dependencies = [ 123dependencies = [
124 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 124 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -130,7 +130,7 @@ dependencies = [
130 130
131[[package]] 131[[package]]
132name = "cc" 132name = "cc"
133version = "1.0.30" 133version = "1.0.31"
134source = "registry+https://github.com/rust-lang/crates.io-index" 134source = "registry+https://github.com/rust-lang/crates.io-index"
135 135
136[[package]] 136[[package]]
@@ -265,7 +265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
265dependencies = [ 265dependencies = [
266 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 266 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
267 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 267 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
268 "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", 268 "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
269] 269]
270 270
271[[package]] 271[[package]]
@@ -338,7 +338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
338dependencies = [ 338dependencies = [
339 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 339 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
340 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 340 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
341 "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", 341 "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
342 "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 342 "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
343] 343]
344 344
@@ -563,7 +563,7 @@ name = "jemalloc-sys"
563version = "0.1.8" 563version = "0.1.8"
564source = "registry+https://github.com/rust-lang/crates.io-index" 564source = "registry+https://github.com/rust-lang/crates.io-index"
565dependencies = [ 565dependencies = [
566 "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", 566 "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
567 "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 567 "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
568 "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 568 "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
569] 569]
@@ -755,7 +755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
755dependencies = [ 755dependencies = [
756 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 756 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
757 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 757 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
758 "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", 758 "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
759] 759]
760 760
761[[package]] 761[[package]]
@@ -847,7 +847,7 @@ dependencies = [
847 "pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 847 "pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
848 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 848 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
849 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 849 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
850 "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", 850 "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
851] 851]
852 852
853[[package]] 853[[package]]
@@ -1083,7 +1083,7 @@ dependencies = [
1083name = "ra_project_model" 1083name = "ra_project_model"
1084version = "0.1.0" 1084version = "0.1.0"
1085dependencies = [ 1085dependencies = [
1086 "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1086 "cargo_metadata 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
1087 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1087 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1088 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1088 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1089 "ra_arena 0.1.0", 1089 "ra_arena 0.1.0",
@@ -1395,7 +1395,7 @@ dependencies = [
1395 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1395 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1396 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 1396 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
1397 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 1397 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
1398 "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", 1398 "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
1399] 1399]
1400 1400
1401[[package]] 1401[[package]]
@@ -1440,7 +1440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1440dependencies = [ 1440dependencies = [
1441 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 1441 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
1442 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 1442 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
1443 "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", 1443 "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
1444] 1444]
1445 1445
1446[[package]] 1446[[package]]
@@ -1523,7 +1523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1523 1523
1524[[package]] 1524[[package]]
1525name = "syn" 1525name = "syn"
1526version = "0.15.27" 1526version = "0.15.29"
1527source = "registry+https://github.com/rust-lang/crates.io-index" 1527source = "registry+https://github.com/rust-lang/crates.io-index"
1528dependencies = [ 1528dependencies = [
1529 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 1529 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1538,7 +1538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1538dependencies = [ 1538dependencies = [
1539 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 1539 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
1540 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 1540 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
1541 "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", 1541 "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
1542 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1542 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1543] 1543]
1544 1544
@@ -1905,8 +1905,8 @@ dependencies = [
1905"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" 1905"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
1906"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" 1906"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
1907"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" 1907"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
1908"checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720" 1908"checksum cargo_metadata 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bc796c7161c220089dfc7159e13324979181532850a237576b8fb907dd087c0d"
1909"checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92" 1909"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
1910"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" 1910"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
1911"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" 1911"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
1912"checksum ci_info 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e5e881307a989a3a5e20d52a32cc05950e3c2178cccfcc9428271a6cde09f902" 1912"checksum ci_info 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e5e881307a989a3a5e20d52a32cc05950e3c2178cccfcc9428271a6cde09f902"
@@ -2042,7 +2042,7 @@ dependencies = [
2042"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 2042"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
2043"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 2043"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
2044"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 2044"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
2045"checksum syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)" = "525bd55255f03c816e5d7f615587bd13030c7103354fadb104993dcee6a788ec" 2045"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2"
2046"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" 2046"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
2047"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" 2047"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a"
2048"checksum tera 0.11.20 (registry+https://github.com/rust-lang/crates.io-index)" = "4b505279e19d8f7d24b1a9dc58327c9c36174b1a2c7ebdeac70792d017cb64f3" 2048"checksum tera 0.11.20 (registry+https://github.com/rust-lang/crates.io-index)" = "4b505279e19d8f7d24b1a9dc58327c9c36174b1a2c7ebdeac70792d017cb64f3"
diff --git a/README.md b/README.md
index 15da30f2d..5bc90a3f0 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,10 @@
4 4
5Rust Analyzer is an **experimental** modular compiler frontend for the Rust 5Rust Analyzer is an **experimental** modular compiler frontend for the Rust
6language. It is a part of a larger rls-2.0 effort to create excellent IDE 6language. It is a part of a larger rls-2.0 effort to create excellent IDE
7support for Rust. If you want to get involved, check rls-2.0 working group repository: 7support for Rust. If you want to get involved, check the rls-2.0 working group
8in the compiler-team repository:
8 9
9https://github.com/rust-analyzer/WG-rls2.0 10https://github.com/rust-lang/compiler-team/tree/master/working-groups/rls-2.0
10 11
11Work on the Rust Analyzer is sponsored by 12Work on the Rust Analyzer is sponsored by
12 13
diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs
new file mode 100644
index 000000000..4435c4b5d
--- /dev/null
+++ b/crates/ra_assists/src/add_missing_impl_members.rs
@@ -0,0 +1,283 @@
1use crate::{Assist, AssistId, AssistCtx};
2
3use hir::Resolver;
4use hir::db::HirDatabase;
5use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc};
6use ra_syntax::ast::{self, AstNode, FnDef, ImplItem, ImplItemKind, NameOwner};
7use ra_db::FilePosition;
8use ra_fmt::{leading_indent, reindent};
9
10use itertools::Itertools;
11
12pub(crate) fn add_missing_impl_members(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
13 let impl_node = ctx.node_at_offset::<ast::ImplBlock>()?;
14 let impl_item_list = impl_node.item_list()?;
15
16 let trait_def = {
17 let file_id = ctx.frange.file_id;
18 let position = FilePosition { file_id, offset: impl_node.syntax().range().start() };
19 let resolver = hir::source_binder::resolver_for_position(ctx.db, position);
20
21 resolve_target_trait_def(ctx.db, &resolver, impl_node)?
22 };
23
24 let missing_fns: Vec<_> = {
25 let fn_def_opt = |kind| if let ImplItemKind::FnDef(def) = kind { Some(def) } else { None };
26 let def_name = |def| -> Option<&SmolStr> { FnDef::name(def).map(ast::Name::text) };
27
28 let trait_items =
29 trait_def.syntax().descendants().find_map(ast::ItemList::cast)?.impl_items();
30 let impl_items = impl_item_list.impl_items();
31
32 let trait_fns = trait_items.map(ImplItem::kind).filter_map(fn_def_opt).collect::<Vec<_>>();
33 let impl_fns = impl_items.map(ImplItem::kind).filter_map(fn_def_opt).collect::<Vec<_>>();
34
35 trait_fns
36 .into_iter()
37 .filter(|t| def_name(t).is_some())
38 .filter(|t| impl_fns.iter().all(|i| def_name(i) != def_name(t)))
39 .collect()
40 };
41 if missing_fns.is_empty() {
42 return None;
43 }
44
45 ctx.add_action(AssistId("add_impl_missing_members"), "add missing impl members", |edit| {
46 let (parent_indent, indent) = {
47 // FIXME: Find a way to get the indent already used in the file.
48 // Now, we copy the indent of first item or indent with 4 spaces relative to impl block
49 const DEFAULT_INDENT: &str = " ";
50 let first_item = impl_item_list.impl_items().next();
51 let first_item_indent =
52 first_item.and_then(|i| leading_indent(i.syntax())).map(ToOwned::to_owned);
53 let impl_block_indent = leading_indent(impl_node.syntax()).unwrap_or_default();
54
55 (
56 impl_block_indent.to_owned(),
57 first_item_indent.unwrap_or_else(|| impl_block_indent.to_owned() + DEFAULT_INDENT),
58 )
59 };
60
61 let changed_range = {
62 let children = impl_item_list.syntax().children();
63 let last_whitespace = children.filter_map(ast::Whitespace::cast).last();
64
65 last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| {
66 let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}");
67 TextRange::from_to(in_brackets, in_brackets)
68 })
69 };
70
71 let func_bodies = format!("\n{}", missing_fns.into_iter().map(build_func_body).join("\n"));
72 let trailing_whitespace = format!("\n{}", parent_indent);
73 let func_bodies = reindent(&func_bodies, &indent) + &trailing_whitespace;
74
75 let replaced_text_range = TextUnit::of_str(&func_bodies);
76
77 edit.replace(changed_range, func_bodies);
78 edit.set_cursor(
79 changed_range.start() + replaced_text_range - TextUnit::of_str(&trailing_whitespace),
80 );
81 });
82
83 ctx.build()
84}
85
86/// Given an `ast::ImplBlock`, resolves the target trait (the one being
87/// implemented) to a `ast::TraitDef`.
88fn resolve_target_trait_def(
89 db: &impl HirDatabase,
90 resolver: &Resolver,
91 impl_block: &ast::ImplBlock,
92) -> Option<TreeArc<ast::TraitDef>> {
93 let ast_path = impl_block.target_trait().map(AstNode::syntax).and_then(ast::PathType::cast)?;
94 let hir_path = ast_path.path().and_then(hir::Path::from_ast)?;
95
96 match resolver.resolve_path(db, &hir_path).take_types() {
97 Some(hir::Resolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).1),
98 _ => None,
99 }
100}
101
102fn build_func_body(def: &ast::FnDef) -> String {
103 let mut buf = String::new();
104
105 for child in def.syntax().children() {
106 if child.kind() == SyntaxKind::SEMI {
107 buf.push_str(" { unimplemented!() }")
108 } else {
109 child.text().push_to(&mut buf);
110 }
111 }
112
113 buf.trim_end().to_string()
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::helpers::{check_assist, check_assist_not_applicable};
120
121 #[test]
122 fn test_add_missing_impl_members() {
123 check_assist(
124 add_missing_impl_members,
125 "
126trait Foo {
127 fn foo(&self);
128 fn bar(&self);
129 fn baz(&self);
130}
131
132struct S;
133
134impl Foo for S {
135 fn bar(&self) {}
136 <|>
137}",
138 "
139trait Foo {
140 fn foo(&self);
141 fn bar(&self);
142 fn baz(&self);
143}
144
145struct S;
146
147impl Foo for S {
148 fn bar(&self) {}
149 fn foo(&self) { unimplemented!() }
150 fn baz(&self) { unimplemented!() }<|>
151}",
152 );
153 }
154
155 #[test]
156 fn test_copied_overriden_members() {
157 check_assist(
158 add_missing_impl_members,
159 "
160trait Foo {
161 fn foo(&self);
162 fn bar(&self) -> bool { true }
163 fn baz(&self) -> u32 { 42 }
164}
165
166struct S;
167
168impl Foo for S {
169 fn bar(&self) {}
170 <|>
171}",
172 "
173trait Foo {
174 fn foo(&self);
175 fn bar(&self) -> bool { true }
176 fn baz(&self) -> u32 { 42 }
177}
178
179struct S;
180
181impl Foo for S {
182 fn bar(&self) {}
183 fn foo(&self) { unimplemented!() }
184 fn baz(&self) -> u32 { 42 }<|>
185}",
186 );
187 }
188
189 #[test]
190 fn test_empty_impl_block() {
191 check_assist(
192 add_missing_impl_members,
193 "
194trait Foo { fn foo(&self); }
195struct S;
196impl Foo for S {<|>}",
197 "
198trait Foo { fn foo(&self); }
199struct S;
200impl Foo for S {
201 fn foo(&self) { unimplemented!() }<|>
202}",
203 );
204 }
205
206 #[test]
207 fn test_cursor_after_empty_impl_block() {
208 check_assist(
209 add_missing_impl_members,
210 "
211trait Foo { fn foo(&self); }
212struct S;
213impl Foo for S {}<|>",
214 "
215trait Foo { fn foo(&self); }
216struct S;
217impl Foo for S {
218 fn foo(&self) { unimplemented!() }<|>
219}",
220 )
221 }
222
223 #[test]
224 fn test_empty_trait() {
225 check_assist_not_applicable(
226 add_missing_impl_members,
227 "
228trait Foo;
229struct S;
230impl Foo for S { <|> }",
231 )
232 }
233
234 #[test]
235 fn test_ignore_unnamed_trait_members() {
236 check_assist(
237 add_missing_impl_members,
238 "
239trait Foo {
240 fn (arg: u32);
241 fn valid(some: u32) -> bool { false }
242}
243struct S;
244impl Foo for S { <|> }",
245 "
246trait Foo {
247 fn (arg: u32);
248 fn valid(some: u32) -> bool { false }
249}
250struct S;
251impl Foo for S {
252 fn valid(some: u32) -> bool { false }<|>
253}",
254 )
255 }
256
257 #[test]
258 fn test_indented_impl_block() {
259 check_assist(
260 add_missing_impl_members,
261 "
262trait Foo {
263 fn valid(some: u32) -> bool { false }
264}
265struct S;
266
267mod my_mod {
268 impl crate::Foo for S { <|> }
269}",
270 "
271trait Foo {
272 fn valid(some: u32) -> bool { false }
273}
274struct S;
275
276mod my_mod {
277 impl crate::Foo for S {
278 fn valid(some: u32) -> bool { false }<|>
279 }
280}",
281 )
282 }
283}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 6c3d75d79..0c4abb450 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -95,6 +95,7 @@ mod replace_if_let_with_match;
95mod split_import; 95mod split_import;
96mod remove_dbg; 96mod remove_dbg;
97mod auto_import; 97mod auto_import;
98mod add_missing_impl_members;
98 99
99fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { 100fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] {
100 &[ 101 &[
@@ -108,6 +109,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
108 split_import::split_import, 109 split_import::split_import,
109 remove_dbg::remove_dbg, 110 remove_dbg::remove_dbg,
110 auto_import::auto_import, 111 auto_import::auto_import,
112 add_missing_impl_members::add_missing_impl_members,
111 ] 113 ]
112} 114}
113 115
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index e45a510b3..2b1001d48 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -124,6 +124,10 @@ impl CrateGraph {
124 self.arena.is_empty() 124 self.arena.is_empty()
125 } 125 }
126 126
127 pub fn iter<'a>(&'a self) -> impl Iterator<Item = CrateId> + 'a {
128 self.arena.keys().map(|it| *it)
129 }
130
127 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 131 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
128 self.arena[&crate_id].file_id 132 self.arena[&crate_id].file_id
129 } 133 }
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index dd7eeebd0..b00481cd5 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -8,13 +8,12 @@ use crate::{
8 Name, ScopesWithSourceMap, Ty, HirFileId, 8 Name, ScopesWithSourceMap, Ty, HirFileId,
9 HirDatabase, PersistentHirDatabase, 9 HirDatabase, PersistentHirDatabase,
10 type_ref::TypeRef, 10 type_ref::TypeRef,
11 nameres::{ModuleScope, Namespace, lower::ImportId}, 11 nameres::{ModuleScope, Namespace, ImportId, CrateModuleId},
12 expr::{Body, BodySourceMap}, 12 expr::{Body, BodySourceMap},
13 ty::InferenceResult, 13 ty::InferenceResult,
14 adt::{EnumVariantId, StructFieldId, VariantDef}, 14 adt::{EnumVariantId, StructFieldId, VariantDef},
15 generics::GenericParams, 15 generics::GenericParams,
16 docs::{Documentation, Docs, docs_from_ast}, 16 docs::{Documentation, Docs, docs_from_ast},
17 module_tree::ModuleId,
18 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, 17 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId},
19 impl_block::ImplBlock, 18 impl_block::ImplBlock,
20 resolve::Resolver, 19 resolve::Resolver,
@@ -65,11 +64,11 @@ impl Crate {
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub struct Module { 65pub struct Module {
67 pub(crate) krate: Crate, 66 pub(crate) krate: Crate,
68 pub(crate) module_id: ModuleId, 67 pub(crate) module_id: CrateModuleId,
69} 68}
70 69
71/// The defs which can be visible in the module. 70/// The defs which can be visible in the module.
72#[derive(Debug, Clone, Copy, PartialEq, Eq)] 71#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
73pub enum ModuleDef { 72pub enum ModuleDef {
74 Module(Module), 73 Module(Module),
75 Function(Function), 74 Function(Function),
@@ -173,7 +172,7 @@ impl Module {
173 172
174 /// Returns a `ModuleScope`: a set of items, visible in this module. 173 /// Returns a `ModuleScope`: a set of items, visible in this module.
175 pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope { 174 pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope {
176 db.item_map(self.krate)[self.module_id].clone() 175 db.crate_def_map(self.krate)[self.module_id].scope.clone()
177 } 176 }
178 177
179 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { 178 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
@@ -181,16 +180,16 @@ impl Module {
181 } 180 }
182 181
183 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 182 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
184 let item_map = db.item_map(self.krate); 183 let def_map = db.crate_def_map(self.krate);
185 Resolver::default().push_module_scope(item_map, *self) 184 Resolver::default().push_module_scope(def_map, self.module_id)
186 } 185 }
187 186
188 pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> { 187 pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> {
189 let lowered_module = db.lower_module(self); 188 let def_map = db.crate_def_map(self.krate);
190 lowered_module 189 def_map[self.module_id]
191 .declarations 190 .scope
192 .values() 191 .entries()
193 .cloned() 192 .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None })
194 .flat_map(|per_ns| { 193 .flat_map(|per_ns| {
195 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter()) 194 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
196 }) 195 })
diff --git a/crates/ra_hir/src/code_model_impl/krate.rs b/crates/ra_hir/src/code_model_impl/krate.rs
index 161ae6e18..cc87c6f14 100644
--- a/crates/ra_hir/src/code_model_impl/krate.rs
+++ b/crates/ra_hir/src/code_model_impl/krate.rs
@@ -18,9 +18,7 @@ impl Crate {
18 .collect() 18 .collect()
19 } 19 }
20 pub(crate) fn root_module_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 20 pub(crate) fn root_module_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
21 let module_tree = db.module_tree(*self); 21 let module_id = db.crate_def_map(*self).root();
22 let module_id = module_tree.modules().next()?;
23
24 let module = Module { krate: *self, module_id }; 22 let module = Module { krate: *self, module_id };
25 Some(module) 23 Some(module)
26 } 24 }
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 437f96942..f7d15c55e 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -1,33 +1,61 @@
1use ra_syntax::{ast, SyntaxNode, TreeArc}; 1use ra_db::FileId;
2use ra_syntax::{ast, SyntaxNode, TreeArc, AstNode};
2 3
3use crate::{ 4use crate::{
4 Module, ModuleSource, Problem, 5 Module, ModuleSource, Problem, Name,
5 Name, 6 nameres::{CrateModuleId, ImportId},
6 module_tree::ModuleId,
7 nameres::lower::ImportId,
8 HirDatabase, PersistentHirDatabase, 7 HirDatabase, PersistentHirDatabase,
9 HirFileId 8 HirFileId, SourceItemId,
10}; 9};
11 10
11impl ModuleSource {
12 pub(crate) fn new(
13 db: &impl PersistentHirDatabase,
14 file_id: Option<FileId>,
15 decl_id: Option<SourceItemId>,
16 ) -> ModuleSource {
17 match (file_id, decl_id) {
18 (Some(file_id), _) => {
19 let source_file = db.parse(file_id);
20 ModuleSource::SourceFile(source_file)
21 }
22 (None, Some(item_id)) => {
23 let module = db.file_item(item_id);
24 let module = ast::Module::cast(&*module).unwrap();
25 assert!(module.item_list().is_some(), "expected inline module");
26 ModuleSource::Module(module.to_owned())
27 }
28 (None, None) => panic!(),
29 }
30 }
31}
32
12impl Module { 33impl Module {
13 fn with_module_id(&self, module_id: ModuleId) -> Module { 34 fn with_module_id(&self, module_id: CrateModuleId) -> Module {
14 Module { module_id, krate: self.krate } 35 Module { module_id, krate: self.krate }
15 } 36 }
16 37
17 pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option<Name> { 38 pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option<Name> {
18 let module_tree = db.module_tree(self.krate); 39 let def_map = db.crate_def_map(self.krate);
19 let link = self.module_id.parent_link(&module_tree)?; 40 let parent = def_map[self.module_id].parent?;
20 Some(link.name(&module_tree).clone()) 41 def_map[parent].children.iter().find_map(|(name, module_id)| {
42 if *module_id == self.module_id {
43 Some(name.clone())
44 } else {
45 None
46 }
47 })
21 } 48 }
22 49
23 pub(crate) fn definition_source_impl( 50 pub(crate) fn definition_source_impl(
24 &self, 51 &self,
25 db: &impl PersistentHirDatabase, 52 db: &impl PersistentHirDatabase,
26 ) -> (HirFileId, ModuleSource) { 53 ) -> (HirFileId, ModuleSource) {
27 let module_tree = db.module_tree(self.krate); 54 let def_map = db.crate_def_map(self.krate);
28 let file_id = self.module_id.file_id(&module_tree); 55 let decl_id = def_map[self.module_id].declaration;
29 let decl_id = self.module_id.decl_id(&module_tree); 56 let file_id = def_map[self.module_id].definition;
30 let module_source = ModuleSource::new(db, file_id, decl_id); 57 let module_source = ModuleSource::new(db, file_id, decl_id);
58 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id);
31 (file_id, module_source) 59 (file_id, module_source)
32 } 60 }
33 61
@@ -35,11 +63,11 @@ impl Module {
35 &self, 63 &self,
36 db: &impl HirDatabase, 64 db: &impl HirDatabase,
37 ) -> Option<(HirFileId, TreeArc<ast::Module>)> { 65 ) -> Option<(HirFileId, TreeArc<ast::Module>)> {
38 let module_tree = db.module_tree(self.krate); 66 let def_map = db.crate_def_map(self.krate);
39 let link = self.module_id.parent_link(&module_tree)?; 67 let decl = def_map[self.module_id].declaration?;
40 let file_id = link.owner(&module_tree).file_id(&module_tree); 68 let syntax_node = db.file_item(decl);
41 let src = link.source(&module_tree, db); 69 let ast = ast::Module::cast(&syntax_node).unwrap().to_owned();
42 Some((file_id, src)) 70 Some((decl.file_id, ast))
43 } 71 }
44 72
45 pub(crate) fn import_source_impl( 73 pub(crate) fn import_source_impl(
@@ -47,22 +75,21 @@ impl Module {
47 db: &impl HirDatabase, 75 db: &impl HirDatabase,
48 import: ImportId, 76 import: ImportId,
49 ) -> TreeArc<ast::PathSegment> { 77 ) -> TreeArc<ast::PathSegment> {
50 let (_, source_map) = db.lower_module_with_source_map(*self); 78 let (file_id, source) = self.definition_source(db);
51 let (_, source) = self.definition_source(db); 79 let (_, source_map) = db.raw_items_with_source_map(file_id.original_file(db));
52 source_map.get(&source, import) 80 source_map.get(&source, import)
53 } 81 }
54 82
55 pub(crate) fn crate_root_impl(&self, db: &impl PersistentHirDatabase) -> Module { 83 pub(crate) fn crate_root_impl(&self, db: &impl PersistentHirDatabase) -> Module {
56 let module_tree = db.module_tree(self.krate); 84 let def_map = db.crate_def_map(self.krate);
57 let module_id = self.module_id.crate_root(&module_tree); 85 self.with_module_id(def_map.root())
58 self.with_module_id(module_id)
59 } 86 }
60 87
61 /// Finds a child module with the specified name. 88 /// Finds a child module with the specified name.
62 pub(crate) fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option<Module> { 89 pub(crate) fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option<Module> {
63 let module_tree = db.module_tree(self.krate); 90 let def_map = db.crate_def_map(self.krate);
64 let child_id = self.module_id.child(&module_tree, name)?; 91 let child_id = def_map[self.module_id].children.get(name)?;
65 Some(self.with_module_id(child_id)) 92 Some(self.with_module_id(*child_id))
66 } 93 }
67 94
68 /// Iterates over all child modules. 95 /// Iterates over all child modules.
@@ -70,18 +97,18 @@ impl Module {
70 &self, 97 &self,
71 db: &impl PersistentHirDatabase, 98 db: &impl PersistentHirDatabase,
72 ) -> impl Iterator<Item = Module> { 99 ) -> impl Iterator<Item = Module> {
73 let module_tree = db.module_tree(self.krate); 100 let def_map = db.crate_def_map(self.krate);
74 let children = self 101 let children = def_map[self.module_id]
75 .module_id 102 .children
76 .children(&module_tree) 103 .iter()
77 .map(|(_, module_id)| self.with_module_id(module_id)) 104 .map(|(_, module_id)| self.with_module_id(*module_id))
78 .collect::<Vec<_>>(); 105 .collect::<Vec<_>>();
79 children.into_iter() 106 children.into_iter()
80 } 107 }
81 108
82 pub(crate) fn parent_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 109 pub(crate) fn parent_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
83 let module_tree = db.module_tree(self.krate); 110 let def_map = db.crate_def_map(self.krate);
84 let parent_id = self.module_id.parent(&module_tree)?; 111 let parent_id = def_map[self.module_id].parent?;
85 Some(self.with_module_id(parent_id)) 112 Some(self.with_module_id(parent_id))
86 } 113 }
87 114
@@ -89,7 +116,14 @@ impl Module {
89 &self, 116 &self,
90 db: &impl HirDatabase, 117 db: &impl HirDatabase,
91 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> { 118 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
92 let module_tree = db.module_tree(self.krate); 119 let def_map = db.crate_def_map(self.krate);
93 self.module_id.problems(&module_tree, db) 120 let (my_file_id, _) = self.definition_source(db);
121 // FIXME: not entirely corret filterint by module
122 def_map
123 .problems()
124 .iter()
125 .filter(|(source_item_id, _problem)| my_file_id == source_item_id.file_id)
126 .map(|(source_item_id, problem)| (db.file_item(*source_item_id), problem.clone()))
127 .collect()
94 } 128 }
95} 129}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 21d22aa7f..c7bad7e2b 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,23 +1,18 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SourceDatabase, salsa}; 4use ra_db::{SourceDatabase, salsa, FileId};
5 5
6use crate::{ 6use crate::{
7 MacroCallId, HirFileId, 7 HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner,
8 SourceFileItems, SourceItemId, Crate, Module, HirInterner,
9 Function, FnSignature, ExprScopes, TypeAlias, 8 Function, FnSignature, ExprScopes, TypeAlias,
10 Struct, Enum, StructField, 9 Struct, Enum, StructField,
11 Const, ConstSignature, Static, 10 Const, ConstSignature, Static,
12 macros::MacroExpansion, 11 nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap},
13 module_tree::ModuleTree, 12 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig},
14 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
15 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
16 adt::{StructData, EnumData}, 13 adt::{StructData, EnumData},
17 impl_block::{ModuleImplBlocks, ImplSourceMap}, 14 impl_block::{ModuleImplBlocks, ImplSourceMap},
18 generics::{GenericParams, GenericDef}, 15 generics::{GenericParams, GenericDef},
19 ids::SourceFileItemId,
20 nameres::Namespace,
21 type_ref::TypeRef, 16 type_ref::TypeRef,
22}; 17};
23 18
@@ -26,9 +21,6 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
26 #[salsa::invoke(HirFileId::hir_parse)] 21 #[salsa::invoke(HirFileId::hir_parse)]
27 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; 22 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;
28 23
29 #[salsa::invoke(crate::macros::expand_macro_invocation)]
30 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;
31
32 #[salsa::invoke(crate::adt::StructData::struct_data_query)] 24 #[salsa::invoke(crate::adt::StructData::struct_data_query)]
33 fn struct_data(&self, s: Struct) -> Arc<StructData>; 25 fn struct_data(&self, s: Struct) -> Arc<StructData>;
34 26
@@ -41,27 +33,14 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
41 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)] 33 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)]
42 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; 34 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>;
43 35
44 #[salsa::invoke(crate::module_tree::Submodule::submodules_query)] 36 #[salsa::invoke(RawItems::raw_items_query)]
45 fn submodules( 37 fn raw_items(&self, file_id: FileId) -> Arc<RawItems>;
46 &self,
47 file_id: HirFileId,
48 delc_id: Option<SourceFileItemId>,
49 ) -> Arc<Vec<crate::module_tree::Submodule>>;
50 38
51 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_with_source_map_query)] 39 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
52 fn lower_module_with_source_map( 40 fn raw_items_with_source_map(&self, file_id: FileId) -> (Arc<RawItems>, Arc<ImportSourceMap>);
53 &self,
54 module: Module,
55 ) -> (Arc<LoweredModule>, Arc<ImportSourceMap>);
56 41
57 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)] 42 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
58 fn lower_module(&self, module: Module) -> Arc<LoweredModule>; 43 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
59
60 #[salsa::invoke(crate::nameres::ItemMap::item_map_query)]
61 fn item_map(&self, krate: Crate) -> Arc<ItemMap>;
62
63 #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)]
64 fn module_tree(&self, krate: Crate) -> Arc<ModuleTree>;
65 44
66 #[salsa::invoke(crate::impl_block::impls_in_module)] 45 #[salsa::invoke(crate::impl_block::impls_in_module)]
67 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; 46 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>;
@@ -105,6 +84,9 @@ pub trait HirDatabase: PersistentHirDatabase {
105 #[salsa::invoke(crate::ty::type_for_field)] 84 #[salsa::invoke(crate::ty::type_for_field)]
106 fn type_for_field(&self, field: StructField) -> Ty; 85 fn type_for_field(&self, field: StructField) -> Ty;
107 86
87 #[salsa::invoke(crate::ty::callable_item_sig)]
88 fn callable_item_signature(&self, def: CallableDef) -> FnSig;
89
108 #[salsa::invoke(crate::expr::body_with_source_map_query)] 90 #[salsa::invoke(crate::expr::body_with_source_map_query)]
109 fn body_with_source_map( 91 fn body_with_source_map(
110 &self, 92 &self,
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 5b00330c6..9596488d3 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -83,30 +83,37 @@ impl HirFileId {
83 } 83 }
84 } 84 }
85 85
86 pub(crate) fn as_macro_call_id(self) -> Option<MacroCallId> {
87 match self.0 {
88 HirFileIdRepr::Macro(it) => Some(it),
89 _ => None,
90 }
91 }
92
93 pub(crate) fn hir_parse( 86 pub(crate) fn hir_parse(
94 db: &impl PersistentHirDatabase, 87 db: &impl PersistentHirDatabase,
95 file_id: HirFileId, 88 file_id: HirFileId,
96 ) -> TreeArc<SourceFile> { 89 ) -> TreeArc<SourceFile> {
97 match file_id.0 { 90 match file_id.0 {
98 HirFileIdRepr::File(file_id) => db.parse(file_id), 91 HirFileIdRepr::File(file_id) => db.parse(file_id),
99 HirFileIdRepr::Macro(m) => { 92 HirFileIdRepr::Macro(macro_call_id) => {
100 if let Some(exp) = db.expand_macro_invocation(m) {
101 return exp.file();
102 }
103 // returning an empty string looks fishy... 93 // returning an empty string looks fishy...
104 SourceFile::parse("") 94 parse_macro(db, macro_call_id).unwrap_or_else(|| SourceFile::parse(""))
105 } 95 }
106 } 96 }
107 } 97 }
108} 98}
109 99
100fn parse_macro(
101 db: &impl PersistentHirDatabase,
102 macro_call_id: MacroCallId,
103) -> Option<TreeArc<SourceFile>> {
104 let loc = macro_call_id.loc(db);
105 let syntax = db.file_item(loc.source_item_id);
106 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
107 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?;
108
109 let def_map = db.crate_def_map(loc.module.krate);
110 let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?;
111 let def_map = db.crate_def_map(krate);
112 let macro_rules = &def_map[macro_id];
113 let tt = macro_rules.expand(&macro_arg).ok()?;
114 Some(mbe::token_tree_to_ast_item_list(&tt))
115}
116
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111enum HirFileIdRepr { 118enum HirFileIdRepr {
112 File(FileId), 119 File(FileId),
@@ -200,8 +207,14 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
200 fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>; 207 fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>;
201 fn from_ast(ctx: LocationCtx<&impl PersistentHirDatabase>, ast: &N) -> Self { 208 fn from_ast(ctx: LocationCtx<&impl PersistentHirDatabase>, ast: &N) -> Self {
202 let items = ctx.db.file_items(ctx.file_id); 209 let items = ctx.db.file_items(ctx.file_id);
203 let raw = 210 let item_id = items.id_of(ctx.file_id, ast.syntax());
204 SourceItemId { file_id: ctx.file_id, item_id: items.id_of(ctx.file_id, ast.syntax()) }; 211 Self::from_source_item_id_unchecked(ctx, item_id)
212 }
213 fn from_source_item_id_unchecked(
214 ctx: LocationCtx<&impl PersistentHirDatabase>,
215 item_id: SourceFileItemId,
216 ) -> Self {
217 let raw = SourceItemId { file_id: ctx.file_id, item_id };
205 let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData }; 218 let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData };
206 219
207 Self::interner(ctx.db.as_ref()).loc2id(&loc) 220 Self::interner(ctx.db.as_ref()).loc2id(&loc)
@@ -290,6 +303,12 @@ impl AstItemDef<ast::TypeAliasDef> for TypeId {
290pub struct SourceFileItemId(RawId); 303pub struct SourceFileItemId(RawId);
291impl_arena_id!(SourceFileItemId); 304impl_arena_id!(SourceFileItemId);
292 305
306impl SourceFileItemId {
307 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
308 SourceItemId { file_id, item_id: self }
309 }
310}
311
293#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 312#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
294pub struct SourceItemId { 313pub struct SourceItemId {
295 pub(crate) file_id: HirFileId, 314 pub(crate) file_id: HirFileId,
@@ -309,9 +328,7 @@ impl SourceFileItems {
309 file_id: HirFileId, 328 file_id: HirFileId,
310 ) -> Arc<SourceFileItems> { 329 ) -> Arc<SourceFileItems> {
311 let source_file = db.hir_parse(file_id); 330 let source_file = db.hir_parse(file_id);
312 let mut res = SourceFileItems { file_id, arena: Arena::default() }; 331 Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
313 res.init(&source_file);
314 Arc::new(res)
315 } 332 }
316 333
317 pub(crate) fn file_item_query( 334 pub(crate) fn file_item_query(
@@ -324,18 +341,23 @@ impl SourceFileItems {
324 .to_owned() 341 .to_owned()
325 } 342 }
326 343
327 fn init(&mut self, source_file: &SourceFile) { 344 pub(crate) fn from_source_file(
345 source_file: &SourceFile,
346 file_id: HirFileId,
347 ) -> SourceFileItems {
348 let mut res = SourceFileItems { file_id, arena: Arena::default() };
328 // By walking the tree in bread-first order we make sure that parents 349 // By walking the tree in bread-first order we make sure that parents
329 // get lower ids then children. That is, adding a new child does not 350 // get lower ids then children. That is, adding a new child does not
330 // change parent's id. This means that, say, adding a new function to a 351 // change parent's id. This means that, say, adding a new function to a
331 // trait does not change ids of top-level items, which helps caching. 352 // trait does not change ids of top-level items, which helps caching.
332 bfs(source_file.syntax(), |it| { 353 bfs(source_file.syntax(), |it| {
333 if let Some(module_item) = ast::ModuleItem::cast(it) { 354 if let Some(module_item) = ast::ModuleItem::cast(it) {
334 self.alloc(module_item.syntax()); 355 res.alloc(module_item.syntax());
335 } else if let Some(macro_call) = ast::MacroCall::cast(it) { 356 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
336 self.alloc(macro_call.syntax()); 357 res.alloc(macro_call.syntax());
337 } 358 }
338 }) 359 });
360 res
339 } 361 }
340 362
341 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { 363 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index eb2d4ed8d..8807a4b56 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -4,7 +4,8 @@ use rustc_hash::FxHashMap;
4use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 4use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
5use ra_syntax::{ 5use ra_syntax::{
6 AstPtr, SourceFile, TreeArc, 6 AstPtr, SourceFile, TreeArc,
7ast::{self, AstNode}}; 7 ast::{self, AstNode}
8};
8 9
9use crate::{ 10use crate::{
10 Const, TypeAlias, Function, HirFileId, 11 Const, TypeAlias, Function, HirFileId,
@@ -13,7 +14,7 @@ use crate::{
13 type_ref::TypeRef, 14 type_ref::TypeRef,
14 ids::LocationCtx, 15 ids::LocationCtx,
15 resolve::Resolver, 16 resolve::Resolver,
16 ty::Ty, generics::GenericParams 17 ty::Ty, generics::GenericParams,
17}; 18};
18 19
19use crate::code_model_api::{Module, ModuleSource}; 20use crate::code_model_api::{Module, ModuleSource};
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index ac5f33079..75c977d32 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -24,9 +24,7 @@ mod path;
24pub mod source_binder; 24pub mod source_binder;
25 25
26mod ids; 26mod ids;
27mod macros;
28mod name; 27mod name;
29mod module_tree;
30mod nameres; 28mod nameres;
31mod adt; 29mod adt;
32mod type_alias; 30mod type_alias;
@@ -54,9 +52,8 @@ pub use self::{
54 path::{Path, PathKind}, 52 path::{Path, PathKind},
55 name::Name, 53 name::Name,
56 ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, 54 ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
57 macros::{MacroDef, MacroInput, MacroExpansion}, 55 nameres::{PerNs, Namespace},
58 nameres::{ItemMap, PerNs, Namespace}, 56 ty::{Ty, Substs, display::HirDisplay},
59 ty::{Ty, Substs},
60 impl_block::{ImplBlock, ImplItem}, 57 impl_block::{ImplBlock, ImplItem},
61 docs::{Docs, Documentation}, 58 docs::{Docs, Documentation},
62 adt::AdtDef, 59 adt::AdtDef,
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs
deleted file mode 100644
index 45128c7df..000000000
--- a/crates/ra_hir/src/macros.rs
+++ /dev/null
@@ -1,135 +0,0 @@
1/// Machinery for macro expansion.
2///
3/// One of the more complicated things about macros is managing the source code
4/// that is produced after expansion. See `HirFileId` and `MacroCallId` for how
5/// do we do that.
6///
7/// When the file-management question is resolved, all that is left is a
8/// token-tree-to-token-tree transformation plus hygiene. We don't have either of
9/// those yet, so all macros are string based at the moment!
10use std::sync::Arc;
11
12use ra_syntax::{
13 TextRange, TextUnit, SourceFile, AstNode, SyntaxNode, TreeArc, SyntaxNodePtr,
14 ast,
15};
16
17use crate::{MacroCallId, PersistentHirDatabase};
18
19// Hard-coded defs for now :-(
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum MacroDef {
22 Vec,
23}
24
25impl MacroDef {
26 /// Expands macro call, returning the expansion and offset to be used to
27 /// convert ranges between expansion and original source.
28 pub fn ast_expand(macro_call: &ast::MacroCall) -> Option<(TextUnit, MacroExpansion)> {
29 let (def, input) = MacroDef::from_call(macro_call)?;
30 let exp = def.expand(input)?;
31 let off = macro_call.token_tree()?.syntax().range().start();
32 Some((off, exp))
33 }
34
35 fn from_call(macro_call: &ast::MacroCall) -> Option<(MacroDef, MacroInput)> {
36 let def = {
37 let path = macro_call.path()?;
38 let name_ref = path.segment()?.name_ref()?;
39 if name_ref.text() == "vec" {
40 MacroDef::Vec
41 } else {
42 return None;
43 }
44 };
45
46 let input = {
47 let arg = macro_call.token_tree()?.syntax();
48 MacroInput { text: arg.text().to_string() }
49 };
50 Some((def, input))
51 }
52
53 fn expand(self, input: MacroInput) -> Option<MacroExpansion> {
54 match self {
55 MacroDef::Vec => self.expand_vec(input),
56 }
57 }
58 fn expand_vec(self, input: MacroInput) -> Option<MacroExpansion> {
59 let text = format!(r"fn dummy() {{ {}; }}", input.text);
60 let file = SourceFile::parse(&text);
61 let array_expr = file.syntax().descendants().find_map(ast::ArrayExpr::cast)?;
62 let ptr = SyntaxNodePtr::new(array_expr.syntax());
63 let src_range = TextRange::offset_len(0.into(), TextUnit::of_str(&input.text));
64 let ranges_map = vec![(src_range, array_expr.syntax().range())];
65 let res = MacroExpansion { text, ranges_map, ptr };
66 Some(res)
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct MacroInput {
72 // Should be token trees
73 pub text: String,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
77pub struct MacroExpansion {
78 /// The result of macro expansion. Should be token tree as well.
79 text: String,
80 /// Correspondence between ranges in the original source code and ranges in
81 /// the macro.
82 ranges_map: Vec<(TextRange, TextRange)>,
83 /// Implementation detail: internally, a macro is expanded to the whole file,
84 /// even if it is an expression. This `ptr` selects the actual expansion from
85 /// the expanded file.
86 ptr: SyntaxNodePtr,
87}
88
89impl MacroExpansion {
90 // FIXME: does not really make sense, macro expansion is not necessary a
91 // whole file. See `MacroExpansion::ptr` as well.
92 pub(crate) fn file(&self) -> TreeArc<SourceFile> {
93 SourceFile::parse(&self.text)
94 }
95
96 pub fn syntax(&self) -> TreeArc<SyntaxNode> {
97 self.ptr.to_node(&self.file()).to_owned()
98 }
99 /// Maps range in the source code to the range in the expanded code.
100 pub fn map_range_forward(&self, src_range: TextRange) -> Option<TextRange> {
101 for (s_range, t_range) in self.ranges_map.iter() {
102 if src_range.is_subrange(&s_range) {
103 let src_at_zero_range = src_range - src_range.start();
104 let src_range_offset = src_range.start() - s_range.start();
105 let src_range = src_at_zero_range + src_range_offset + t_range.start();
106 return Some(src_range);
107 }
108 }
109 None
110 }
111 /// Maps range in the expanded code to the range in the source code.
112 pub fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> {
113 for (s_range, t_range) in self.ranges_map.iter() {
114 if tgt_range.is_subrange(&t_range) {
115 let tgt_at_zero_range = tgt_range - tgt_range.start();
116 let tgt_range_offset = tgt_range.start() - t_range.start();
117 let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start();
118 return Some(src_range);
119 }
120 }
121 None
122 }
123}
124
125pub(crate) fn expand_macro_invocation(
126 db: &impl PersistentHirDatabase,
127 invoc: MacroCallId,
128) -> Option<Arc<MacroExpansion>> {
129 let loc = invoc.loc(db);
130 let syntax = db.file_item(loc.source_item_id);
131 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
132
133 let (def, input) = MacroDef::from_call(macro_call)?;
134 def.expand(input).map(Arc::new)
135}
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 6f3e5f09d..5b6400042 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -1,6 +1,7 @@
1test_utils::marks!( 1test_utils::marks!(
2 bogus_paths
2 name_res_works_for_broken_modules 3 name_res_works_for_broken_modules
3 item_map_enum_importing 4 can_import_enum_variant
4 type_var_cycles_resolve_completely 5 type_var_cycles_resolve_completely
5 type_var_cycles_resolve_as_possible 6 type_var_cycles_resolve_as_possible
6 type_var_resolves_to_int_var 7 type_var_resolves_to_int_var
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
index 99c2115e1..e69de29bb 100644
--- a/crates/ra_hir/src/module_tree.rs
+++ b/crates/ra_hir/src/module_tree.rs
@@ -1,331 +0,0 @@
1use std::sync::Arc;
2
3use arrayvec::ArrayVec;
4use relative_path::RelativePathBuf;
5use ra_db::{FileId, SourceRoot};
6use ra_syntax::{
7 SyntaxNode, TreeArc,
8 algo::generate,
9 ast::{self, AstNode, NameOwner},
10};
11use ra_arena::{Arena, RawId, impl_arena_id};
12use test_utils::tested_by;
13
14use crate::{
15 Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource,
16 PersistentHirDatabase,
17 Crate,
18 ids::SourceFileItemId,
19};
20
21impl ModuleSource {
22 pub(crate) fn new(
23 db: &impl PersistentHirDatabase,
24 file_id: HirFileId,
25 decl_id: Option<SourceFileItemId>,
26 ) -> ModuleSource {
27 match decl_id {
28 Some(item_id) => {
29 let module = db.file_item(SourceItemId { file_id, item_id });
30 let module = ast::Module::cast(&*module).unwrap();
31 assert!(module.item_list().is_some(), "expected inline module");
32 ModuleSource::Module(module.to_owned())
33 }
34 None => {
35 let source_file = db.hir_parse(file_id);
36 ModuleSource::SourceFile(source_file)
37 }
38 }
39 }
40}
41
42#[derive(Clone, Hash, PartialEq, Eq, Debug)]
43pub struct Submodule {
44 name: Name,
45 is_declaration: bool,
46 decl_id: SourceFileItemId,
47}
48
49impl Submodule {
50 pub(crate) fn submodules_query(
51 db: &impl PersistentHirDatabase,
52 file_id: HirFileId,
53 decl_id: Option<SourceFileItemId>,
54 ) -> Arc<Vec<Submodule>> {
55 db.check_canceled();
56 let file_items = db.file_items(file_id);
57 let module_source = ModuleSource::new(db, file_id, decl_id);
58 let submodules = match module_source {
59 ModuleSource::SourceFile(source_file) => {
60 collect_submodules(file_id, &file_items, &*source_file)
61 }
62 ModuleSource::Module(module) => {
63 collect_submodules(file_id, &file_items, module.item_list().unwrap())
64 }
65 };
66
67 return Arc::new(submodules);
68
69 fn collect_submodules(
70 file_id: HirFileId,
71 file_items: &SourceFileItems,
72 root: &impl ast::ModuleItemOwner,
73 ) -> Vec<Submodule> {
74 root.items()
75 .filter_map(|item| match item.kind() {
76 ast::ModuleItemKind::Module(m) => Some(m),
77 _ => None,
78 })
79 .filter_map(|module| {
80 let name = module.name()?.as_name();
81 if !module.has_semi() && module.item_list().is_none() {
82 tested_by!(name_res_works_for_broken_modules);
83 return None;
84 }
85 let sub = Submodule {
86 name,
87 is_declaration: module.has_semi(),
88 decl_id: file_items.id_of(file_id, module.syntax()),
89 };
90 Some(sub)
91 })
92 .collect()
93 }
94 }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
98pub struct ModuleId(RawId);
99impl_arena_id!(ModuleId);
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
102pub struct LinkId(RawId);
103impl_arena_id!(LinkId);
104
105/// Physically, rust source is organized as a set of files, but logically it is
106/// organized as a tree of modules. Usually, a single file corresponds to a
107/// single module, but it is not neccessarily always the case.
108///
109/// `ModuleTree` encapsulates the logic of transitioning from the fuzzy world of files
110/// (which can have multiple parents) to the precise world of modules (which
111/// always have one parent).
112#[derive(Default, Debug, PartialEq, Eq)]
113pub struct ModuleTree {
114 mods: Arena<ModuleId, ModuleData>,
115 links: Arena<LinkId, LinkData>,
116}
117
118#[derive(Debug, PartialEq, Eq)]
119pub struct ModuleData {
120 file_id: HirFileId,
121 /// Points to `ast::Module`, `None` for the whole file.
122 decl_id: Option<SourceFileItemId>,
123 parent: Option<LinkId>,
124 children: Vec<LinkId>,
125}
126
127#[derive(Hash, Debug, PartialEq, Eq)]
128struct LinkData {
129 source: SourceItemId,
130 owner: ModuleId,
131 name: Name,
132 points_to: Vec<ModuleId>,
133 problem: Option<Problem>,
134}
135
136impl ModuleTree {
137 pub(crate) fn module_tree_query(
138 db: &impl PersistentHirDatabase,
139 krate: Crate,
140 ) -> Arc<ModuleTree> {
141 db.check_canceled();
142 let mut res = ModuleTree::default();
143 res.init_crate(db, krate);
144 Arc::new(res)
145 }
146
147 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
148 self.mods.iter().map(|(id, _)| id)
149 }
150
151 pub(crate) fn find_module_by_source(
152 &self,
153 file_id: HirFileId,
154 decl_id: Option<SourceFileItemId>,
155 ) -> Option<ModuleId> {
156 let (res, _) =
157 self.mods.iter().find(|(_, m)| (m.file_id, m.decl_id) == (file_id, decl_id))?;
158 Some(res)
159 }
160
161 fn init_crate(&mut self, db: &impl PersistentHirDatabase, krate: Crate) {
162 let crate_graph = db.crate_graph();
163 let file_id = crate_graph.crate_root(krate.crate_id);
164 let source_root_id = db.file_source_root(file_id);
165
166 let source_root = db.source_root(source_root_id);
167 self.init_subtree(db, &source_root, None, file_id.into(), None);
168 }
169
170 fn init_subtree(
171 &mut self,
172 db: &impl PersistentHirDatabase,
173 source_root: &SourceRoot,
174 parent: Option<LinkId>,
175 file_id: HirFileId,
176 decl_id: Option<SourceFileItemId>,
177 ) -> ModuleId {
178 let is_root = parent.is_none();
179 let id = self.alloc_mod(ModuleData { file_id, decl_id, parent, children: Vec::new() });
180 for sub in db.submodules(file_id, decl_id).iter() {
181 let link = self.alloc_link(LinkData {
182 source: SourceItemId { file_id, item_id: sub.decl_id },
183 name: sub.name.clone(),
184 owner: id,
185 points_to: Vec::new(),
186 problem: None,
187 });
188
189 let (points_to, problem) = if sub.is_declaration {
190 let (points_to, problem) = resolve_submodule(db, file_id, &sub.name, is_root);
191 let points_to = points_to
192 .into_iter()
193 .map(|file_id| {
194 self.init_subtree(db, source_root, Some(link), file_id.into(), None)
195 })
196 .collect::<Vec<_>>();
197 (points_to, problem)
198 } else {
199 let points_to =
200 self.init_subtree(db, source_root, Some(link), file_id, Some(sub.decl_id));
201 (vec![points_to], None)
202 };
203
204 self.links[link].points_to = points_to;
205 self.links[link].problem = problem;
206 }
207 id
208 }
209
210 fn alloc_mod(&mut self, data: ModuleData) -> ModuleId {
211 self.mods.alloc(data)
212 }
213
214 fn alloc_link(&mut self, data: LinkData) -> LinkId {
215 let owner = data.owner;
216 let id = self.links.alloc(data);
217 self.mods[owner].children.push(id);
218 id
219 }
220}
221
222impl ModuleId {
223 pub(crate) fn file_id(self, tree: &ModuleTree) -> HirFileId {
224 tree.mods[self].file_id
225 }
226 pub(crate) fn decl_id(self, tree: &ModuleTree) -> Option<SourceFileItemId> {
227 tree.mods[self].decl_id
228 }
229 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
230 tree.mods[self].parent
231 }
232 pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
233 let link = self.parent_link(tree)?;
234 Some(tree.links[link].owner)
235 }
236 pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
237 generate(Some(self), move |it| it.parent(tree)).last().unwrap()
238 }
239 pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
240 let link = tree.mods[self]
241 .children
242 .iter()
243 .map(|&it| &tree.links[it])
244 .find(|it| it.name == *name)?;
245 Some(*link.points_to.first()?)
246 }
247 pub(crate) fn children<'a>(
248 self,
249 tree: &'a ModuleTree,
250 ) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
251 tree.mods[self].children.iter().filter_map(move |&it| {
252 let link = &tree.links[it];
253 let module = *link.points_to.first()?;
254 Some((link.name.clone(), module))
255 })
256 }
257 pub(crate) fn problems(
258 self,
259 tree: &ModuleTree,
260 db: &impl HirDatabase,
261 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
262 tree.mods[self]
263 .children
264 .iter()
265 .filter_map(|&link| {
266 let p = tree.links[link].problem.clone()?;
267 let s = link.source(tree, db);
268 let s = s.name().unwrap().syntax().to_owned();
269 Some((s, p))
270 })
271 .collect()
272 }
273}
274
275impl LinkId {
276 pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
277 tree.links[self].owner
278 }
279 pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
280 &tree.links[self].name
281 }
282 pub(crate) fn source(
283 self,
284 tree: &ModuleTree,
285 db: &impl PersistentHirDatabase,
286 ) -> TreeArc<ast::Module> {
287 let syntax_node = db.file_item(tree.links[self].source);
288 ast::Module::cast(&syntax_node).unwrap().to_owned()
289 }
290}
291
292fn resolve_submodule(
293 db: &impl PersistentHirDatabase,
294 file_id: HirFileId,
295 name: &Name,
296 is_root: bool,
297) -> (Vec<FileId>, Option<Problem>) {
298 // FIXME: handle submodules of inline modules properly
299 let file_id = file_id.original_file(db);
300 let source_root_id = db.file_source_root(file_id);
301 let path = db.file_relative_path(file_id);
302 let root = RelativePathBuf::default();
303 let dir_path = path.parent().unwrap_or(&root);
304 let mod_name = path.file_stem().unwrap_or("unknown");
305 let is_dir_owner = is_root || mod_name == "mod";
306
307 let file_mod = dir_path.join(format!("{}.rs", name));
308 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
309 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
310 let mut candidates = ArrayVec::<[_; 2]>::new();
311 if is_dir_owner {
312 candidates.push(file_mod.clone());
313 candidates.push(dir_mod);
314 } else {
315 candidates.push(file_dir_mod.clone());
316 };
317 let sr = db.source_root(source_root_id);
318 let points_to = candidates
319 .into_iter()
320 .filter_map(|path| sr.files.get(&path))
321 .map(|&it| it)
322 .collect::<Vec<_>>();
323 let problem = if points_to.is_empty() {
324 Some(Problem::UnresolvedModule {
325 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
326 })
327 } else {
328 None
329 };
330 (points_to, problem)
331}
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 8d786d2ac..06bafa6f0 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -64,6 +64,7 @@ impl Name {
64 "str" => KnownName::Str, 64 "str" => KnownName::Str,
65 "Self" => KnownName::SelfType, 65 "Self" => KnownName::SelfType,
66 "self" => KnownName::SelfParam, 66 "self" => KnownName::SelfParam,
67 "macro_rules" => KnownName::MacroRules,
67 _ => return None, 68 _ => return None,
68 }; 69 };
69 Some(name) 70 Some(name)
@@ -122,4 +123,6 @@ pub(crate) enum KnownName {
122 123
123 SelfType, 124 SelfType,
124 SelfParam, 125 SelfParam,
126
127 MacroRules,
125} 128}
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 73919ee37..edd2f25f7 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -1,60 +1,148 @@
1//! Name resolution algorithm. The end result of the algorithm is an `ItemMap`: 1/// This module implements import-resolution/macro expansion algorithm.
2//! a map which maps each module to its scope: the set of items visible in the 2///
3//! module. That is, we only resolve imports here, name resolution of item 3/// The result of this module is `CrateDefMap`: a datastructure which contains:
4//! bodies will be done in a separate step. 4///
5//! 5/// * a tree of modules for the crate
6//! Like Rustc, we use an interactive per-crate algorithm: we start with scopes 6/// * for each module, a set of items visible in the module (directly declared
7//! containing only directly defined items, and then iteratively resolve 7/// or imported)
8//! imports. 8///
9//! 9/// Note that `CrateDefMap` contains fully macro expanded code.
10//! To make this work nicely in the IDE scenario, we place `InputModuleItems` 10///
11//! in between raw syntax and name resolution. `InputModuleItems` are computed 11/// Computing `CrateDefMap` can be partitioned into several logically
12//! using only the module's syntax, and it is all directly defined items plus 12/// independent "phases". The phases are mutually recursive though, there's no
13//! imports. The plan is to make `InputModuleItems` independent of local 13/// strict ordering.
14//! modifications (that is, typing inside a function should not change IMIs), 14///
15//! so that the results of name resolution can be preserved unless the module 15/// ## Collecting RawItems
16//! structure itself is modified. 16///
17pub(crate) mod lower; 17/// This happens in the `raw` module, which parses a single source file into a
18 18/// set of top-level items. Nested imports are desugared to flat imports in
19use std::{time, sync::Arc}; 19/// this phase. Macro calls are represented as a triple of (Path, Option<Name>,
20 20/// TokenTree).
21use rustc_hash::{FxHashMap, FxHashSet}; 21///
22 22/// ## Collecting Modules
23use ra_arena::map::ArenaMap; 23///
24use ra_db::Edition; 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 raw;
52mod collector;
53#[cfg(test)]
54mod tests;
55
56use std::sync::Arc;
57
58use rustc_hash::FxHashMap;
59use ra_arena::{Arena, RawId, impl_arena_id};
60use ra_db::{FileId, Edition};
25use test_utils::tested_by; 61use test_utils::tested_by;
26 62
27use crate::{ 63use crate::{
28 Module, ModuleDef, 64 ModuleDef, Name, Crate, Module, Problem,
29 Path, PathKind, PersistentHirDatabase, 65 PersistentHirDatabase, Path, PathKind, HirFileId,
30 Crate, Name, 66 ids::{SourceItemId, SourceFileItemId, MacroCallId},
31 module_tree::{ModuleId, ModuleTree},
32 nameres::lower::{ImportId, LoweredModule, ImportData},
33}; 67};
34 68
35/// `ItemMap` is the result of module name resolution. It contains, for each 69pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap};
36/// module, the set of visible items. 70
71pub use self::per_ns::{PerNs, Namespace};
72
73/// Contans all top-level defs from a macro-expanded crate
37#[derive(Debug, PartialEq, Eq)] 74#[derive(Debug, PartialEq, Eq)]
38pub struct ItemMap { 75pub struct CrateDefMap {
76 krate: Crate,
39 edition: Edition, 77 edition: Edition,
40 /// The prelude module for this crate. This either comes from an import 78 /// The prelude module for this crate. This either comes from an import
41 /// marked with the `prelude_import` attribute, or (in the normal case) from 79 /// marked with the `prelude_import` attribute, or (in the normal case) from
42 /// a dependency (`std` or `core`). 80 /// a dependency (`std` or `core`).
43 pub(crate) prelude: Option<Module>, 81 prelude: Option<Module>,
44 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>, 82 extern_prelude: FxHashMap<Name, ModuleDef>,
45 per_module: ArenaMap<ModuleId, ModuleScope>, 83 root: CrateModuleId,
84 modules: Arena<CrateModuleId, ModuleData>,
85 macros: Arena<CrateMacroId, mbe::MacroRules>,
86 public_macros: FxHashMap<Name, CrateMacroId>,
87 macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>,
88 problems: CrateDefMapProblems,
89}
90
91impl std::ops::Index<CrateModuleId> for CrateDefMap {
92 type Output = ModuleData;
93 fn index(&self, id: CrateModuleId) -> &ModuleData {
94 &self.modules[id]
95 }
96}
97
98impl std::ops::Index<CrateMacroId> for CrateDefMap {
99 type Output = mbe::MacroRules;
100 fn index(&self, id: CrateMacroId) -> &mbe::MacroRules {
101 &self.macros[id]
102 }
103}
104
105/// An ID of a macro, **local** to a specific crate
106#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
107pub(crate) struct CrateMacroId(RawId);
108impl_arena_id!(CrateMacroId);
109
110/// An ID of a module, **local** to a specific crate
111#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
112pub(crate) struct CrateModuleId(RawId);
113impl_arena_id!(CrateModuleId);
114
115#[derive(Default, Debug, PartialEq, Eq)]
116pub(crate) struct ModuleData {
117 pub(crate) parent: Option<CrateModuleId>,
118 pub(crate) children: FxHashMap<Name, CrateModuleId>,
119 pub(crate) scope: ModuleScope,
120 /// None for root
121 pub(crate) declaration: Option<SourceItemId>,
122 /// None for inline modules.
123 ///
124 /// Note that non-inline modules, by definition, live inside non-macro file.
125 pub(crate) definition: Option<FileId>,
126}
127
128#[derive(Default, Debug, PartialEq, Eq)]
129pub(crate) struct CrateDefMapProblems {
130 problems: Vec<(SourceItemId, Problem)>,
46} 131}
47 132
48impl std::ops::Index<ModuleId> for ItemMap { 133impl CrateDefMapProblems {
49 type Output = ModuleScope; 134 fn add(&mut self, source_item_id: SourceItemId, problem: Problem) {
50 fn index(&self, id: ModuleId) -> &ModuleScope { 135 self.problems.push((source_item_id, problem))
51 &self.per_module[id] 136 }
137
138 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a {
139 self.problems.iter().map(|(s, p)| (s, p))
52 } 140 }
53} 141}
54 142
55#[derive(Debug, Default, PartialEq, Eq, Clone)] 143#[derive(Debug, Default, PartialEq, Eq, Clone)]
56pub struct ModuleScope { 144pub struct ModuleScope {
57 pub(crate) items: FxHashMap<Name, Resolution>, 145 items: FxHashMap<Name, Resolution>,
58} 146}
59 147
60impl ModuleScope { 148impl ModuleScope {
@@ -66,8 +154,6 @@ impl ModuleScope {
66 } 154 }
67} 155}
68 156
69/// `Resolution` is basically `DefId` atm, but it should account for stuff like
70/// multiple namespaces, ambiguity and errors.
71#[derive(Debug, Clone, PartialEq, Eq, Default)] 157#[derive(Debug, Clone, PartialEq, Eq, Default)]
72pub struct Resolution { 158pub struct Resolution {
73 /// None for unresolved 159 /// None for unresolved
@@ -76,372 +162,6 @@ pub struct Resolution {
76 pub import: Option<ImportId>, 162 pub import: Option<ImportId>,
77} 163}
78 164
79#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
80pub enum Namespace {
81 Types,
82 Values,
83}
84
85#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
86pub struct PerNs<T> {
87 pub types: Option<T>,
88 pub values: Option<T>,
89}
90
91impl<T> Default for PerNs<T> {
92 fn default() -> Self {
93 PerNs { types: None, values: None }
94 }
95}
96
97impl<T> PerNs<T> {
98 pub fn none() -> PerNs<T> {
99 PerNs { types: None, values: None }
100 }
101
102 pub fn values(t: T) -> PerNs<T> {
103 PerNs { types: None, values: Some(t) }
104 }
105
106 pub fn types(t: T) -> PerNs<T> {
107 PerNs { types: Some(t), values: None }
108 }
109
110 pub fn both(types: T, values: T) -> PerNs<T> {
111 PerNs { types: Some(types), values: Some(values) }
112 }
113
114 pub fn is_none(&self) -> bool {
115 self.types.is_none() && self.values.is_none()
116 }
117
118 pub fn is_both(&self) -> bool {
119 self.types.is_some() && self.values.is_some()
120 }
121
122 pub fn take(self, namespace: Namespace) -> Option<T> {
123 match namespace {
124 Namespace::Types => self.types,
125 Namespace::Values => self.values,
126 }
127 }
128
129 pub fn take_types(self) -> Option<T> {
130 self.take(Namespace::Types)
131 }
132
133 pub fn take_values(self) -> Option<T> {
134 self.take(Namespace::Values)
135 }
136
137 pub fn get(&self, namespace: Namespace) -> Option<&T> {
138 self.as_ref().take(namespace)
139 }
140
141 pub fn as_ref(&self) -> PerNs<&T> {
142 PerNs { types: self.types.as_ref(), values: self.values.as_ref() }
143 }
144
145 pub fn or(self, other: PerNs<T>) -> PerNs<T> {
146 PerNs { types: self.types.or(other.types), values: self.values.or(other.values) }
147 }
148
149 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
150 PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) }
151 }
152
153 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
154 PerNs { types: self.types.map(&f), values: self.values.map(&f) }
155 }
156}
157
158struct Resolver<'a, DB> {
159 db: &'a DB,
160 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
161 krate: Crate,
162 module_tree: Arc<ModuleTree>,
163 processed_imports: FxHashSet<(ModuleId, ImportId)>,
164 /// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import)
165 glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, ImportId)>>,
166 result: ItemMap,
167}
168
169impl<'a, DB> Resolver<'a, DB>
170where
171 DB: PersistentHirDatabase,
172{
173 fn new(
174 db: &'a DB,
175 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
176 krate: Crate,
177 ) -> Resolver<'a, DB> {
178 let module_tree = db.module_tree(krate);
179 Resolver {
180 db,
181 input,
182 krate,
183 module_tree,
184 processed_imports: FxHashSet::default(),
185 glob_imports: FxHashMap::default(),
186 result: ItemMap {
187 edition: krate.edition(db),
188 prelude: None,
189 extern_prelude: FxHashMap::default(),
190 per_module: ArenaMap::default(),
191 },
192 }
193 }
194
195 pub(crate) fn resolve(mut self) -> ItemMap {
196 self.populate_extern_prelude();
197 for (&module_id, items) in self.input.iter() {
198 self.populate_module(module_id, Arc::clone(items));
199 }
200
201 let mut iter = 0;
202 loop {
203 iter += 1;
204 if iter > 1000 {
205 panic!("failed to reach fixedpoint after 1000 iters")
206 }
207 let processed_imports_count = self.processed_imports.len();
208 for &module_id in self.input.keys() {
209 self.db.check_canceled();
210 self.resolve_imports(module_id);
211 }
212 if processed_imports_count == self.processed_imports.len() {
213 // no new imports resolved
214 break;
215 }
216 }
217 self.result
218 }
219
220 fn populate_extern_prelude(&mut self) {
221 for dep in self.krate.dependencies(self.db) {
222 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
223 if let Some(module) = dep.krate.root_module(self.db) {
224 self.result.extern_prelude.insert(dep.name.clone(), module.into());
225 }
226 // look for the prelude
227 if self.result.prelude.is_none() {
228 let item_map = self.db.item_map(dep.krate);
229 if item_map.prelude.is_some() {
230 self.result.prelude = item_map.prelude;
231 }
232 }
233 }
234 }
235
236 fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) {
237 let mut module_items = ModuleScope::default();
238 for (import_id, import_data) in input.imports.iter() {
239 if let Some(last_segment) = import_data.path.segments.iter().last() {
240 if !import_data.is_glob {
241 let name =
242 import_data.alias.clone().unwrap_or_else(|| last_segment.name.clone());
243 module_items
244 .items
245 .insert(name, Resolution { def: PerNs::none(), import: Some(import_id) });
246 }
247 }
248 }
249 // Populate explicitly declared items, except modules
250 for (name, &def) in input.declarations.iter() {
251 let resolution = Resolution { def, import: None };
252 module_items.items.insert(name.clone(), resolution);
253 }
254
255 // Populate modules
256 for (name, module_id) in module_id.children(&self.module_tree) {
257 let module = Module { module_id, krate: self.krate };
258 self.add_module_item(&mut module_items, name, PerNs::types(module.into()));
259 }
260
261 self.result.per_module.insert(module_id, module_items);
262 }
263
264 fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def: PerNs<ModuleDef>) {
265 let resolution = Resolution { def, import: None };
266 module_items.items.insert(name, resolution);
267 }
268
269 fn resolve_imports(&mut self, module_id: ModuleId) {
270 for (import_id, import_data) in self.input[&module_id].imports.iter() {
271 if self.processed_imports.contains(&(module_id, import_id)) {
272 // already done
273 continue;
274 }
275 if self.resolve_import(module_id, import_id, import_data) == ReachedFixedPoint::Yes {
276 log::debug!("import {:?} resolved (or definite error)", import_id);
277 self.processed_imports.insert((module_id, import_id));
278 }
279 }
280 }
281
282 fn resolve_import(
283 &mut self,
284 module_id: ModuleId,
285 import_id: ImportId,
286 import: &ImportData,
287 ) -> ReachedFixedPoint {
288 log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
289 let original_module = Module { krate: self.krate, module_id };
290
291 let (def, reached_fixedpoint) = if import.is_extern_crate {
292 let res = self.result.resolve_name_in_extern_prelude(
293 &import
294 .path
295 .as_ident()
296 .expect("extern crate should have been desugared to one-element path"),
297 );
298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
299 } else {
300 let res = self.result.resolve_path_fp(
301 self.db,
302 ResolveMode::Import,
303 original_module,
304 &import.path,
305 );
306
307 (res.resolved_def, res.reached_fixedpoint)
308 };
309
310 if reached_fixedpoint != ReachedFixedPoint::Yes {
311 return reached_fixedpoint;
312 }
313
314 if import.is_glob {
315 log::debug!("glob import: {:?}", import);
316 match def.take_types() {
317 Some(ModuleDef::Module(m)) => {
318 if import.is_prelude {
319 tested_by!(std_prelude);
320 self.result.prelude = Some(m);
321 } else if m.krate != self.krate {
322 tested_by!(glob_across_crates);
323 // glob import from other crate => we can just import everything once
324 let item_map = self.db.item_map(m.krate);
325 let scope = &item_map[m.module_id];
326 let items = scope
327 .items
328 .iter()
329 .map(|(name, res)| (name.clone(), res.clone()))
330 .collect::<Vec<_>>();
331 self.update(module_id, Some(import_id), &items);
332 } else {
333 // glob import from same crate => we do an initial
334 // import, and then need to propagate any further
335 // additions
336 let scope = &self.result[m.module_id];
337 let items = scope
338 .items
339 .iter()
340 .map(|(name, res)| (name.clone(), res.clone()))
341 .collect::<Vec<_>>();
342 self.update(module_id, Some(import_id), &items);
343 // record the glob import in case we add further items
344 self.glob_imports
345 .entry(m.module_id)
346 .or_default()
347 .push((module_id, import_id));
348 }
349 }
350 Some(ModuleDef::Enum(e)) => {
351 tested_by!(glob_enum);
352 // glob import from enum => just import all the variants
353 let variants = e.variants(self.db);
354 let resolutions = variants
355 .into_iter()
356 .filter_map(|variant| {
357 let res = Resolution {
358 def: PerNs::both(variant.into(), variant.into()),
359 import: Some(import_id),
360 };
361 let name = variant.name(self.db)?;
362 Some((name, res))
363 })
364 .collect::<Vec<_>>();
365 self.update(module_id, Some(import_id), &resolutions);
366 }
367 Some(d) => {
368 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
369 }
370 None => {
371 log::debug!("glob import {:?} didn't resolve as type", import);
372 }
373 }
374 } else {
375 let last_segment = import.path.segments.last().unwrap();
376 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
377 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
378
379 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
380 if let Some(root_module) = self.krate.root_module(self.db) {
381 if import.is_extern_crate && module_id == root_module.module_id {
382 if let Some(def) = def.take_types() {
383 self.result.extern_prelude.insert(name.clone(), def);
384 }
385 }
386 }
387 let resolution = Resolution { def, import: Some(import_id) };
388 self.update(module_id, None, &[(name, resolution)]);
389 }
390 reached_fixedpoint
391 }
392
393 fn update(
394 &mut self,
395 module_id: ModuleId,
396 import: Option<ImportId>,
397 resolutions: &[(Name, Resolution)],
398 ) {
399 self.update_recursive(module_id, import, resolutions, 0)
400 }
401
402 fn update_recursive(
403 &mut self,
404 module_id: ModuleId,
405 import: Option<ImportId>,
406 resolutions: &[(Name, Resolution)],
407 depth: usize,
408 ) {
409 if depth > 100 {
410 // prevent stack overflows (but this shouldn't be possible)
411 panic!("infinite recursion in glob imports!");
412 }
413 let module_items = self.result.per_module.get_mut(module_id).unwrap();
414 let mut changed = false;
415 for (name, res) in resolutions {
416 let existing = module_items.items.entry(name.clone()).or_default();
417 if existing.def.types.is_none() && res.def.types.is_some() {
418 existing.def.types = res.def.types;
419 existing.import = import.or(res.import);
420 changed = true;
421 }
422 if existing.def.values.is_none() && res.def.values.is_some() {
423 existing.def.values = res.def.values;
424 existing.import = import.or(res.import);
425 changed = true;
426 }
427 }
428 if !changed {
429 return;
430 }
431 let glob_imports = self
432 .glob_imports
433 .get(&module_id)
434 .into_iter()
435 .flat_map(|v| v.iter())
436 .cloned()
437 .collect::<Vec<_>>();
438 for (glob_importing_module, glob_import) in glob_imports {
439 // We pass the glob import so that the tracked import in those modules is that glob import
440 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
441 }
442 }
443}
444
445#[derive(Debug, Clone)] 165#[derive(Debug, Clone)]
446struct ResolvePathResult { 166struct ResolvePathResult {
447 resolved_def: PerNs<ModuleDef>, 167 resolved_def: PerNs<ModuleDef>,
@@ -475,84 +195,85 @@ enum ReachedFixedPoint {
475 No, 195 No,
476} 196}
477 197
478impl ItemMap { 198impl CrateDefMap {
479 pub(crate) fn item_map_query(db: &impl PersistentHirDatabase, krate: Crate) -> Arc<ItemMap> { 199 pub(crate) fn crate_def_map_query(
480 let start = time::Instant::now(); 200 db: &impl PersistentHirDatabase,
481 let module_tree = db.module_tree(krate); 201 krate: Crate,
482 let input = module_tree 202 ) -> Arc<CrateDefMap> {
483 .modules() 203 let start = std::time::Instant::now();
484 .map(|module_id| (module_id, db.lower_module(Module { krate, module_id }))) 204 let def_map = {
485 .collect::<FxHashMap<_, _>>(); 205 let edition = krate.edition(db);
486 206 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
487 let resolver = Resolver::new(db, &input, krate); 207 let root = modules.alloc(ModuleData::default());
488 let res = resolver.resolve(); 208 CrateDefMap {
489 let elapsed = start.elapsed(); 209 krate,
490 log::info!("item_map: {:?}", elapsed); 210 edition,
491 Arc::new(res) 211 extern_prelude: FxHashMap::default(),
212 prelude: None,
213 root,
214 modules,
215 macros: Arena::default(),
216 public_macros: FxHashMap::default(),
217 macro_resolutions: FxHashMap::default(),
218 problems: CrateDefMapProblems::default(),
219 }
220 };
221 let def_map = collector::collect_defs(db, def_map);
222 log::info!("crate_def_map_query: {:?}", start.elapsed());
223 Arc::new(def_map)
492 } 224 }
493 225
494 pub(crate) fn resolve_path( 226 pub(crate) fn root(&self) -> CrateModuleId {
495 &self, 227 self.root
496 db: &impl PersistentHirDatabase,
497 original_module: Module,
498 path: &Path,
499 ) -> (PerNs<ModuleDef>, Option<usize>) {
500 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
501 (res.resolved_def, res.segment_index)
502 } 228 }
503 229
504 fn resolve_in_prelude( 230 pub(crate) fn problems(&self) -> &CrateDefMapProblems {
505 &self, 231 &self.problems
506 db: &impl PersistentHirDatabase,
507 original_module: Module,
508 name: &Name,
509 ) -> PerNs<ModuleDef> {
510 if let Some(prelude) = self.prelude {
511 let resolution = if prelude.krate == original_module.krate {
512 self[prelude.module_id].items.get(name).cloned()
513 } else {
514 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
515 };
516 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
517 } else {
518 PerNs::none()
519 }
520 } 232 }
521 233
522 pub(crate) fn resolve_name_in_module( 234 pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module {
523 &self, 235 Module { krate: self.krate, module_id }
524 db: &impl PersistentHirDatabase, 236 }
525 module: Module,
526 name: &Name,
527 ) -> PerNs<ModuleDef> {
528 // Resolve in:
529 // - current module / scope
530 // - extern prelude
531 // - std prelude
532 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
533 let from_extern_prelude =
534 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
535 let from_prelude = self.resolve_in_prelude(db, module, name);
536 237
537 from_scope.or(from_extern_prelude).or(from_prelude) 238 pub(crate) fn prelude(&self) -> Option<Module> {
239 self.prelude
538 } 240 }
539 241
540 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 242 pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> {
541 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) 243 &self.extern_prelude
542 } 244 }
543 245
544 fn resolve_name_in_crate_root_or_extern_prelude( 246 pub(crate) fn resolve_macro(
545 &self, 247 &self,
546 db: &impl PersistentHirDatabase, 248 macro_call_id: MacroCallId,
547 module: Module, 249 ) -> Option<(Crate, CrateMacroId)> {
548 name: &Name, 250 self.macro_resolutions.get(&macro_call_id).map(|&it| it)
549 ) -> PerNs<ModuleDef> { 251 }
550 let crate_root = module.crate_root(db);
551 let from_crate_root =
552 self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
553 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
554 252
555 from_crate_root.or(from_extern_prelude) 253 pub(crate) fn find_module_by_source(
254 &self,
255 file_id: HirFileId,
256 decl_id: Option<SourceFileItemId>,
257 ) -> Option<CrateModuleId> {
258 let decl_id = decl_id.map(|it| it.with_file_id(file_id));
259 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
260 if decl_id.is_some() {
261 module_data.declaration == decl_id
262 } else {
263 module_data.definition.map(|it| it.into()) == Some(file_id)
264 }
265 })?;
266 Some(module_id)
267 }
268
269 pub(crate) fn resolve_path(
270 &self,
271 db: &impl PersistentHirDatabase,
272 original_module: CrateModuleId,
273 path: &Path,
274 ) -> (PerNs<ModuleDef>, Option<usize>) {
275 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
276 (res.resolved_def, res.segment_index)
556 } 277 }
557 278
558 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 279 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -561,13 +282,17 @@ impl ItemMap {
561 &self, 282 &self,
562 db: &impl PersistentHirDatabase, 283 db: &impl PersistentHirDatabase,
563 mode: ResolveMode, 284 mode: ResolveMode,
564 original_module: Module, 285 original_module: CrateModuleId,
565 path: &Path, 286 path: &Path,
566 ) -> ResolvePathResult { 287 ) -> ResolvePathResult {
567 let mut segments = path.segments.iter().enumerate(); 288 let mut segments = path.segments.iter().enumerate();
568 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 289 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
569 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 290 PathKind::Crate => {
570 PathKind::Self_ => PerNs::types(original_module.into()), 291 PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
292 }
293 PathKind::Self_ => {
294 PerNs::types(Module { krate: self.krate, module_id: original_module }.into())
295 }
571 // plain import or absolute path in 2015: crate-relative with 296 // plain import or absolute path in 2015: crate-relative with
572 // fallback to extern prelude (with the simplification in 297 // fallback to extern prelude (with the simplification in
573 // rust-lang/rust#57745) 298 // rust-lang/rust#57745)
@@ -581,11 +306,7 @@ impl ItemMap {
581 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 306 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
582 }; 307 };
583 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 308 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
584 self.resolve_name_in_crate_root_or_extern_prelude( 309 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
585 db,
586 original_module,
587 &segment.name,
588 )
589 } 310 }
590 PathKind::Plain => { 311 PathKind::Plain => {
591 let segment = match segments.next() { 312 let segment = match segments.next() {
@@ -596,8 +317,8 @@ impl ItemMap {
596 self.resolve_name_in_module(db, original_module, &segment.name) 317 self.resolve_name_in_module(db, original_module, &segment.name)
597 } 318 }
598 PathKind::Super => { 319 PathKind::Super => {
599 if let Some(p) = original_module.parent(db) { 320 if let Some(p) = self.modules[original_module].parent {
600 PerNs::types(p.into()) 321 PerNs::types(Module { krate: self.krate, module_id: p }.into())
601 } else { 322 } else {
602 log::debug!("super path in root module"); 323 log::debug!("super path in root module");
603 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 324 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -634,14 +355,14 @@ impl ItemMap {
634 355
635 curr_per_ns = match curr { 356 curr_per_ns = match curr {
636 ModuleDef::Module(module) => { 357 ModuleDef::Module(module) => {
637 if module.krate != original_module.krate { 358 if module.krate != self.krate {
638 let path = Path { 359 let path = Path {
639 segments: path.segments[i..].iter().cloned().collect(), 360 segments: path.segments[i..].iter().cloned().collect(),
640 kind: PathKind::Self_, 361 kind: PathKind::Self_,
641 }; 362 };
642 log::debug!("resolving {:?} in other crate", path); 363 log::debug!("resolving {:?} in other crate", path);
643 let item_map = db.item_map(module.krate); 364 let defp_map = db.crate_def_map(module.krate);
644 let (def, s) = item_map.resolve_path(db, *module, &path); 365 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
645 return ResolvePathResult::with( 366 return ResolvePathResult::with(
646 def, 367 def,
647 ReachedFixedPoint::Yes, 368 ReachedFixedPoint::Yes,
@@ -649,7 +370,7 @@ impl ItemMap {
649 ); 370 );
650 } 371 }
651 372
652 match self[module.module_id].items.get(&segment.name) { 373 match self[module.module_id].scope.items.get(&segment.name) {
653 Some(res) if !res.def.is_none() => res.def, 374 Some(res) if !res.def.is_none() => res.def,
654 _ => { 375 _ => {
655 log::debug!("path segment {:?} not found", segment.name); 376 log::debug!("path segment {:?} not found", segment.name);
@@ -659,7 +380,7 @@ impl ItemMap {
659 } 380 }
660 ModuleDef::Enum(e) => { 381 ModuleDef::Enum(e) => {
661 // enum variant 382 // enum variant
662 tested_by!(item_map_enum_importing); 383 tested_by!(can_import_enum_variant);
663 match e.variant(db, &segment.name) { 384 match e.variant(db, &segment.name) {
664 Some(variant) => PerNs::both(variant.into(), variant.into()), 385 Some(variant) => PerNs::both(variant.into(), variant.into()),
665 None => { 386 None => {
@@ -690,7 +411,47 @@ impl ItemMap {
690 } 411 }
691 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 412 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
692 } 413 }
693}
694 414
695#[cfg(test)] 415 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
696mod tests; 416 let from_crate_root =
417 self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def);
418 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
419
420 from_crate_root.or(from_extern_prelude)
421 }
422
423 pub(crate) fn resolve_name_in_module(
424 &self,
425 db: &impl PersistentHirDatabase,
426 module: CrateModuleId,
427 name: &Name,
428 ) -> PerNs<ModuleDef> {
429 // Resolve in:
430 // - current module / scope
431 // - extern prelude
432 // - std prelude
433 let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def);
434 let from_extern_prelude =
435 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
436 let from_prelude = self.resolve_in_prelude(db, name);
437
438 from_scope.or(from_extern_prelude).or(from_prelude)
439 }
440
441 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
442 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
443 }
444
445 fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> {
446 if let Some(prelude) = self.prelude {
447 let resolution = if prelude.krate == self.krate {
448 self[prelude.module_id].scope.items.get(name).cloned()
449 } else {
450 db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned()
451 };
452 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
453 } else {
454 PerNs::none()
455 }
456 }
457}
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
new file mode 100644
index 000000000..12ed49a0a
--- /dev/null
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -0,0 +1,564 @@
1use arrayvec::ArrayVec;
2use rustc_hash::FxHashMap;
3use relative_path::RelativePathBuf;
4use test_utils::tested_by;
5use ra_db::FileId;
6
7use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 PersistentHirDatabase, HirFileId, Name, Path, Problem, Crate,
10 KnownName,
11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw},
12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
13};
14
15use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId};
16
17pub(super) fn collect_defs(
18 db: &impl PersistentHirDatabase,
19 mut def_map: CrateDefMap,
20) -> CrateDefMap {
21 // populate external prelude
22 for dep in def_map.krate.dependencies(db) {
23 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
24 if let Some(module) = dep.krate.root_module(db) {
25 def_map.extern_prelude.insert(dep.name.clone(), module.into());
26 }
27 // look for the prelude
28 if def_map.prelude.is_none() {
29 let map = db.crate_def_map(dep.krate);
30 if map.prelude.is_some() {
31 def_map.prelude = map.prelude;
32 }
33 }
34 }
35
36 let mut collector = DefCollector {
37 db,
38 def_map,
39 glob_imports: FxHashMap::default(),
40 unresolved_imports: Vec::new(),
41 unexpanded_macros: Vec::new(),
42 global_macro_scope: FxHashMap::default(),
43 };
44 collector.collect();
45 collector.finish()
46}
47
48/// Walks the tree of module recursively
49struct DefCollector<DB> {
50 db: DB,
51 def_map: CrateDefMap,
52 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
53 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
54 unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>,
55 global_macro_scope: FxHashMap<Name, CrateMacroId>,
56}
57
58impl<'a, DB> DefCollector<&'a DB>
59where
60 DB: PersistentHirDatabase,
61{
62 fn collect(&mut self) {
63 let crate_graph = self.db.crate_graph();
64 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
65 let raw_items = self.db.raw_items(file_id);
66 let module_id = self.def_map.root;
67 self.def_map.modules[module_id].definition = Some(file_id);
68 ModCollector {
69 def_collector: &mut *self,
70 module_id,
71 file_id: file_id.into(),
72 raw_items: &raw_items,
73 }
74 .collect(raw_items.items());
75
76 // main name resolution fixed-point loop.
77 let mut i = 0;
78 loop {
79 match (self.resolve_imports(), self.resolve_macros()) {
80 (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break,
81 _ => i += 1,
82 }
83 if i == 1000 {
84 log::error!("diverging name resolution");
85 break;
86 }
87 }
88
89 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
90 // show unresolved imports in completion, etc
91 for (module_id, import, import_data) in unresolved_imports {
92 self.record_resolved_import(module_id, PerNs::none(), import, &import_data)
93 }
94 }
95
96 fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) {
97 if let Ok(rules) = mbe::MacroRules::parse(tt) {
98 let macro_id = self.def_map.macros.alloc(rules);
99 if export {
100 self.def_map.public_macros.insert(name.clone(), macro_id);
101 }
102 self.global_macro_scope.insert(name, macro_id);
103 }
104 }
105
106 fn resolve_imports(&mut self) -> ReachedFixedPoint {
107 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
108 let mut resolved = Vec::new();
109 imports.retain(|(module_id, import, import_data)| {
110 let (def, fp) = self.resolve_import(*module_id, import_data);
111 if fp == ReachedFixedPoint::Yes {
112 resolved.push((*module_id, def, *import, import_data.clone()))
113 }
114 fp == ReachedFixedPoint::No
115 });
116 self.unresolved_imports = imports;
117 // Resolves imports, filling-in module scopes
118 let result =
119 if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
120 for (module_id, def, import, import_data) in resolved {
121 self.record_resolved_import(module_id, def, import, &import_data)
122 }
123 result
124 }
125
126 fn resolve_import(
127 &mut self,
128 module_id: CrateModuleId,
129 import: &raw::ImportData,
130 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
131 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
132 if import.is_extern_crate {
133 let res = self.def_map.resolve_name_in_extern_prelude(
134 &import
135 .path
136 .as_ident()
137 .expect("extern crate should have been desugared to one-element path"),
138 );
139 (res, ReachedFixedPoint::Yes)
140 } else {
141 let res =
142 self.def_map.resolve_path_fp(self.db, ResolveMode::Import, module_id, &import.path);
143
144 (res.resolved_def, res.reached_fixedpoint)
145 }
146 }
147
148 fn record_resolved_import(
149 &mut self,
150 module_id: CrateModuleId,
151 def: PerNs<ModuleDef>,
152 import_id: raw::ImportId,
153 import: &raw::ImportData,
154 ) {
155 if import.is_glob {
156 log::debug!("glob import: {:?}", import);
157 match def.take_types() {
158 Some(ModuleDef::Module(m)) => {
159 if import.is_prelude {
160 tested_by!(std_prelude);
161 self.def_map.prelude = Some(m);
162 } else if m.krate != self.def_map.krate {
163 tested_by!(glob_across_crates);
164 // glob import from other crate => we can just import everything once
165 let item_map = self.db.crate_def_map(m.krate);
166 let scope = &item_map[m.module_id].scope;
167 let items = scope
168 .items
169 .iter()
170 .map(|(name, res)| (name.clone(), res.clone()))
171 .collect::<Vec<_>>();
172 self.update(module_id, Some(import_id), &items);
173 } else {
174 // glob import from same crate => we do an initial
175 // import, and then need to propagate any further
176 // additions
177 let scope = &self.def_map[m.module_id].scope;
178 let items = scope
179 .items
180 .iter()
181 .map(|(name, res)| (name.clone(), res.clone()))
182 .collect::<Vec<_>>();
183 self.update(module_id, Some(import_id), &items);
184 // record the glob import in case we add further items
185 self.glob_imports
186 .entry(m.module_id)
187 .or_default()
188 .push((module_id, import_id));
189 }
190 }
191 Some(ModuleDef::Enum(e)) => {
192 tested_by!(glob_enum);
193 // glob import from enum => just import all the variants
194 let variants = e.variants(self.db);
195 let resolutions = variants
196 .into_iter()
197 .filter_map(|variant| {
198 let res = Resolution {
199 def: PerNs::both(variant.into(), variant.into()),
200 import: Some(import_id),
201 };
202 let name = variant.name(self.db)?;
203 Some((name, res))
204 })
205 .collect::<Vec<_>>();
206 self.update(module_id, Some(import_id), &resolutions);
207 }
208 Some(d) => {
209 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
210 }
211 None => {
212 log::debug!("glob import {:?} didn't resolve as type", import);
213 }
214 }
215 } else {
216 match import.path.segments.last() {
217 Some(last_segment) => {
218 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
219 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
220
221 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
222 if import.is_extern_crate && module_id == self.def_map.root {
223 if let Some(def) = def.take_types() {
224 self.def_map.extern_prelude.insert(name.clone(), def);
225 }
226 }
227 let resolution = Resolution { def, import: Some(import_id) };
228 self.update(module_id, Some(import_id), &[(name, resolution)]);
229 }
230 None => tested_by!(bogus_paths),
231 }
232 }
233 }
234
235 fn update(
236 &mut self,
237 module_id: CrateModuleId,
238 import: Option<raw::ImportId>,
239 resolutions: &[(Name, Resolution)],
240 ) {
241 self.update_recursive(module_id, import, resolutions, 0)
242 }
243
244 fn update_recursive(
245 &mut self,
246 module_id: CrateModuleId,
247 import: Option<raw::ImportId>,
248 resolutions: &[(Name, Resolution)],
249 depth: usize,
250 ) {
251 if depth > 100 {
252 // prevent stack overflows (but this shouldn't be possible)
253 panic!("infinite recursion in glob imports!");
254 }
255 let module_items = &mut self.def_map.modules[module_id].scope;
256 let mut changed = false;
257 for (name, res) in resolutions {
258 let existing = module_items.items.entry(name.clone()).or_default();
259 if existing.def.types.is_none() && res.def.types.is_some() {
260 existing.def.types = res.def.types;
261 existing.import = import.or(res.import);
262 changed = true;
263 }
264 if existing.def.values.is_none() && res.def.values.is_some() {
265 existing.def.values = res.def.values;
266 existing.import = import.or(res.import);
267 changed = true;
268 }
269 if existing.def.is_none()
270 && res.def.is_none()
271 && existing.import.is_none()
272 && res.import.is_some()
273 {
274 existing.import = res.import;
275 }
276 }
277 if !changed {
278 return;
279 }
280 let glob_imports = self
281 .glob_imports
282 .get(&module_id)
283 .into_iter()
284 .flat_map(|v| v.iter())
285 .cloned()
286 .collect::<Vec<_>>();
287 for (glob_importing_module, glob_import) in glob_imports {
288 // We pass the glob import so that the tracked import in those modules is that glob import
289 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
290 }
291 }
292
293 // XXX: this is just a pile of hacks now, because `PerNs` does not handle
294 // macro namespace.
295 fn resolve_macros(&mut self) -> ReachedFixedPoint {
296 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
297 let mut resolved = Vec::new();
298 let mut res = ReachedFixedPoint::Yes;
299 macros.retain(|(module_id, call_id, path, tt)| {
300 if path.segments.len() != 2 {
301 return true;
302 }
303 let crate_name = &path.segments[0].name;
304 let krate = match self.def_map.resolve_name_in_extern_prelude(crate_name).take_types() {
305 Some(ModuleDef::Module(m)) => m.krate(self.db),
306 _ => return true,
307 };
308 let krate = match krate {
309 Some(it) => it,
310 _ => return true,
311 };
312 res = ReachedFixedPoint::No;
313 let def_map = self.db.crate_def_map(krate);
314 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() {
315 resolved.push((*module_id, *call_id, (krate, macro_id), tt.clone()));
316 }
317 false
318 });
319
320 for (module_id, macro_call_id, macro_def_id, arg) in resolved {
321 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id, arg);
322 }
323 res
324 }
325
326 fn collect_macro_expansion(
327 &mut self,
328 module_id: CrateModuleId,
329 macro_call_id: MacroCallId,
330 macro_def_id: (Crate, CrateMacroId),
331 macro_arg: tt::Subtree,
332 ) {
333 let (macro_krate, macro_id) = macro_def_id;
334 let dm;
335 let rules = if macro_krate == self.def_map.krate {
336 &self.def_map[macro_id]
337 } else {
338 dm = self.db.crate_def_map(macro_krate);
339 &dm[macro_id]
340 };
341 if let Ok(expansion) = rules.expand(&macro_arg) {
342 self.def_map.macro_resolutions.insert(macro_call_id, macro_def_id);
343 // XXX: this **does not** go through a database, because we can't
344 // identify macro_call without adding the whole state of name resolution
345 // as a parameter to the query.
346 //
347 // So, we run the queries "manually" and we must ensure that
348 // `db.hir_parse(macro_call_id)` returns the same source_file.
349 let file_id: HirFileId = macro_call_id.into();
350 let source_file = mbe::token_tree_to_ast_item_list(&expansion);
351
352 let raw_items = raw::RawItems::from_source_file(&source_file, file_id);
353 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
354 .collect(raw_items.items())
355 }
356 }
357
358 fn finish(self) -> CrateDefMap {
359 self.def_map
360 }
361}
362
363/// Walks a single module, populating defs, imports and macros
364struct ModCollector<'a, D> {
365 def_collector: D,
366 module_id: CrateModuleId,
367 file_id: HirFileId,
368 raw_items: &'a raw::RawItems,
369}
370
371impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>>
372where
373 DB: PersistentHirDatabase,
374{
375 fn collect(&mut self, items: &[raw::RawItem]) {
376 for item in items {
377 match *item {
378 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]),
379 raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push((
380 self.module_id,
381 import,
382 self.raw_items[import].clone(),
383 )),
384 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]),
385 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
386 }
387 }
388 }
389
390 fn collect_module(&mut self, module: &raw::ModuleData) {
391 match module {
392 // inline module, just recurse
393 raw::ModuleData::Definition { name, items, source_item_id } => {
394 let module_id = self.push_child_module(
395 name.clone(),
396 source_item_id.with_file_id(self.file_id),
397 None,
398 );
399 ModCollector {
400 def_collector: &mut *self.def_collector,
401 module_id,
402 file_id: self.file_id,
403 raw_items: self.raw_items,
404 }
405 .collect(&*items);
406 }
407 // out of line module, resovle, parse and recurse
408 raw::ModuleData::Declaration { name, source_item_id } => {
409 let source_item_id = source_item_id.with_file_id(self.file_id);
410 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
411 let (file_ids, problem) =
412 resolve_submodule(self.def_collector.db, self.file_id, name, is_root);
413
414 if let Some(problem) = problem {
415 self.def_collector.def_map.problems.add(source_item_id, problem)
416 }
417
418 if let Some(&file_id) = file_ids.first() {
419 let module_id =
420 self.push_child_module(name.clone(), source_item_id, Some(file_id));
421 let raw_items = self.def_collector.db.raw_items(file_id);
422 ModCollector {
423 def_collector: &mut *self.def_collector,
424 module_id,
425 file_id: file_id.into(),
426 raw_items: &raw_items,
427 }
428 .collect(raw_items.items())
429 }
430 }
431 }
432 }
433
434 fn push_child_module(
435 &mut self,
436 name: Name,
437 declaration: SourceItemId,
438 definition: Option<FileId>,
439 ) -> CrateModuleId {
440 let modules = &mut self.def_collector.def_map.modules;
441 let res = modules.alloc(ModuleData::default());
442 modules[res].parent = Some(self.module_id);
443 modules[res].declaration = Some(declaration);
444 modules[res].definition = definition;
445 modules[self.module_id].children.insert(name.clone(), res);
446 let resolution = Resolution {
447 def: PerNs::types(
448 Module { krate: self.def_collector.def_map.krate, module_id: res }.into(),
449 ),
450 import: None,
451 };
452 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
453 res
454 }
455
456 fn define_def(&mut self, def: &raw::DefData) {
457 let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id };
458 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into());
459 macro_rules! id {
460 () => {
461 AstItemDef::from_source_item_id_unchecked(ctx, def.source_item_id)
462 };
463 }
464 let name = def.name.clone();
465 let def: PerNs<ModuleDef> = match def.kind {
466 raw::DefKind::Function => PerNs::values(Function { id: id!() }.into()),
467 raw::DefKind::Struct => {
468 let s = Struct { id: id!() }.into();
469 PerNs::both(s, s)
470 }
471 raw::DefKind::Enum => PerNs::types(Enum { id: id!() }.into()),
472 raw::DefKind::Const => PerNs::values(Const { id: id!() }.into()),
473 raw::DefKind::Static => PerNs::values(Static { id: id!() }.into()),
474 raw::DefKind::Trait => PerNs::types(Trait { id: id!() }.into()),
475 raw::DefKind::TypeAlias => PerNs::types(TypeAlias { id: id!() }.into()),
476 };
477 let resolution = Resolution { def, import: None };
478 self.def_collector.update(self.module_id, None, &[(name, resolution)])
479 }
480
481 fn collect_macro(&mut self, mac: &raw::MacroData) {
482 // Case 1: macro rules, define a macro in crate-global mutable scope
483 if is_macro_rules(&mac.path) {
484 if let Some(name) = &mac.name {
485 self.def_collector.define_macro(name.clone(), &mac.arg, mac.export)
486 }
487 return;
488 }
489
490 let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id };
491 let macro_call_id = MacroCallLoc {
492 module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id },
493 source_item_id,
494 }
495 .id(self.def_collector.db);
496
497 // Case 2: try to expand macro_rules from this crate, triggering
498 // recursive item collection.
499 if let Some(&macro_id) =
500 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name))
501 {
502 self.def_collector.collect_macro_expansion(
503 self.module_id,
504 macro_call_id,
505 (self.def_collector.def_map.krate, macro_id),
506 mac.arg.clone(),
507 );
508 return;
509 }
510
511 // Case 3: path to a macro from another crate, expand during name resolution
512 self.def_collector.unexpanded_macros.push((
513 self.module_id,
514 macro_call_id,
515 mac.path.clone(),
516 mac.arg.clone(),
517 ))
518 }
519}
520
521fn is_macro_rules(path: &Path) -> bool {
522 path.as_ident().and_then(Name::as_known_name) == Some(KnownName::MacroRules)
523}
524
525fn resolve_submodule(
526 db: &impl PersistentHirDatabase,
527 file_id: HirFileId,
528 name: &Name,
529 is_root: bool,
530) -> (Vec<FileId>, Option<Problem>) {
531 // FIXME: handle submodules of inline modules properly
532 let file_id = file_id.original_file(db);
533 let source_root_id = db.file_source_root(file_id);
534 let path = db.file_relative_path(file_id);
535 let root = RelativePathBuf::default();
536 let dir_path = path.parent().unwrap_or(&root);
537 let mod_name = path.file_stem().unwrap_or("unknown");
538 let is_dir_owner = is_root || mod_name == "mod";
539
540 let file_mod = dir_path.join(format!("{}.rs", name));
541 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
542 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
543 let mut candidates = ArrayVec::<[_; 2]>::new();
544 if is_dir_owner {
545 candidates.push(file_mod.clone());
546 candidates.push(dir_mod);
547 } else {
548 candidates.push(file_dir_mod.clone());
549 };
550 let sr = db.source_root(source_root_id);
551 let points_to = candidates
552 .into_iter()
553 .filter_map(|path| sr.files.get(&path))
554 .map(|&it| it)
555 .collect::<Vec<_>>();
556 let problem = if points_to.is_empty() {
557 Some(Problem::UnresolvedModule {
558 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
559 })
560 } else {
561 None
562 };
563 (points_to, problem)
564}
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
deleted file mode 100644
index 56262ad6d..000000000
--- a/crates/ra_hir/src/nameres/lower.rs
+++ /dev/null
@@ -1,222 +0,0 @@
1use std::sync::Arc;
2
3use ra_syntax::{
4 AstNode, SourceFile, TreeArc, AstPtr,
5 ast::{self, ModuleItemOwner, NameOwner, AttrsOwner},
6};
7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8use rustc_hash::FxHashMap;
9
10use crate::{
11 SourceItemId, Path, ModuleSource, Name,
12 HirFileId, MacroCallLoc, AsName, PerNs, Function,
13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
14 ids::LocationCtx, PersistentHirDatabase,
15};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct ImportId(RawId);
19impl_arena_id!(ImportId);
20
21#[derive(Debug, PartialEq, Eq)]
22pub(super) struct ImportData {
23 pub(super) path: Path,
24 pub(super) alias: Option<Name>,
25 pub(super) is_glob: bool,
26 pub(super) is_prelude: bool,
27 pub(super) is_extern_crate: bool,
28}
29
30/// A set of items and imports declared inside a module, without relation to
31/// other modules.
32///
33/// This sits in-between raw syntax and name resolution and allows us to avoid
34/// recomputing name res: if two instance of `InputModuleItems` are the same, we
35/// can avoid redoing name resolution.
36#[derive(Debug, Default, PartialEq, Eq)]
37pub struct LoweredModule {
38 pub(crate) declarations: FxHashMap<Name, PerNs<ModuleDef>>,
39 pub(super) imports: Arena<ImportId, ImportData>,
40}
41
42#[derive(Debug, Default, PartialEq, Eq)]
43pub struct ImportSourceMap {
44 map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
45}
46
47impl ImportSourceMap {
48 fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
49 self.map.insert(import, AstPtr::new(segment))
50 }
51
52 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
53 let file = match source {
54 ModuleSource::SourceFile(file) => &*file,
55 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
56 };
57
58 self.map[import].to_node(file).to_owned()
59 }
60}
61
62impl LoweredModule {
63 pub(crate) fn lower_module_query(
64 db: &impl PersistentHirDatabase,
65 module: Module,
66 ) -> Arc<LoweredModule> {
67 db.lower_module_with_source_map(module).0
68 }
69
70 pub(crate) fn lower_module_with_source_map_query(
71 db: &impl PersistentHirDatabase,
72 module: Module,
73 ) -> (Arc<LoweredModule>, Arc<ImportSourceMap>) {
74 let (file_id, source) = module.definition_source(db);
75 let file_id: HirFileId = file_id.into();
76 let mut source_map = ImportSourceMap::default();
77 let mut res = LoweredModule::default();
78 match source {
79 ModuleSource::SourceFile(it) => {
80 res.fill(&mut source_map, db, module, file_id, &mut it.items_with_macros())
81 }
82 ModuleSource::Module(it) => {
83 if let Some(item_list) = it.item_list() {
84 res.fill(
85 &mut source_map,
86 db,
87 module,
88 file_id,
89 &mut item_list.items_with_macros(),
90 )
91 }
92 }
93 };
94 (Arc::new(res), Arc::new(source_map))
95 }
96
97 fn fill(
98 &mut self,
99 source_map: &mut ImportSourceMap,
100 db: &impl PersistentHirDatabase,
101 module: Module,
102 file_id: HirFileId,
103 items: &mut Iterator<Item = ast::ItemOrMacro>,
104 ) {
105 let file_items = db.file_items(file_id);
106
107 for item in items {
108 match item {
109 ast::ItemOrMacro::Item(it) => {
110 self.add_def_id(source_map, db, module, file_id, it);
111 }
112 ast::ItemOrMacro::Macro(macro_call) => {
113 let item_id = file_items.id_of_unchecked(macro_call.syntax());
114 let loc =
115 MacroCallLoc { module, source_item_id: SourceItemId { file_id, item_id } };
116 let id = loc.id(db);
117 let file_id = HirFileId::from(id);
118 //FIXME: expand recursively
119 for item in db.hir_parse(file_id).items() {
120 self.add_def_id(source_map, db, module, file_id, item);
121 }
122 }
123 }
124 }
125 }
126
127 fn add_def_id(
128 &mut self,
129 source_map: &mut ImportSourceMap,
130 db: &impl PersistentHirDatabase,
131 module: Module,
132 file_id: HirFileId,
133 item: &ast::ModuleItem,
134 ) {
135 let ctx = LocationCtx::new(db, module, file_id);
136 match item.kind() {
137 ast::ModuleItemKind::StructDef(it) => {
138 if let Some(name) = it.name() {
139 let s = Struct { id: ctx.to_def(it) };
140 let s: ModuleDef = s.into();
141 self.declarations.insert(name.as_name(), PerNs::both(s, s));
142 }
143 }
144 ast::ModuleItemKind::EnumDef(it) => {
145 if let Some(name) = it.name() {
146 let e = Enum { id: ctx.to_def(it) };
147 let e: ModuleDef = e.into();
148 self.declarations.insert(name.as_name(), PerNs::types(e));
149 }
150 }
151 ast::ModuleItemKind::FnDef(it) => {
152 if let Some(name) = it.name() {
153 let func = Function { id: ctx.to_def(it) };
154 self.declarations.insert(name.as_name(), PerNs::values(func.into()));
155 }
156 }
157 ast::ModuleItemKind::TraitDef(it) => {
158 if let Some(name) = it.name() {
159 let t = Trait { id: ctx.to_def(it) };
160 self.declarations.insert(name.as_name(), PerNs::types(t.into()));
161 }
162 }
163 ast::ModuleItemKind::TypeAliasDef(it) => {
164 if let Some(name) = it.name() {
165 let t = TypeAlias { id: ctx.to_def(it) };
166 self.declarations.insert(name.as_name(), PerNs::types(t.into()));
167 }
168 }
169 ast::ModuleItemKind::ImplBlock(_) => {
170 // impls don't define items
171 }
172 ast::ModuleItemKind::UseItem(it) => {
173 self.add_use_item(source_map, it);
174 }
175 ast::ModuleItemKind::ExternCrateItem(it) => {
176 if let Some(name_ref) = it.name_ref() {
177 let path = Path::from_name_ref(name_ref);
178 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
179 self.imports.alloc(ImportData {
180 path,
181 alias,
182 is_glob: false,
183 is_prelude: false,
184 is_extern_crate: true,
185 });
186 }
187 }
188 ast::ModuleItemKind::ConstDef(it) => {
189 if let Some(name) = it.name() {
190 let c = Const { id: ctx.to_def(it) };
191 self.declarations.insert(name.as_name(), PerNs::values(c.into()));
192 }
193 }
194 ast::ModuleItemKind::StaticDef(it) => {
195 if let Some(name) = it.name() {
196 let s = Static { id: ctx.to_def(it) };
197 self.declarations.insert(name.as_name(), PerNs::values(s.into()));
198 }
199 }
200 ast::ModuleItemKind::Module(_) => {
201 // modules are handled separately directly by name res
202 }
203 };
204 }
205
206 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
207 let is_prelude =
208 item.attrs().any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false));
209 Path::expand_use_item(item, |path, segment, alias| {
210 let import = self.imports.alloc(ImportData {
211 path,
212 alias,
213 is_glob: segment.is_none(),
214 is_prelude,
215 is_extern_crate: false,
216 });
217 if let Some(segment) = segment {
218 source_map.insert(import, segment)
219 }
220 })
221 }
222}
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs
new file mode 100644
index 000000000..c40a3ff9d
--- /dev/null
+++ b/crates/ra_hir/src/nameres/per_ns.rs
@@ -0,0 +1,78 @@
1#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2pub enum Namespace {
3 Types,
4 Values,
5}
6
7#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8pub struct PerNs<T> {
9 pub types: Option<T>,
10 pub values: Option<T>,
11}
12
13impl<T> Default for PerNs<T> {
14 fn default() -> Self {
15 PerNs { types: None, values: None }
16 }
17}
18
19impl<T> PerNs<T> {
20 pub fn none() -> PerNs<T> {
21 PerNs { types: None, values: None }
22 }
23
24 pub fn values(t: T) -> PerNs<T> {
25 PerNs { types: None, values: Some(t) }
26 }
27
28 pub fn types(t: T) -> PerNs<T> {
29 PerNs { types: Some(t), values: None }
30 }
31
32 pub fn both(types: T, values: T) -> PerNs<T> {
33 PerNs { types: Some(types), values: Some(values) }
34 }
35
36 pub fn is_none(&self) -> bool {
37 self.types.is_none() && self.values.is_none()
38 }
39
40 pub fn is_both(&self) -> bool {
41 self.types.is_some() && self.values.is_some()
42 }
43
44 pub fn take(self, namespace: Namespace) -> Option<T> {
45 match namespace {
46 Namespace::Types => self.types,
47 Namespace::Values => self.values,
48 }
49 }
50
51 pub fn take_types(self) -> Option<T> {
52 self.take(Namespace::Types)
53 }
54
55 pub fn take_values(self) -> Option<T> {
56 self.take(Namespace::Values)
57 }
58
59 pub fn get(&self, namespace: Namespace) -> Option<&T> {
60 self.as_ref().take(namespace)
61 }
62
63 pub fn as_ref(&self) -> PerNs<&T> {
64 PerNs { types: self.types.as_ref(), values: self.values.as_ref() }
65 }
66
67 pub fn or(self, other: PerNs<T>) -> PerNs<T> {
68 PerNs { types: self.types.or(other.types), values: self.values.or(other.values) }
69 }
70
71 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
72 PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) }
73 }
74
75 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
76 PerNs { types: self.types.map(&f), values: self.values.map(&f) }
77 }
78}
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
new file mode 100644
index 000000000..3226bbf0d
--- /dev/null
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -0,0 +1,322 @@
1use std::{
2 sync::Arc,
3 ops::Index,
4};
5
6use test_utils::tested_by;
7use ra_db::FileId;
8use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
9use ra_syntax::{
10 AstNode, SourceFile, AstPtr, TreeArc,
11 ast::{self, NameOwner, AttrsOwner},
12};
13
14use crate::{
15 PersistentHirDatabase, Name, AsName, Path, HirFileId, ModuleSource,
16 ids::{SourceFileItemId, SourceFileItems},
17};
18
19#[derive(Debug, Default, PartialEq, Eq)]
20pub struct RawItems {
21 modules: Arena<Module, ModuleData>,
22 imports: Arena<ImportId, ImportData>,
23 defs: Arena<Def, DefData>,
24 macros: Arena<Macro, MacroData>,
25 /// items for top-level module
26 items: Vec<RawItem>,
27}
28
29#[derive(Debug, Default, PartialEq, Eq)]
30pub struct ImportSourceMap {
31 map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
32}
33
34impl ImportSourceMap {
35 pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
36 self.map.insert(import, AstPtr::new(segment))
37 }
38
39 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
40 let file = match source {
41 ModuleSource::SourceFile(file) => &*file,
42 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
43 };
44
45 self.map[import].to_node(file).to_owned()
46 }
47}
48
49impl RawItems {
50 pub(crate) fn raw_items_query(
51 db: &impl PersistentHirDatabase,
52 file_id: FileId,
53 ) -> Arc<RawItems> {
54 db.raw_items_with_source_map(file_id).0
55 }
56
57 pub(crate) fn raw_items_with_source_map_query(
58 db: &impl PersistentHirDatabase,
59 file_id: FileId,
60 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
61 let mut collector = RawItemsCollector {
62 raw_items: RawItems::default(),
63 source_file_items: db.file_items(file_id.into()),
64 source_map: ImportSourceMap::default(),
65 };
66 let source_file = db.parse(file_id);
67 collector.process_module(None, &*source_file);
68 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
69 }
70
71 pub(crate) fn items(&self) -> &[RawItem] {
72 &self.items
73 }
74
75 // We can't use queries during name resolution for fear of cycles, so this
76 // is a query-less variant of the above function.
77 pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems {
78 let source_file_items = SourceFileItems::from_source_file(source_file, file_id);
79 let mut collector = RawItemsCollector {
80 raw_items: RawItems::default(),
81 source_file_items: Arc::new(source_file_items),
82 source_map: ImportSourceMap::default(),
83 };
84 collector.process_module(None, &*source_file);
85 collector.raw_items
86 }
87}
88
89impl Index<Module> for RawItems {
90 type Output = ModuleData;
91 fn index(&self, idx: Module) -> &ModuleData {
92 &self.modules[idx]
93 }
94}
95
96impl Index<ImportId> for RawItems {
97 type Output = ImportData;
98 fn index(&self, idx: ImportId) -> &ImportData {
99 &self.imports[idx]
100 }
101}
102
103impl Index<Def> for RawItems {
104 type Output = DefData;
105 fn index(&self, idx: Def) -> &DefData {
106 &self.defs[idx]
107 }
108}
109
110impl Index<Macro> for RawItems {
111 type Output = MacroData;
112 fn index(&self, idx: Macro) -> &MacroData {
113 &self.macros[idx]
114 }
115}
116
117#[derive(Debug, PartialEq, Eq, Clone, Copy)]
118pub(crate) enum RawItem {
119 Module(Module),
120 Import(ImportId),
121 Def(Def),
122 Macro(Macro),
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126pub(crate) struct Module(RawId);
127impl_arena_id!(Module);
128
129#[derive(Debug, PartialEq, Eq)]
130pub(crate) enum ModuleData {
131 Declaration { name: Name, source_item_id: SourceFileItemId },
132 Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> },
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
136pub struct ImportId(RawId);
137impl_arena_id!(ImportId);
138
139#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct ImportData {
141 pub(crate) path: Path,
142 pub(crate) alias: Option<Name>,
143 pub(crate) is_glob: bool,
144 pub(crate) is_prelude: bool,
145 pub(crate) is_extern_crate: bool,
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
149pub(crate) struct Def(RawId);
150impl_arena_id!(Def);
151
152#[derive(Debug, PartialEq, Eq)]
153pub(crate) struct DefData {
154 pub(crate) source_item_id: SourceFileItemId,
155 pub(crate) name: Name,
156 pub(crate) kind: DefKind,
157}
158
159#[derive(Debug, PartialEq, Eq, Clone, Copy)]
160pub(crate) enum DefKind {
161 Function,
162 Struct,
163 Enum,
164 Const,
165 Static,
166 Trait,
167 TypeAlias,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
171pub(crate) struct Macro(RawId);
172impl_arena_id!(Macro);
173
174#[derive(Debug, PartialEq, Eq)]
175pub(crate) struct MacroData {
176 pub(crate) source_item_id: SourceFileItemId,
177 pub(crate) path: Path,
178 pub(crate) name: Option<Name>,
179 pub(crate) arg: tt::Subtree,
180 pub(crate) export: bool,
181}
182
183struct RawItemsCollector {
184 raw_items: RawItems,
185 source_file_items: Arc<SourceFileItems>,
186 source_map: ImportSourceMap,
187}
188
189impl RawItemsCollector {
190 fn process_module(&mut self, current_module: Option<Module>, body: &impl ast::ModuleItemOwner) {
191 for item_or_macro in body.items_with_macros() {
192 match item_or_macro {
193 ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
194 ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
195 }
196 }
197 }
198
199 fn add_item(&mut self, current_module: Option<Module>, item: &ast::ModuleItem) {
200 let (kind, name) = match item.kind() {
201 ast::ModuleItemKind::Module(module) => {
202 self.add_module(current_module, module);
203 return;
204 }
205 ast::ModuleItemKind::UseItem(use_item) => {
206 self.add_use_item(current_module, use_item);
207 return;
208 }
209 ast::ModuleItemKind::ExternCrateItem(extern_crate) => {
210 self.add_extern_crate_item(current_module, extern_crate);
211 return;
212 }
213 ast::ModuleItemKind::ImplBlock(_) => {
214 // impls don't participate in name resolution
215 return;
216 }
217 ast::ModuleItemKind::StructDef(it) => (DefKind::Struct, it.name()),
218 ast::ModuleItemKind::EnumDef(it) => (DefKind::Enum, it.name()),
219 ast::ModuleItemKind::FnDef(it) => (DefKind::Function, it.name()),
220 ast::ModuleItemKind::TraitDef(it) => (DefKind::Trait, it.name()),
221 ast::ModuleItemKind::TypeAliasDef(it) => (DefKind::TypeAlias, it.name()),
222 ast::ModuleItemKind::ConstDef(it) => (DefKind::Const, it.name()),
223 ast::ModuleItemKind::StaticDef(it) => (DefKind::Static, it.name()),
224 };
225 if let Some(name) = name {
226 let name = name.as_name();
227 let source_item_id = self.source_file_items.id_of_unchecked(item.syntax());
228 let def = self.raw_items.defs.alloc(DefData { name, kind, source_item_id });
229 self.push_item(current_module, RawItem::Def(def))
230 }
231 }
232
233 fn add_module(&mut self, current_module: Option<Module>, module: &ast::Module) {
234 let name = match module.name() {
235 Some(it) => it.as_name(),
236 None => return,
237 };
238 let source_item_id = self.source_file_items.id_of_unchecked(module.syntax());
239 if module.has_semi() {
240 let item =
241 self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id });
242 self.push_item(current_module, RawItem::Module(item));
243 return;
244 }
245
246 if let Some(item_list) = module.item_list() {
247 let item = self.raw_items.modules.alloc(ModuleData::Definition {
248 name,
249 source_item_id,
250 items: Vec::new(),
251 });
252 self.process_module(Some(item), item_list);
253 self.push_item(current_module, RawItem::Module(item));
254 return;
255 }
256 tested_by!(name_res_works_for_broken_modules);
257 }
258
259 fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
260 let is_prelude = use_item.has_atom_attr("prelude_import");
261
262 Path::expand_use_item(use_item, |path, segment, alias| {
263 let import = self.raw_items.imports.alloc(ImportData {
264 path,
265 alias,
266 is_glob: segment.is_none(),
267 is_prelude,
268 is_extern_crate: false,
269 });
270 if let Some(segment) = segment {
271 self.source_map.insert(import, segment)
272 }
273 self.push_item(current_module, RawItem::Import(import))
274 })
275 }
276
277 fn add_extern_crate_item(
278 &mut self,
279 current_module: Option<Module>,
280 extern_crate: &ast::ExternCrateItem,
281 ) {
282 if let Some(name_ref) = extern_crate.name_ref() {
283 let path = Path::from_name_ref(name_ref);
284 let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name);
285 let import = self.raw_items.imports.alloc(ImportData {
286 path,
287 alias,
288 is_glob: false,
289 is_prelude: false,
290 is_extern_crate: true,
291 });
292 self.push_item(current_module, RawItem::Import(import))
293 }
294 }
295
296 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
297 let (path, arg) = match (
298 m.path().and_then(Path::from_ast),
299 m.token_tree().and_then(mbe::ast_to_token_tree),
300 ) {
301 (Some(path), Some((token_tree, _token_map))) => (path, token_tree),
302 _ => return,
303 };
304
305 let name = m.name().map(|it| it.as_name());
306 let source_item_id = self.source_file_items.id_of_unchecked(m.syntax());
307 let export = m.has_atom_attr("macro_export");
308 let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name, export });
309 self.push_item(current_module, RawItem::Macro(m));
310 }
311
312 fn push_item(&mut self, current_module: Option<Module>, item: RawItem) {
313 match current_module {
314 Some(module) => match &mut self.raw_items.modules[module] {
315 ModuleData::Definition { items, .. } => items,
316 ModuleData::Declaration { .. } => unreachable!(),
317 },
318 None => &mut self.raw_items.items,
319 }
320 .push(item)
321 }
322}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 9b151bb0c..ac9b88520 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -1,34 +1,43 @@
1mod macros;
2mod globs;
3mod incremental;
4
1use std::sync::Arc; 5use std::sync::Arc;
2 6
3use ra_db::SourceDatabase; 7use ra_db::SourceDatabase;
4use test_utils::{assert_eq_text, covers}; 8use test_utils::covers;
5 9use insta::assert_snapshot_matches;
6use crate::{ 10
7 ItemMap, 11use crate::{Crate, mock::{MockDatabase, CrateGraphFixture}, nameres::Resolution};
8 PersistentHirDatabase, 12
9 mock::MockDatabase, 13use super::*;
10 module_tree::ModuleId, 14
11}; 15fn compute_crate_def_map(fixture: &str, graph: Option<CrateGraphFixture>) -> Arc<CrateDefMap> {
12use super::Resolution; 16 let mut db = MockDatabase::with_files(fixture);
13 17 if let Some(graph) = graph {
14fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) { 18 db.set_crate_graph_from_fixture(graph);
15 let (db, pos) = MockDatabase::with_position(fixture); 19 }
16 let module = crate::source_binder::module_from_position(&db, pos).unwrap(); 20 let crate_id = db.crate_graph().iter().next().unwrap();
17 let krate = module.krate(&db).unwrap(); 21 let krate = Crate { crate_id };
18 let module_id = module.module_id; 22 db.crate_def_map(krate)
19 (db.item_map(krate), module_id)
20} 23}
21 24
22fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { 25fn render_crate_def_map(map: &CrateDefMap) -> String {
23 let mut lines = map[module_id] 26 let mut buf = String::new();
24 .items 27 go(&mut buf, map, "\ncrate", map.root);
25 .iter() 28 return buf;
26 .map(|(name, res)| format!("{}: {}", name, dump_resolution(res))) 29
27 .collect::<Vec<_>>(); 30 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) {
28 lines.sort(); 31 *buf += path;
29 let actual = lines.join("\n"); 32 *buf += "\n";
30 let expected = expected.trim().lines().map(|it| it.trim()).collect::<Vec<_>>().join("\n"); 33 for (name, res) in map.modules[module].scope.items.iter() {
31 assert_eq_text!(&expected, &actual); 34 *buf += &format!("{}: {}\n", name, dump_resolution(res))
35 }
36 for (name, child) in map.modules[module].children.iter() {
37 let path = path.to_string() + &format!("::{}", name);
38 go(buf, map, &path, *child);
39 }
40 }
32 41
33 fn dump_resolution(resolution: &Resolution) -> &'static str { 42 fn dump_resolution(resolution: &Resolution) -> &'static str {
34 match (resolution.def.types.is_some(), resolution.def.values.is_some()) { 43 match (resolution.def.types.is_some(), resolution.def.values.is_some()) {
@@ -40,66 +49,112 @@ fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) {
40 } 49 }
41} 50}
42 51
52fn def_map(fixtute: &str) -> String {
53 let dm = compute_crate_def_map(fixtute, None);
54 render_crate_def_map(&dm)
55}
56
57fn def_map_with_crate_graph(fixtute: &str, graph: CrateGraphFixture) -> String {
58 let dm = compute_crate_def_map(fixtute, Some(graph));
59 render_crate_def_map(&dm)
60}
61
43#[test] 62#[test]
44fn item_map_smoke_test() { 63fn crate_def_map_smoke_test() {
45 let (item_map, module_id) = item_map( 64 let map = def_map(
46 " 65 "
47 //- /lib.rs 66 //- /lib.rs
48 mod foo; 67 mod foo;
49 68 struct S;
50 use crate::foo::bar::Baz; 69 use crate::foo::bar::E;
51 <|> 70 use self::E::V;
52 71
53 //- /foo/mod.rs 72 //- /foo/mod.rs
54 pub mod bar; 73 pub mod bar;
74 fn f() {}
55 75
56 //- /foo/bar.rs 76 //- /foo/bar.rs
57 pub struct Baz; 77 pub struct Baz;
58 ", 78 enum E { V }
79 ",
59 ); 80 );
60 check_module_item_map( 81 assert_snapshot_matches!(map, @r###"
61 &item_map, 82crate
62 module_id, 83V: t v
84E: t
85foo: t
86S: t v
87
88crate::foo
89bar: t
90f: v
91
92crate::foo::bar
93Baz: t v
94E: t
95"###
96 )
97}
98
99#[test]
100fn bogus_paths() {
101 covers!(bogus_paths);
102 let map = def_map(
63 " 103 "
64 Baz: t v 104 //- /lib.rs
65 foo: t 105 mod foo;
106 struct S;
107 use self;
108
109 //- /foo/mod.rs
110 use super;
111 use crate;
112
66 ", 113 ",
67 ); 114 );
115 assert_snapshot_matches!(map, @r###"
116crate
117foo: t
118S: t v
119
120crate::foo
121"###
122 )
68} 123}
69 124
70#[test] 125#[test]
71fn use_as() { 126fn use_as() {
72 let (item_map, module_id) = item_map( 127 let map = def_map(
73 " 128 "
74 //- /lib.rs 129 //- /lib.rs
75 mod foo; 130 mod foo;
76 131
77 use crate::foo::Baz as Foo; 132 use crate::foo::Baz as Foo;
78 <|>
79 133
80 //- /foo/mod.rs 134 //- /foo/mod.rs
81 pub struct Baz; 135 pub struct Baz;
82 ",
83 );
84 check_module_item_map(
85 &item_map,
86 module_id,
87 "
88 Foo: t v
89 foo: t
90 ", 136 ",
91 ); 137 );
138 assert_snapshot_matches!(map,
139 @r###"
140crate
141Foo: t v
142foo: t
143
144crate::foo
145Baz: t v
146"###
147 );
92} 148}
93 149
94#[test] 150#[test]
95fn use_trees() { 151fn use_trees() {
96 let (item_map, module_id) = item_map( 152 let map = def_map(
97 " 153 "
98 //- /lib.rs 154 //- /lib.rs
99 mod foo; 155 mod foo;
100 156
101 use crate::foo::bar::{Baz, Quux}; 157 use crate::foo::bar::{Baz, Quux};
102 <|>
103 158
104 //- /foo/mod.rs 159 //- /foo/mod.rs
105 pub mod bar; 160 pub mod bar;
@@ -107,28 +162,33 @@ fn use_trees() {
107 //- /foo/bar.rs 162 //- /foo/bar.rs
108 pub struct Baz; 163 pub struct Baz;
109 pub enum Quux {}; 164 pub enum Quux {};
110 ",
111 );
112 check_module_item_map(
113 &item_map,
114 module_id,
115 "
116 Baz: t v
117 Quux: t
118 foo: t
119 ", 165 ",
120 ); 166 );
167 assert_snapshot_matches!(map,
168 @r###"
169crate
170Quux: t
171Baz: t v
172foo: t
173
174crate::foo
175bar: t
176
177crate::foo::bar
178Quux: t
179Baz: t v
180"###
181 );
121} 182}
122 183
123#[test] 184#[test]
124fn re_exports() { 185fn re_exports() {
125 let (item_map, module_id) = item_map( 186 let map = def_map(
126 " 187 "
127 //- /lib.rs 188 //- /lib.rs
128 mod foo; 189 mod foo;
129 190
130 use self::foo::Baz; 191 use self::foo::Baz;
131 <|>
132 192
133 //- /foo/mod.rs 193 //- /foo/mod.rs
134 pub mod bar; 194 pub mod bar;
@@ -137,137 +197,73 @@ fn re_exports() {
137 197
138 //- /foo/bar.rs 198 //- /foo/bar.rs
139 pub struct Baz; 199 pub struct Baz;
140 ",
141 );
142 check_module_item_map(
143 &item_map,
144 module_id,
145 "
146 Baz: t v
147 foo: t
148 ", 200 ",
149 ); 201 );
150} 202 assert_snapshot_matches!(map,
203 @r###"
204crate
205Baz: t v
206foo: t
151 207
152#[test] 208crate::foo
153fn glob_1() { 209bar: t
154 let (item_map, module_id) = item_map( 210Baz: t v
155 "
156 //- /lib.rs
157 mod foo;
158 use foo::*;
159 <|>
160
161 //- /foo/mod.rs
162 pub mod bar;
163 pub use self::bar::Baz;
164 pub struct Foo;
165 211
166 //- /foo/bar.rs 212crate::foo::bar
167 pub struct Baz; 213Baz: t v
168 ", 214"###
169 );
170 check_module_item_map(
171 &item_map,
172 module_id,
173 "
174 Baz: t v
175 Foo: t v
176 bar: t
177 foo: t
178 ",
179 ); 215 );
180} 216}
181 217
182#[test] 218#[test]
183fn glob_2() { 219fn std_prelude() {
184 let (item_map, module_id) = item_map( 220 covers!(std_prelude);
185 " 221 let map = def_map_with_crate_graph(
186 //- /lib.rs
187 mod foo;
188 use foo::*;
189 <|>
190
191 //- /foo/mod.rs
192 pub mod bar;
193 pub use self::bar::*;
194 pub struct Foo;
195
196 //- /foo/bar.rs
197 pub struct Baz;
198 pub use super::*;
199 ",
200 );
201 check_module_item_map(
202 &item_map,
203 module_id,
204 " 222 "
205 Baz: t v 223 //- /main.rs
206 Foo: t v 224 use Foo::*;
207 bar: t
208 foo: t
209 ",
210 );
211}
212 225
213#[test]
214fn glob_enum() {
215 covers!(glob_enum);
216 let (item_map, module_id) = item_map(
217 "
218 //- /lib.rs 226 //- /lib.rs
219 enum Foo { 227 mod prelude;
220 Bar, Baz 228 #[prelude_import]
221 } 229 use prelude::*;
222 use self::Foo::*; 230
223 <|> 231 //- /prelude.rs
224 ", 232 pub enum Foo { Bar, Baz };
225 );
226 check_module_item_map(
227 &item_map,
228 module_id,
229 "
230 Bar: t v
231 Baz: t v
232 Foo: t
233 ", 233 ",
234 crate_graph! {
235 "main": ("/main.rs", ["test_crate"]),
236 "test_crate": ("/lib.rs", []),
237 },
234 ); 238 );
239 assert_snapshot_matches!(map, @r###"
240crate
241Bar: t v
242Baz: t v
243"###);
235} 244}
236 245
237#[test] 246#[test]
238fn glob_across_crates() { 247fn can_import_enum_variant() {
239 covers!(glob_across_crates); 248 covers!(can_import_enum_variant);
240 let mut db = MockDatabase::with_files( 249 let map = def_map(
241 " 250 "
242 //- /main.rs
243 use test_crate::*;
244
245 //- /lib.rs 251 //- /lib.rs
246 pub struct Baz; 252 enum E { V }
253 use self::E::V;
247 ", 254 ",
248 ); 255 );
249 db.set_crate_graph_from_fixture(crate_graph! { 256 assert_snapshot_matches!(map, @r###"
250 "main": ("/main.rs", ["test_crate"]), 257crate
251 "test_crate": ("/lib.rs", []), 258V: t v
252 }); 259E: t
253 let main_id = db.file_id_of("/main.rs"); 260"###
254
255 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
256 let krate = module.krate(&db).unwrap();
257 let item_map = db.item_map(krate);
258
259 check_module_item_map(
260 &item_map,
261 module.module_id,
262 "
263 Baz: t v
264 ",
265 ); 261 );
266} 262}
267 263
268#[test] 264#[test]
269fn edition_2015_imports() { 265fn edition_2015_imports() {
270 let mut db = MockDatabase::with_files( 266 let map = def_map_with_crate_graph(
271 " 267 "
272 //- /main.rs 268 //- /main.rs
273 mod foo; 269 mod foo;
@@ -282,31 +278,32 @@ fn edition_2015_imports() {
282 278
283 //- /lib.rs 279 //- /lib.rs
284 struct FromLib; 280 struct FromLib;
285 ",
286 );
287 db.set_crate_graph_from_fixture(crate_graph! {
288 "main": ("/main.rs", "2015", ["other_crate"]),
289 "other_crate": ("/lib.rs", "2018", []),
290 });
291 let foo_id = db.file_id_of("/foo.rs");
292
293 let module = crate::source_binder::module_from_file_id(&db, foo_id).unwrap();
294 let krate = module.krate(&db).unwrap();
295 let item_map = db.item_map(krate);
296
297 check_module_item_map(
298 &item_map,
299 module.module_id,
300 "
301 Bar: t v
302 FromLib: t v
303 ", 281 ",
282 crate_graph! {
283 "main": ("/main.rs", "2015", ["other_crate"]),
284 "other_crate": ("/lib.rs", "2018", []),
285 },
286 );
287
288 assert_snapshot_matches!(map,
289 @r###"
290crate
291bar: t
292foo: t
293
294crate::bar
295Bar: t v
296
297crate::foo
298FromLib: t v
299Bar: t v
300"###
304 ); 301 );
305} 302}
306 303
307#[test] 304#[test]
308fn module_resolution_works_for_non_standard_filenames() { 305fn module_resolution_works_for_non_standard_filenames() {
309 let mut db = MockDatabase::with_files( 306 let map = def_map_with_crate_graph(
310 " 307 "
311 //- /my_library.rs 308 //- /my_library.rs
312 mod foo; 309 mod foo;
@@ -315,73 +312,32 @@ fn module_resolution_works_for_non_standard_filenames() {
315 //- /foo/mod.rs 312 //- /foo/mod.rs
316 pub struct Bar; 313 pub struct Bar;
317 ", 314 ",
315 crate_graph! {
316 "my_library": ("/my_library.rs", []),
317 },
318 ); 318 );
319 db.set_crate_graph_from_fixture(crate_graph! {
320 "my_library": ("/my_library.rs", []),
321 });
322 let file_id = db.file_id_of("/my_library.rs");
323
324 let module = crate::source_binder::module_from_file_id(&db, file_id).unwrap();
325 let krate = module.krate(&db).unwrap();
326 let module_id = module.module_id;
327 let item_map = db.item_map(krate);
328 check_module_item_map(
329 &item_map,
330 module_id,
331 "
332 Bar: t v
333 foo: t
334 ",
335 );
336}
337 319
338#[test] 320 assert_snapshot_matches!(map,
339fn std_prelude() { 321 @r###"
340 covers!(std_prelude); 322crate
341 let mut db = MockDatabase::with_files( 323Bar: t v
342 " 324foo: t
343 //- /main.rs
344 use Foo::*;
345
346 //- /lib.rs
347 mod prelude;
348 #[prelude_import]
349 use prelude::*;
350 325
351 //- /prelude.rs 326crate::foo
352 pub enum Foo { Bar, Baz }; 327Bar: t v
353 ", 328"###
354 );
355 db.set_crate_graph_from_fixture(crate_graph! {
356 "main": ("/main.rs", ["test_crate"]),
357 "test_crate": ("/lib.rs", []),
358 });
359 let main_id = db.file_id_of("/main.rs");
360
361 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
362 let krate = module.krate(&db).unwrap();
363 let item_map = db.item_map(krate);
364
365 check_module_item_map(
366 &item_map,
367 module.module_id,
368 "
369 Bar: t v
370 Baz: t v
371 ",
372 ); 329 );
373} 330}
374 331
375#[test] 332#[test]
376fn name_res_works_for_broken_modules() { 333fn name_res_works_for_broken_modules() {
377 covers!(name_res_works_for_broken_modules); 334 covers!(name_res_works_for_broken_modules);
378 let (item_map, module_id) = item_map( 335 let map = def_map(
379 " 336 "
380 //- /lib.rs 337 //- /lib.rs
381 mod foo // no `;`, no body 338 mod foo // no `;`, no body
382 339
383 use self::foo::Baz; 340 use self::foo::Baz;
384 <|>
385 341
386 //- /foo/mod.rs 342 //- /foo/mod.rs
387 pub mod bar; 343 pub mod bar;
@@ -390,65 +346,47 @@ fn name_res_works_for_broken_modules() {
390 346
391 //- /foo/bar.rs 347 //- /foo/bar.rs
392 pub struct Baz; 348 pub struct Baz;
393 ",
394 );
395 check_module_item_map(
396 &item_map,
397 module_id,
398 "
399 Baz: _
400 ", 349 ",
401 ); 350 );
402} 351 assert_snapshot_matches!(map,
403 352 @r###"
404#[test] 353crate
405fn item_map_using_self() { 354Baz: _
406 let (item_map, module_id) = item_map( 355"###
407 "
408 //- /lib.rs
409 mod foo;
410 use crate::foo::bar::Baz::{self};
411 <|>
412 //- /foo/mod.rs
413 pub mod bar;
414 //- /foo/bar.rs
415 pub struct Baz;
416 ",
417 );
418 check_module_item_map(
419 &item_map,
420 module_id,
421 "
422 Baz: t v
423 foo: t
424 ",
425 ); 356 );
426} 357}
427 358
428#[test] 359#[test]
429fn item_map_enum_importing() { 360fn item_map_using_self() {
430 covers!(item_map_enum_importing); 361 let map = def_map(
431 let (item_map, module_id) = item_map(
432 " 362 "
433 //- /lib.rs 363 //- /lib.rs
434 enum E { V } 364 mod foo;
435 use self::E::V; 365 use crate::foo::bar::Baz::{self};
436 <|> 366 //- /foo/mod.rs
367 pub mod bar;
368 //- /foo/bar.rs
369 pub struct Baz;
437 ", 370 ",
438 ); 371 );
439 check_module_item_map( 372 assert_snapshot_matches!(map,
440 &item_map, 373 @r###"
441 module_id, 374crate
442 " 375Baz: t v
443 E: t 376foo: t
444 V: t v 377
445 ", 378crate::foo
379bar: t
380
381crate::foo::bar
382Baz: t v
383"###
446 ); 384 );
447} 385}
448 386
449#[test] 387#[test]
450fn item_map_across_crates() { 388fn item_map_across_crates() {
451 let mut db = MockDatabase::with_files( 389 let map = def_map_with_crate_graph(
452 " 390 "
453 //- /main.rs 391 //- /main.rs
454 use test_crate::Baz; 392 use test_crate::Baz;
@@ -456,29 +394,23 @@ fn item_map_across_crates() {
456 //- /lib.rs 394 //- /lib.rs
457 pub struct Baz; 395 pub struct Baz;
458 ", 396 ",
397 crate_graph! {
398 "main": ("/main.rs", ["test_crate"]),
399 "test_crate": ("/lib.rs", []),
400 },
459 ); 401 );
460 db.set_crate_graph_from_fixture(crate_graph! { 402
461 "main": ("/main.rs", ["test_crate"]), 403 assert_snapshot_matches!(map,
462 "test_crate": ("/lib.rs", []), 404 @r###"
463 }); 405crate
464 let main_id = db.file_id_of("/main.rs"); 406Baz: t v
465 407"###
466 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
467 let krate = module.krate(&db).unwrap();
468 let item_map = db.item_map(krate);
469
470 check_module_item_map(
471 &item_map,
472 module.module_id,
473 "
474 Baz: t v
475 ",
476 ); 408 );
477} 409}
478 410
479#[test] 411#[test]
480fn extern_crate_rename() { 412fn extern_crate_rename() {
481 let mut db = MockDatabase::with_files( 413 let map = def_map_with_crate_graph(
482 " 414 "
483 //- /main.rs 415 //- /main.rs
484 extern crate alloc as alloc_crate; 416 extern crate alloc as alloc_crate;
@@ -492,29 +424,23 @@ fn extern_crate_rename() {
492 //- /lib.rs 424 //- /lib.rs
493 struct Arc; 425 struct Arc;
494 ", 426 ",
427 crate_graph! {
428 "main": ("/main.rs", ["alloc"]),
429 "alloc": ("/lib.rs", []),
430 },
495 ); 431 );
496 db.set_crate_graph_from_fixture(crate_graph! { 432
497 "main": ("/main.rs", ["alloc"]), 433 assert_snapshot_matches!(map,
498 "alloc": ("/lib.rs", []), 434 @r###"
499 }); 435crate
500 let sync_id = db.file_id_of("/sync.rs"); 436Arc: t v
501 437"###
502 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
503 let krate = module.krate(&db).unwrap();
504 let item_map = db.item_map(krate);
505
506 check_module_item_map(
507 &item_map,
508 module.module_id,
509 "
510 Arc: t v
511 ",
512 ); 438 );
513} 439}
514 440
515#[test] 441#[test]
516fn extern_crate_rename_2015_edition() { 442fn extern_crate_rename_2015_edition() {
517 let mut db = MockDatabase::with_files( 443 let map = def_map_with_crate_graph(
518 " 444 "
519 //- /main.rs 445 //- /main.rs
520 extern crate alloc as alloc_crate; 446 extern crate alloc as alloc_crate;
@@ -528,29 +454,23 @@ fn extern_crate_rename_2015_edition() {
528 //- /lib.rs 454 //- /lib.rs
529 struct Arc; 455 struct Arc;
530 ", 456 ",
457 crate_graph! {
458 "main": ("/main.rs", "2015", ["alloc"]),
459 "alloc": ("/lib.rs", []),
460 },
531 ); 461 );
532 db.set_crate_graph_from_fixture(crate_graph! { 462
533 "main": ("/main.rs", "2015", ["alloc"]), 463 assert_snapshot_matches!(map,
534 "alloc": ("/lib.rs", []), 464 @r###"
535 }); 465crate
536 let sync_id = db.file_id_of("/sync.rs"); 466Arc: t v
537 467"###
538 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
539 let krate = module.krate(&db).unwrap();
540 let item_map = db.item_map(krate);
541
542 check_module_item_map(
543 &item_map,
544 module.module_id,
545 "
546 Arc: t v
547 ",
548 ); 468 );
549} 469}
550 470
551#[test] 471#[test]
552fn import_across_source_roots() { 472fn import_across_source_roots() {
553 let mut db = MockDatabase::with_files( 473 let map = def_map_with_crate_graph(
554 " 474 "
555 //- /lib.rs 475 //- /lib.rs
556 pub mod a { 476 pub mod a {
@@ -564,29 +484,23 @@ fn import_across_source_roots() {
564 //- /main/main.rs 484 //- /main/main.rs
565 use test_crate::a::b::C; 485 use test_crate::a::b::C;
566 ", 486 ",
487 crate_graph! {
488 "main": ("/main/main.rs", ["test_crate"]),
489 "test_crate": ("/lib.rs", []),
490 },
567 ); 491 );
568 db.set_crate_graph_from_fixture(crate_graph! { 492
569 "main": ("/main/main.rs", ["test_crate"]), 493 assert_snapshot_matches!(map,
570 "test_crate": ("/lib.rs", []), 494 @r###"
571 }); 495crate
572 let main_id = db.file_id_of("/main/main.rs"); 496C: t v
573 497"###
574 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
575 let krate = module.krate(&db).unwrap();
576 let item_map = db.item_map(krate);
577
578 check_module_item_map(
579 &item_map,
580 module.module_id,
581 "
582 C: t v
583 ",
584 ); 498 );
585} 499}
586 500
587#[test] 501#[test]
588fn reexport_across_crates() { 502fn reexport_across_crates() {
589 let mut db = MockDatabase::with_files( 503 let map = def_map_with_crate_graph(
590 " 504 "
591 //- /main.rs 505 //- /main.rs
592 use test_crate::Baz; 506 use test_crate::Baz;
@@ -599,29 +513,23 @@ fn reexport_across_crates() {
599 //- /foo.rs 513 //- /foo.rs
600 pub struct Baz; 514 pub struct Baz;
601 ", 515 ",
516 crate_graph! {
517 "main": ("/main.rs", ["test_crate"]),
518 "test_crate": ("/lib.rs", []),
519 },
602 ); 520 );
603 db.set_crate_graph_from_fixture(crate_graph! { 521
604 "main": ("/main.rs", ["test_crate"]), 522 assert_snapshot_matches!(map,
605 "test_crate": ("/lib.rs", []), 523 @r###"
606 }); 524crate
607 let main_id = db.file_id_of("/main.rs"); 525Baz: t v
608 526"###
609 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
610 let krate = module.krate(&db).unwrap();
611 let item_map = db.item_map(krate);
612
613 check_module_item_map(
614 &item_map,
615 module.module_id,
616 "
617 Baz: t v
618 ",
619 ); 527 );
620} 528}
621 529
622#[test] 530#[test]
623fn values_dont_shadow_extern_crates() { 531fn values_dont_shadow_extern_crates() {
624 let mut db = MockDatabase::with_files( 532 let map = def_map_with_crate_graph(
625 " 533 "
626 //- /main.rs 534 //- /main.rs
627 fn foo() {} 535 fn foo() {}
@@ -630,139 +538,17 @@ fn values_dont_shadow_extern_crates() {
630 //- /foo/lib.rs 538 //- /foo/lib.rs
631 pub struct Bar; 539 pub struct Bar;
632 ", 540 ",
541 crate_graph! {
542 "main": ("/main.rs", ["foo"]),
543 "foo": ("/foo/lib.rs", []),
544 },
633 ); 545 );
634 db.set_crate_graph_from_fixture(crate_graph! {
635 "main": ("/main.rs", ["foo"]),
636 "foo": ("/foo/lib.rs", []),
637 });
638 let main_id = db.file_id_of("/main.rs");
639
640 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
641 let krate = module.krate(&db).unwrap();
642 let item_map = db.item_map(krate);
643
644 check_module_item_map(
645 &item_map,
646 module.module_id,
647 "
648 Bar: t v
649 foo: v
650 ",
651 );
652}
653
654fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
655 let (mut db, pos) = MockDatabase::with_position(initial);
656 let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();
657 let krate = module.krate(&db).unwrap();
658 {
659 let events = db.log_executed(|| {
660 db.item_map(krate);
661 });
662 assert!(format!("{:?}", events).contains("item_map"))
663 }
664 db.set_file_text(pos.file_id, Arc::new(file_change.to_string()));
665
666 {
667 let events = db.log_executed(|| {
668 db.item_map(krate);
669 });
670 assert!(!format!("{:?}", events).contains("item_map"), "{:#?}", events)
671 }
672}
673
674#[test]
675fn typing_inside_a_function_should_not_invalidate_item_map() {
676 check_item_map_is_not_recomputed(
677 "
678 //- /lib.rs
679 mod foo;<|>
680
681 use crate::foo::bar::Baz;
682
683 fn foo() -> i32 {
684 1 + 1
685 }
686 //- /foo/mod.rs
687 pub mod bar;
688
689 //- /foo/bar.rs
690 pub struct Baz;
691 ",
692 "
693 mod foo;
694
695 use crate::foo::bar::Baz;
696
697 fn foo() -> i32 { 92 }
698 ",
699 );
700}
701
702#[test]
703fn adding_inner_items_should_not_invalidate_item_map() {
704 check_item_map_is_not_recomputed(
705 "
706 //- /lib.rs
707 struct S { a: i32}
708 enum E { A }
709 trait T {
710 fn a() {}
711 }
712 mod foo;<|>
713 impl S {
714 fn a() {}
715 }
716 use crate::foo::bar::Baz;
717 //- /foo/mod.rs
718 pub mod bar;
719
720 //- /foo/bar.rs
721 pub struct Baz;
722 ",
723 "
724 struct S { a: i32, b: () }
725 enum E { A, B }
726 trait T {
727 fn a() {}
728 fn b() {}
729 }
730 mod foo;<|>
731 impl S {
732 fn a() {}
733 fn b() {}
734 }
735 use crate::foo::bar::Baz;
736 ",
737 );
738}
739 546
740#[test] 547 assert_snapshot_matches!(map,
741fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() { 548 @r###"
742 check_item_map_is_not_recomputed( 549crate
743 " 550Bar: t v
744 //- /lib.rs 551foo: v
745 mod foo; 552"###
746
747 use crate::foo::bar::Baz;
748
749 //- /foo/mod.rs
750 pub mod bar;
751
752 //- /foo/bar.rs
753 <|>
754 salsa::query_group! {
755 trait Baz {
756 fn foo() -> i32 { 1 + 1 }
757 }
758 }
759 ",
760 "
761 salsa::query_group! {
762 trait Baz {
763 fn foo() -> i32 { 92 }
764 }
765 }
766 ",
767 ); 553 );
768} 554}
diff --git a/crates/ra_hir/src/nameres/tests/globs.rs b/crates/ra_hir/src/nameres/tests/globs.rs
new file mode 100644
index 000000000..6e50c7ff6
--- /dev/null
+++ b/crates/ra_hir/src/nameres/tests/globs.rs
@@ -0,0 +1,118 @@
1use super::*;
2
3#[test]
4fn glob_1() {
5 let map = def_map(
6 "
7 //- /lib.rs
8 mod foo;
9 use foo::*;
10
11 //- /foo/mod.rs
12 pub mod bar;
13 pub use self::bar::Baz;
14 pub struct Foo;
15
16 //- /foo/bar.rs
17 pub struct Baz;
18 ",
19 );
20 assert_snapshot_matches!(map, @r###"
21crate
22bar: t
23Foo: t v
24Baz: t v
25foo: t
26
27crate::foo
28bar: t
29Foo: t v
30Baz: t v
31
32crate::foo::bar
33Baz: t v
34"###
35 );
36}
37
38#[test]
39fn glob_2() {
40 let map = def_map(
41 "
42 //- /lib.rs
43 mod foo;
44 use foo::*;
45
46 //- /foo/mod.rs
47 pub mod bar;
48 pub use self::bar::*;
49 pub struct Foo;
50
51 //- /foo/bar.rs
52 pub struct Baz;
53 pub use super::*;
54 ",
55 );
56 assert_snapshot_matches!(map, @r###"
57crate
58bar: t
59Foo: t v
60Baz: t v
61foo: t
62
63crate::foo
64bar: t
65Foo: t v
66Baz: t v
67
68crate::foo::bar
69bar: t
70Foo: t v
71Baz: t v
72"###
73 );
74}
75
76#[test]
77fn glob_across_crates() {
78 covers!(glob_across_crates);
79 let map = def_map_with_crate_graph(
80 "
81 //- /main.rs
82 use test_crate::*;
83
84 //- /lib.rs
85 pub struct Baz;
86 ",
87 crate_graph! {
88 "main": ("/main.rs", ["test_crate"]),
89 "test_crate": ("/lib.rs", []),
90 },
91 );
92 assert_snapshot_matches!(map, @r###"
93crate
94Baz: t v
95"###
96 );
97}
98
99#[test]
100fn glob_enum() {
101 covers!(glob_enum);
102 let map = def_map(
103 "
104 //- /lib.rs
105 enum Foo {
106 Bar, Baz
107 }
108 use self::Foo::*;
109 ",
110 );
111 assert_snapshot_matches!(map, @r###"
112crate
113Foo: t
114Bar: t v
115Baz: t v
116"###
117 );
118}
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs
new file mode 100644
index 000000000..698781923
--- /dev/null
+++ b/crates/ra_hir/src/nameres/tests/incremental.rs
@@ -0,0 +1,123 @@
1use super::*;
2
3use std::sync::Arc;
4
5use ra_db::SourceDatabase;
6
7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
8 let (mut db, pos) = MockDatabase::with_position(initial);
9 let crate_id = db.crate_graph().iter().next().unwrap();
10 let krate = Crate { crate_id };
11 {
12 let events = db.log_executed(|| {
13 db.crate_def_map(krate);
14 });
15 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
16 }
17 db.set_file_text(pos.file_id, Arc::new(file_change.to_string()));
18
19 {
20 let events = db.log_executed(|| {
21 db.crate_def_map(krate);
22 });
23 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
24 }
25}
26
27#[test]
28fn typing_inside_a_function_should_not_invalidate_def_map() {
29 check_def_map_is_not_recomputed(
30 "
31 //- /lib.rs
32 mod foo;<|>
33
34 use crate::foo::bar::Baz;
35
36 fn foo() -> i32 {
37 1 + 1
38 }
39 //- /foo/mod.rs
40 pub mod bar;
41
42 //- /foo/bar.rs
43 pub struct Baz;
44 ",
45 "
46 mod foo;
47
48 use crate::foo::bar::Baz;
49
50 fn foo() -> i32 { 92 }
51 ",
52 );
53}
54
55#[test]
56fn adding_inner_items_should_not_invalidate_def_map() {
57 check_def_map_is_not_recomputed(
58 "
59 //- /lib.rs
60 struct S { a: i32}
61 enum E { A }
62 trait T {
63 fn a() {}
64 }
65 mod foo;<|>
66 impl S {
67 fn a() {}
68 }
69 use crate::foo::bar::Baz;
70 //- /foo/mod.rs
71 pub mod bar;
72
73 //- /foo/bar.rs
74 pub struct Baz;
75 ",
76 "
77 struct S { a: i32, b: () }
78 enum E { A, B }
79 trait T {
80 fn a() {}
81 fn b() {}
82 }
83 mod foo;<|>
84 impl S {
85 fn a() {}
86 fn b() {}
87 }
88 use crate::foo::bar::Baz;
89 ",
90 );
91}
92
93// It would be awesome to make this work, but it's unclear how
94#[test]
95#[ignore]
96fn typing_inside_a_function_inside_a_macro_should_not_invalidate_def_map() {
97 check_def_map_is_not_recomputed(
98 "
99 //- /lib.rs
100 mod foo;
101
102 use crate::foo::bar::Baz;
103
104 //- /foo/mod.rs
105 pub mod bar;
106
107 //- /foo/bar.rs
108 <|>
109 salsa::query_group! {
110 trait Baz {
111 fn foo() -> i32 { 1 + 1 }
112 }
113 }
114 ",
115 "
116 salsa::query_group! {
117 trait Baz {
118 fn foo() -> i32 { 92 }
119 }
120 }
121 ",
122 );
123}
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
new file mode 100644
index 000000000..8781b026b
--- /dev/null
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -0,0 +1,94 @@
1use super::*;
2
3#[test]
4fn macro_rules_are_globally_visible() {
5 let map = def_map(
6 "
7 //- /lib.rs
8 macro_rules! structs {
9 ($($i:ident),*) => {
10 $(struct $i { field: u32 } )*
11 }
12 }
13 structs!(Foo);
14 mod nested;
15
16 //- /nested.rs
17 structs!(Bar, Baz);
18 ",
19 );
20 assert_snapshot_matches!(map, @r###"
21crate
22nested: t
23Foo: t v
24
25crate::nested
26Bar: t v
27Baz: t v
28"###);
29}
30
31#[test]
32fn macro_rules_can_define_modules() {
33 let map = def_map(
34 "
35 //- /lib.rs
36 macro_rules! m {
37 ($name:ident) => { mod $name; }
38 }
39 m!(n1);
40
41 //- /n1.rs
42 m!(n2)
43 //- /n1/n2.rs
44 struct X;
45 ",
46 );
47 assert_snapshot_matches!(map, @r###"
48crate
49n1: t
50
51crate::n1
52n2: t
53
54crate::n1::n2
55X: t v
56"###);
57}
58
59#[test]
60fn macro_rules_from_other_crates_are_visible() {
61 let map = def_map_with_crate_graph(
62 "
63 //- /main.rs
64 foo::structs!(Foo, Bar)
65 mod bar;
66
67 //- /bar.rs
68 use crate::*;
69
70 //- /lib.rs
71 #[macro_export]
72 macro_rules! structs {
73 ($($i:ident),*) => {
74 $(struct $i { field: u32 } )*
75 }
76 }
77 ",
78 crate_graph! {
79 "main": ("/main.rs", ["foo"]),
80 "foo": ("/lib.rs", []),
81 },
82 );
83 assert_snapshot_matches!(map, @r###"
84crate
85bar: t
86Foo: t v
87Bar: t v
88
89crate::bar
90bar: t
91Foo: t v
92Bar: t v
93"###);
94}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 57e7d0b9a..59af4ec60 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -4,10 +4,10 @@ use std::sync::Arc;
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
5 5
6use crate::{ 6use crate::{
7 ModuleDef, Module, 7 ModuleDef,
8 db::HirDatabase, 8 db::HirDatabase,
9 name::{Name, KnownName}, 9 name::{Name, KnownName},
10 nameres::{PerNs, ItemMap}, 10 nameres::{PerNs, CrateDefMap, CrateModuleId},
11 generics::GenericParams, 11 generics::GenericParams,
12 expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, 12 expr::{scope::{ExprScopes, ScopeId}, PatId, Body},
13 impl_block::ImplBlock, 13 impl_block::ImplBlock,
@@ -22,8 +22,8 @@ pub struct Resolver {
22// TODO how to store these best 22// TODO how to store these best
23#[derive(Debug, Clone)] 23#[derive(Debug, Clone)]
24pub(crate) struct ModuleItemMap { 24pub(crate) struct ModuleItemMap {
25 item_map: Arc<ItemMap>, 25 crate_def_map: Arc<CrateDefMap>,
26 module: Module, 26 module_id: CrateModuleId,
27} 27}
28 28
29#[derive(Debug, Clone)] 29#[derive(Debug, Clone)]
@@ -175,9 +175,9 @@ impl Resolver {
175 names 175 names
176 } 176 }
177 177
178 fn module(&self) -> Option<(&ItemMap, Module)> { 178 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
179 self.scopes.iter().rev().find_map(|scope| match scope { 179 self.scopes.iter().rev().find_map(|scope| match scope {
180 Scope::ModuleScope(m) => Some((&*m.item_map, m.module.clone())), 180 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
181 181
182 _ => None, 182 _ => None,
183 }) 183 })
@@ -206,8 +206,12 @@ impl Resolver {
206 self.push_scope(Scope::ImplBlockScope(impl_block)) 206 self.push_scope(Scope::ImplBlockScope(impl_block))
207 } 207 }
208 208
209 pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module: Module) -> Resolver { 209 pub(crate) fn push_module_scope(
210 self.push_scope(Scope::ModuleScope(ModuleItemMap { item_map, module })) 210 self,
211 crate_def_map: Arc<CrateDefMap>,
212 module_id: CrateModuleId,
213 ) -> Resolver {
214 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
211 } 215 }
212 216
213 pub(crate) fn push_expr_scope( 217 pub(crate) fn push_expr_scope(
@@ -224,9 +228,11 @@ impl Scope {
224 match self { 228 match self {
225 Scope::ModuleScope(m) => { 229 Scope::ModuleScope(m) => {
226 if let Some(KnownName::SelfParam) = name.as_known_name() { 230 if let Some(KnownName::SelfParam) = name.as_known_name() {
227 PerNs::types(Resolution::Def(m.module.into())) 231 PerNs::types(Resolution::Def(m.crate_def_map.mk_module(m.module_id).into()))
228 } else { 232 } else {
229 m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def) 233 m.crate_def_map
234 .resolve_name_in_module(db, m.module_id, name)
235 .map(Resolution::Def)
230 } 236 }
231 } 237 }
232 Scope::GenericParams(gp) => match gp.find_by_name(name) { 238 Scope::GenericParams(gp) => match gp.find_by_name(name) {
@@ -261,15 +267,15 @@ impl Scope {
261 // def: m.module.into(), 267 // def: m.module.into(),
262 // }), 268 // }),
263 // ); 269 // );
264 m.item_map[m.module.module_id].entries().for_each(|(name, res)| { 270 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| {
265 f(name.clone(), res.def.map(Resolution::Def)); 271 f(name.clone(), res.def.map(Resolution::Def));
266 }); 272 });
267 m.item_map.extern_prelude.iter().for_each(|(name, def)| { 273 m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| {
268 f(name.clone(), PerNs::types(Resolution::Def(*def))); 274 f(name.clone(), PerNs::types(Resolution::Def(*def)));
269 }); 275 });
270 if let Some(prelude) = m.item_map.prelude { 276 if let Some(prelude) = m.crate_def_map.prelude() {
271 let prelude_item_map = db.item_map(prelude.krate); 277 let prelude_def_map = db.crate_def_map(prelude.krate);
272 prelude_item_map[prelude.module_id].entries().for_each(|(name, res)| { 278 prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| {
273 f(name.clone(), res.def.map(Resolution::Def)); 279 f(name.clone(), res.def.map(Resolution::Def));
274 }); 280 });
275 } 281 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 4a9921a85..902110913 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,13 +7,13 @@
7/// purely for "IDE needs". 7/// purely for "IDE needs".
8use ra_db::{FileId, FilePosition}; 8use ra_db::{FileId, FilePosition};
9use ra_syntax::{ 9use ra_syntax::{
10 SmolStr, TextRange, SyntaxNode, 10 SyntaxNode,
11 ast::{self, AstNode, NameOwner}, 11 ast::{self, AstNode, NameOwner},
12 algo::{find_node_at_offset, find_leaf_at_offset}, 12 algo::{find_node_at_offset, find_leaf_at_offset},
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Function, ModuleDef, Struct, Enum, 16 HirDatabase, Function, Struct, Enum,
17 AsName, Module, HirFileId, Crate, Trait, Resolver, 17 AsName, Module, HirFileId, Crate, Trait, Resolver,
18 ids::{LocationCtx, SourceFileItemId}, 18 ids::{LocationCtx, SourceFileItemId},
19 expr 19 expr
@@ -80,8 +80,8 @@ fn module_from_source(
80 let source_root_id = db.file_source_root(file_id.as_original_file()); 80 let source_root_id = db.file_source_root(file_id.as_original_file());
81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( 81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
82 |krate| { 82 |krate| {
83 let module_tree = db.module_tree(krate); 83 let def_map = db.crate_def_map(krate);
84 let module_id = module_tree.find_module_by_source(file_id, decl_id)?; 84 let module_id = def_map.find_module_by_source(file_id, decl_id)?;
85 Some(Module { krate, module_id }) 85 Some(Module { krate, module_id })
86 }, 86 },
87 ) 87 )
@@ -152,44 +152,6 @@ pub fn trait_from_module(
152 Trait { id: ctx.to_def(trait_def) } 152 Trait { id: ctx.to_def(trait_def) }
153} 153}
154 154
155pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> {
156 let module = match module_from_file_id(db, file_id) {
157 Some(it) => it,
158 None => return Vec::new(),
159 };
160 let items = db.lower_module(module);
161 let mut res = Vec::new();
162
163 for macro_call_id in items
164 .declarations
165 .iter()
166 .filter_map(|(_, it)| it.clone().take_types())
167 .filter_map(|it| match it {
168 ModuleDef::Trait(it) => Some(it),
169 _ => None,
170 })
171 .filter_map(|it| it.source(db).0.as_macro_call_id())
172 {
173 if let Some(exp) = db.expand_macro_invocation(macro_call_id) {
174 let loc = macro_call_id.loc(db);
175 let syntax = db.file_item(loc.source_item_id);
176 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
177 let off = macro_call.token_tree().unwrap().syntax().range().start();
178 let file = exp.file();
179 for trait_def in file.syntax().descendants().filter_map(ast::TraitDef::cast) {
180 if let Some(name) = trait_def.name() {
181 let dst_range = name.syntax().range();
182 if let Some(src_range) = exp.map_range_back(dst_range) {
183 res.push((name.text().clone(), src_range + off))
184 }
185 }
186 }
187 }
188 }
189
190 res
191}
192
193pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { 155pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver {
194 let file_id = position.file_id; 156 let file_id = position.file_id;
195 let file = db.parse(file_id); 157 let file = db.parse(file_id);
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index bad811a56..2ea3b341f 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -9,16 +9,16 @@ pub(crate) mod method_resolution;
9mod op; 9mod op;
10mod lower; 10mod lower;
11mod infer; 11mod infer;
12pub(crate) mod display;
12 13
13use std::sync::Arc; 14use std::sync::Arc;
14use std::{fmt, mem}; 15use std::{fmt, mem};
15 16
16use join_to_string::join; 17use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase};
17 18
18use crate::{Name, AdtDef, type_ref::Mutability}; 19pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig};
19
20pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field};
21pub(crate) use infer::{infer, InferenceResult, InferTy}; 20pub(crate) use infer::{infer, InferenceResult, InferTy};
21use display::{HirDisplay, HirFormatter};
22 22
23/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). 23/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
24/// 24///
@@ -42,8 +42,6 @@ pub enum Ty {
42 Adt { 42 Adt {
43 /// The definition of the struct/enum. 43 /// The definition of the struct/enum.
44 def_id: AdtDef, 44 def_id: AdtDef,
45 /// The name, for displaying.
46 name: Name,
47 /// Substitutions for the generic parameters of the type. 45 /// Substitutions for the generic parameters of the type.
48 substs: Substs, 46 substs: Substs,
49 }, 47 },
@@ -79,10 +77,6 @@ pub enum Ty {
79 FnDef { 77 FnDef {
80 /// The definition of the function / constructor. 78 /// The definition of the function / constructor.
81 def: CallableDef, 79 def: CallableDef,
82 /// For display
83 name: Name,
84 /// Parameters and return type
85 sig: Arc<FnSig>,
86 /// Substitutions for the generic parameters of the type 80 /// Substitutions for the generic parameters of the type
87 substs: Substs, 81 substs: Substs,
88 }, 82 },
@@ -95,7 +89,7 @@ pub enum Ty {
95 /// fn foo() -> i32 { 1 } 89 /// fn foo() -> i32 { 1 }
96 /// let bar: fn() -> i32 = foo; 90 /// let bar: fn() -> i32 = foo;
97 /// ``` 91 /// ```
98 FnPtr(Arc<FnSig>), 92 FnPtr(FnSig),
99 93
100 /// The never type `!`. 94 /// The never type `!`.
101 Never, 95 Never,
@@ -132,13 +126,44 @@ impl Substs {
132 pub fn empty() -> Substs { 126 pub fn empty() -> Substs {
133 Substs(Arc::new([])) 127 Substs(Arc::new([]))
134 } 128 }
129
130 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
131 // Without an Arc::make_mut_slice, we can't avoid the clone here:
132 let mut v: Vec<_> = self.0.iter().cloned().collect();
133 for t in &mut v {
134 t.walk_mut(f);
135 }
136 self.0 = v.into();
137 }
135} 138}
136 139
137/// A function signature. 140/// A function signature.
138#[derive(Clone, PartialEq, Eq, Debug)] 141#[derive(Clone, PartialEq, Eq, Debug)]
139pub struct FnSig { 142pub struct FnSig {
140 input: Vec<Ty>, 143 params_and_return: Arc<[Ty]>,
141 output: Ty, 144}
145
146impl FnSig {
147 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig {
148 params.push(ret);
149 FnSig { params_and_return: params.into() }
150 }
151 pub fn params(&self) -> &[Ty] {
152 &self.params_and_return[0..self.params_and_return.len() - 1]
153 }
154
155 pub fn ret(&self) -> &Ty {
156 &self.params_and_return[self.params_and_return.len() - 1]
157 }
158
159 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
160 // Without an Arc::make_mut_slice, we can't avoid the clone here:
161 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
162 for t in &mut v {
163 t.walk_mut(f);
164 }
165 self.params_and_return = v.into();
166 }
142} 167}
143 168
144impl Ty { 169impl Ty {
@@ -157,16 +182,12 @@ impl Ty {
157 } 182 }
158 } 183 }
159 Ty::FnPtr(sig) => { 184 Ty::FnPtr(sig) => {
160 for input in &sig.input { 185 for input in sig.params() {
161 input.walk(f); 186 input.walk(f);
162 } 187 }
163 sig.output.walk(f); 188 sig.ret().walk(f);
164 } 189 }
165 Ty::FnDef { substs, sig, .. } => { 190 Ty::FnDef { substs, .. } => {
166 for input in &sig.input {
167 input.walk(f);
168 }
169 sig.output.walk(f);
170 for t in substs.0.iter() { 191 for t in substs.0.iter() {
171 t.walk(f); 192 t.walk(f);
172 } 193 }
@@ -203,32 +224,13 @@ impl Ty {
203 *ts = v.into(); 224 *ts = v.into();
204 } 225 }
205 Ty::FnPtr(sig) => { 226 Ty::FnPtr(sig) => {
206 let sig_mut = Arc::make_mut(sig); 227 sig.walk_mut(f);
207 for input in &mut sig_mut.input {
208 input.walk_mut(f);
209 }
210 sig_mut.output.walk_mut(f);
211 } 228 }
212 Ty::FnDef { substs, sig, .. } => { 229 Ty::FnDef { substs, .. } => {
213 let sig_mut = Arc::make_mut(sig); 230 substs.walk_mut(f);
214 for input in &mut sig_mut.input {
215 input.walk_mut(f);
216 }
217 sig_mut.output.walk_mut(f);
218 // Without an Arc::make_mut_slice, we can't avoid the clone here:
219 let mut v: Vec<_> = substs.0.iter().cloned().collect();
220 for t in &mut v {
221 t.walk_mut(f);
222 }
223 substs.0 = v.into();
224 } 231 }
225 Ty::Adt { substs, .. } => { 232 Ty::Adt { substs, .. } => {
226 // Without an Arc::make_mut_slice, we can't avoid the clone here: 233 substs.walk_mut(f);
227 let mut v: Vec<_> = substs.0.iter().cloned().collect();
228 for t in &mut v {
229 t.walk_mut(f);
230 }
231 substs.0 = v.into();
232 } 234 }
233 Ty::Bool 235 Ty::Bool
234 | Ty::Char 236 | Ty::Char
@@ -265,8 +267,8 @@ impl Ty {
265 /// `Option<u32>` afterwards.) 267 /// `Option<u32>` afterwards.)
266 pub fn apply_substs(self, substs: Substs) -> Ty { 268 pub fn apply_substs(self, substs: Substs) -> Ty {
267 match self { 269 match self {
268 Ty::Adt { def_id, name, .. } => Ty::Adt { def_id, name, substs }, 270 Ty::Adt { def_id, .. } => Ty::Adt { def_id, substs },
269 Ty::FnDef { def, name, sig, .. } => Ty::FnDef { def, name, sig, substs }, 271 Ty::FnDef { def, .. } => Ty::FnDef { def, substs },
270 _ => self, 272 _ => self,
271 } 273 }
272 } 274 }
@@ -297,50 +299,81 @@ impl Ty {
297 } 299 }
298} 300}
299 301
300impl fmt::Display for Ty { 302impl HirDisplay for &Ty {
301 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 303 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
304 HirDisplay::hir_fmt(*self, f)
305 }
306}
307
308impl HirDisplay for Ty {
309 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
302 match self { 310 match self {
303 Ty::Bool => write!(f, "bool"), 311 Ty::Bool => write!(f, "bool")?,
304 Ty::Char => write!(f, "char"), 312 Ty::Char => write!(f, "char")?,
305 Ty::Int(t) => write!(f, "{}", t.ty_to_string()), 313 Ty::Int(t) => write!(f, "{}", t)?,
306 Ty::Float(t) => write!(f, "{}", t.ty_to_string()), 314 Ty::Float(t) => write!(f, "{}", t)?,
307 Ty::Str => write!(f, "str"), 315 Ty::Str => write!(f, "str")?,
308 Ty::Slice(t) | Ty::Array(t) => write!(f, "[{}]", t), 316 Ty::Slice(t) | Ty::Array(t) => {
309 Ty::RawPtr(t, m) => write!(f, "*{}{}", m.as_keyword_for_ptr(), t), 317 write!(f, "[{}]", t.display(f.db))?;
310 Ty::Ref(t, m) => write!(f, "&{}{}", m.as_keyword_for_ref(), t), 318 }
311 Ty::Never => write!(f, "!"), 319 Ty::RawPtr(t, m) => {
320 write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?;
321 }
322 Ty::Ref(t, m) => {
323 write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?;
324 }
325 Ty::Never => write!(f, "!")?,
312 Ty::Tuple(ts) => { 326 Ty::Tuple(ts) => {
313 if ts.len() == 1 { 327 if ts.len() == 1 {
314 write!(f, "({},)", ts[0]) 328 write!(f, "({},)", ts[0].display(f.db))?;
315 } else { 329 } else {
316 join(ts.iter()).surround_with("(", ")").separator(", ").to_fmt(f) 330 write!(f, "(")?;
331 f.write_joined(&**ts, ", ")?;
332 write!(f, ")")?;
317 } 333 }
318 } 334 }
319 Ty::FnPtr(sig) => { 335 Ty::FnPtr(sig) => {
320 join(sig.input.iter()).surround_with("fn(", ")").separator(", ").to_fmt(f)?; 336 write!(f, "fn(")?;
321 write!(f, " -> {}", sig.output) 337 f.write_joined(sig.params(), ", ")?;
338 write!(f, ") -> {}", sig.ret().display(f.db))?;
322 } 339 }
323 Ty::FnDef { def, name, substs, sig, .. } => { 340 Ty::FnDef { def, substs, .. } => {
341 let sig = f.db.callable_item_signature(*def);
342 let name = match def {
343 CallableDef::Function(ff) => ff.name(f.db),
344 CallableDef::Struct(s) => s.name(f.db).unwrap_or_else(Name::missing),
345 CallableDef::EnumVariant(e) => e.name(f.db).unwrap_or_else(Name::missing),
346 };
324 match def { 347 match def {
325 CallableDef::Function(_) => write!(f, "fn {}", name)?, 348 CallableDef::Function(_) => write!(f, "fn {}", name)?,
326 CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?, 349 CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?,
327 } 350 }
328 if substs.0.len() > 0 { 351 if substs.0.len() > 0 {
329 join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?; 352 write!(f, "<")?;
353 f.write_joined(&*substs.0, ", ")?;
354 write!(f, ">")?;
330 } 355 }
331 join(sig.input.iter()).surround_with("(", ")").separator(", ").to_fmt(f)?; 356 write!(f, "(")?;
332 write!(f, " -> {}", sig.output) 357 f.write_joined(sig.params(), ", ")?;
358 write!(f, ") -> {}", sig.ret().display(f.db))?;
333 } 359 }
334 Ty::Adt { name, substs, .. } => { 360 Ty::Adt { def_id, substs, .. } => {
361 let name = match def_id {
362 AdtDef::Struct(s) => s.name(f.db),
363 AdtDef::Enum(e) => e.name(f.db),
364 }
365 .unwrap_or_else(Name::missing);
335 write!(f, "{}", name)?; 366 write!(f, "{}", name)?;
336 if substs.0.len() > 0 { 367 if substs.0.len() > 0 {
337 join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?; 368 write!(f, "<")?;
369 f.write_joined(&*substs.0, ", ")?;
370 write!(f, ">")?;
338 } 371 }
339 Ok(())
340 } 372 }
341 Ty::Param { name, .. } => write!(f, "{}", name), 373 Ty::Param { name, .. } => write!(f, "{}", name)?,
342 Ty::Unknown => write!(f, "{{unknown}}"), 374 Ty::Unknown => write!(f, "{{unknown}}")?,
343 Ty::Infer(..) => write!(f, "_"), 375 Ty::Infer(..) => write!(f, "_")?,
344 } 376 }
377 Ok(())
345 } 378 }
346} 379}
diff --git a/crates/ra_hir/src/ty/display.rs b/crates/ra_hir/src/ty/display.rs
new file mode 100644
index 000000000..63ec9d7e1
--- /dev/null
+++ b/crates/ra_hir/src/ty/display.rs
@@ -0,0 +1,56 @@
1use std::fmt;
2
3use crate::db::HirDatabase;
4
5pub struct HirFormatter<'a, 'b, DB> {
6 pub db: &'a DB,
7 fmt: &'a mut fmt::Formatter<'b>,
8}
9
10pub trait HirDisplay {
11 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result;
12 fn display<'a, DB>(&'a self, db: &'a DB) -> HirDisplayWrapper<'a, DB, Self>
13 where
14 Self: Sized,
15 {
16 HirDisplayWrapper(db, self)
17 }
18}
19
20impl<'a, 'b, DB> HirFormatter<'a, 'b, DB>
21where
22 DB: HirDatabase,
23{
24 pub fn write_joined<T: HirDisplay>(
25 &mut self,
26 iter: impl IntoIterator<Item = T>,
27 sep: &str,
28 ) -> fmt::Result {
29 let mut first = true;
30 for e in iter {
31 if !first {
32 write!(self, "{}", sep)?;
33 }
34 first = false;
35 e.hir_fmt(self)?;
36 }
37 Ok(())
38 }
39
40 /// This allows using the `write!` macro directly with a `HirFormatter`.
41 pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
42 fmt::write(self.fmt, args)
43 }
44}
45
46pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T);
47
48impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T>
49where
50 DB: HirDatabase,
51 T: HirDisplay,
52{
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 self.1.hir_fmt(&mut HirFormatter { db: self.0, fmt: f })
55 }
56}
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 0a698988c..735cdecb9 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -789,11 +789,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
789 Expr::Call { callee, args } => { 789 Expr::Call { callee, args } => {
790 let callee_ty = self.infer_expr(*callee, &Expectation::none()); 790 let callee_ty = self.infer_expr(*callee, &Expectation::none());
791 let (param_tys, ret_ty) = match &callee_ty { 791 let (param_tys, ret_ty) = match &callee_ty {
792 Ty::FnPtr(sig) => (sig.input.clone(), sig.output.clone()), 792 Ty::FnPtr(sig) => (sig.params().to_vec(), sig.ret().clone()),
793 Ty::FnDef { substs, sig, .. } => { 793 Ty::FnDef { substs, def, .. } => {
794 let ret_ty = sig.output.clone().subst(&substs); 794 let sig = self.db.callable_item_signature(*def);
795 let ret_ty = sig.ret().clone().subst(&substs);
795 let param_tys = 796 let param_tys =
796 sig.input.iter().map(|ty| ty.clone().subst(&substs)).collect(); 797 sig.params().iter().map(|ty| ty.clone().subst(&substs)).collect();
797 (param_tys, ret_ty) 798 (param_tys, ret_ty)
798 } 799 }
799 _ => { 800 _ => {
@@ -827,19 +828,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
827 let method_ty = self.insert_type_vars(method_ty); 828 let method_ty = self.insert_type_vars(method_ty);
828 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { 829 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
829 Ty::FnPtr(sig) => { 830 Ty::FnPtr(sig) => {
830 if !sig.input.is_empty() { 831 if !sig.params().is_empty() {
831 (sig.input[0].clone(), sig.input[1..].to_vec(), sig.output.clone()) 832 (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
832 } else { 833 } else {
833 (Ty::Unknown, Vec::new(), sig.output.clone()) 834 (Ty::Unknown, Vec::new(), sig.ret().clone())
834 } 835 }
835 } 836 }
836 Ty::FnDef { substs, sig, .. } => { 837 Ty::FnDef { substs, def, .. } => {
837 let ret_ty = sig.output.clone().subst(&substs); 838 let sig = self.db.callable_item_signature(*def);
838 839 let ret_ty = sig.ret().clone().subst(&substs);
839 if !sig.input.is_empty() { 840
840 let mut arg_iter = sig.input.iter().map(|ty| ty.clone().subst(&substs)); 841 if !sig.params().is_empty() {
841 let receiver_ty = arg_iter.next().unwrap(); 842 let mut params_iter =
842 (receiver_ty, arg_iter.collect(), ret_ty) 843 sig.params().iter().map(|ty| ty.clone().subst(&substs));
844 let receiver_ty = params_iter.next().unwrap();
845 (receiver_ty, params_iter.collect(), ret_ty)
843 } else { 846 } else {
844 (Ty::Unknown, Vec::new(), ret_ty) 847 (Ty::Unknown, Vec::new(), ret_ty)
845 } 848 }
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index f4e055feb..278f592d3 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -9,7 +9,7 @@
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use crate::{ 11use crate::{
12 Function, Struct, StructField, Enum, EnumVariant, Path, Name, 12 Function, Struct, StructField, Enum, EnumVariant, Path,
13 ModuleDef, TypeAlias, 13 ModuleDef, TypeAlias,
14 Const, Static, 14 Const, Static,
15 HirDatabase, 15 HirDatabase,
@@ -51,12 +51,10 @@ impl Ty {
51 } 51 }
52 TypeRef::Placeholder => Ty::Unknown, 52 TypeRef::Placeholder => Ty::Unknown,
53 TypeRef::Fn(params) => { 53 TypeRef::Fn(params) => {
54 let mut inner_tys = 54 let inner_tys =
55 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); 55 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
56 let return_ty = 56 let sig = FnSig { params_and_return: inner_tys.into() };
57 inner_tys.pop().expect("TypeRef::Fn should always have at least return type"); 57 Ty::FnPtr(sig)
58 let sig = FnSig { input: inner_tys, output: return_ty };
59 Ty::FnPtr(Arc::new(sig))
60 } 58 }
61 TypeRef::Error => Ty::Unknown, 59 TypeRef::Error => Ty::Unknown,
62 } 60 }
@@ -214,6 +212,15 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace
214 } 212 }
215} 213}
216 214
215/// Build the signature of a callable item (function, struct or enum variant).
216pub(crate) fn callable_item_sig(db: &impl HirDatabase, def: CallableDef) -> FnSig {
217 match def {
218 CallableDef::Function(f) => fn_sig_for_fn(db, f),
219 CallableDef::Struct(s) => fn_sig_for_struct_constructor(db, s),
220 CallableDef::EnumVariant(e) => fn_sig_for_enum_variant_constructor(db, e),
221 }
222}
223
217/// Build the type of a specific field of a struct or enum variant. 224/// Build the type of a specific field of a struct or enum variant.
218pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { 225pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
219 let parent_def = field.parent_def(db); 226 let parent_def = field.parent_def(db);
@@ -226,19 +233,21 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
226 Ty::from_hir(db, &resolver, type_ref) 233 Ty::from_hir(db, &resolver, type_ref)
227} 234}
228 235
236fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
237 let signature = def.signature(db);
238 let resolver = def.resolver(db);
239 let params =
240 signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
241 let ret = Ty::from_hir(db, &resolver, signature.ret_type());
242 FnSig::from_params_and_return(params, ret)
243}
244
229/// Build the declared type of a function. This should not need to look at the 245/// Build the declared type of a function. This should not need to look at the
230/// function body. 246/// function body.
231fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { 247fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
232 let signature = def.signature(db);
233 let resolver = def.resolver(db);
234 let generics = def.generic_params(db); 248 let generics = def.generic_params(db);
235 let name = def.name(db);
236 let input =
237 signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
238 let output = Ty::from_hir(db, &resolver, signature.ret_type());
239 let sig = Arc::new(FnSig { input, output });
240 let substs = make_substs(&generics); 249 let substs = make_substs(&generics);
241 Ty::FnDef { def: def.into(), sig, name, substs } 250 Ty::FnDef { def: def.into(), substs }
242} 251}
243 252
244/// Build the declared type of a const. 253/// Build the declared type of a const.
@@ -257,44 +266,58 @@ fn type_for_static(db: &impl HirDatabase, def: Static) -> Ty {
257 Ty::from_hir(db, &resolver, signature.type_ref()) 266 Ty::from_hir(db, &resolver, signature.type_ref())
258} 267}
259 268
260/// Build the type of a tuple struct constructor. 269fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
261fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
262 let var_data = def.variant_data(db); 270 let var_data = def.variant_data(db);
263 let fields = match var_data.fields() { 271 let fields = match var_data.fields() {
264 Some(fields) => fields, 272 Some(fields) => fields,
265 None => return type_for_struct(db, def), // Unit struct 273 None => panic!("fn_sig_for_struct_constructor called on unit struct"),
266 }; 274 };
267 let resolver = def.resolver(db); 275 let resolver = def.resolver(db);
268 let generics = def.generic_params(db); 276 let params = fields
269 let name = def.name(db).unwrap_or_else(Name::missing);
270 let input = fields
271 .iter() 277 .iter()
272 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 278 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
273 .collect::<Vec<_>>(); 279 .collect::<Vec<_>>();
274 let output = type_for_struct(db, def); 280 let ret = type_for_struct(db, def);
275 let sig = Arc::new(FnSig { input, output }); 281 FnSig::from_params_and_return(params, ret)
282}
283
284/// Build the type of a tuple struct constructor.
285fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
286 let var_data = def.variant_data(db);
287 if var_data.fields().is_none() {
288 return type_for_struct(db, def); // Unit struct
289 }
290 let generics = def.generic_params(db);
276 let substs = make_substs(&generics); 291 let substs = make_substs(&generics);
277 Ty::FnDef { def: def.into(), sig, name, substs } 292 Ty::FnDef { def: def.into(), substs }
278} 293}
279 294
280/// Build the type of a tuple enum variant constructor. 295fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> FnSig {
281fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
282 let var_data = def.variant_data(db); 296 let var_data = def.variant_data(db);
283 let fields = match var_data.fields() { 297 let fields = match var_data.fields() {
284 Some(fields) => fields, 298 Some(fields) => fields,
285 None => return type_for_enum(db, def.parent_enum(db)), // Unit variant 299 None => panic!("fn_sig_for_enum_variant_constructor called for unit variant"),
286 }; 300 };
287 let resolver = def.parent_enum(db).resolver(db); 301 let resolver = def.parent_enum(db).resolver(db);
288 let generics = def.parent_enum(db).generic_params(db); 302 let params = fields
289 let name = def.name(db).unwrap_or_else(Name::missing);
290 let input = fields
291 .iter() 303 .iter()
292 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 304 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
293 .collect::<Vec<_>>(); 305 .collect::<Vec<_>>();
306 let generics = def.parent_enum(db).generic_params(db);
307 let substs = make_substs(&generics);
308 let ret = type_for_enum(db, def.parent_enum(db)).subst(&substs);
309 FnSig::from_params_and_return(params, ret)
310}
311
312/// Build the type of a tuple enum variant constructor.
313fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
314 let var_data = def.variant_data(db);
315 if var_data.fields().is_none() {
316 return type_for_enum(db, def.parent_enum(db)); // Unit variant
317 }
318 let generics = def.parent_enum(db).generic_params(db);
294 let substs = make_substs(&generics); 319 let substs = make_substs(&generics);
295 let output = type_for_enum(db, def.parent_enum(db)).subst(&substs); 320 Ty::FnDef { def: def.into(), substs }
296 let sig = Arc::new(FnSig { input, output });
297 Ty::FnDef { def: def.into(), sig, name, substs }
298} 321}
299 322
300fn make_substs(generics: &GenericParams) -> Substs { 323fn make_substs(generics: &GenericParams) -> Substs {
@@ -310,20 +333,12 @@ fn make_substs(generics: &GenericParams) -> Substs {
310 333
311fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { 334fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
312 let generics = s.generic_params(db); 335 let generics = s.generic_params(db);
313 Ty::Adt { 336 Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
314 def_id: s.into(),
315 name: s.name(db).unwrap_or_else(Name::missing),
316 substs: make_substs(&generics),
317 }
318} 337}
319 338
320fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { 339fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
321 let generics = s.generic_params(db); 340 let generics = s.generic_params(db);
322 Ty::Adt { 341 Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
323 def_id: s.into(),
324 name: s.name(db).unwrap_or_else(Name::missing),
325 substs: make_substs(&generics),
326 }
327} 342}
328 343
329fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty { 344fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 94b757af2..804824868 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -7,10 +7,12 @@ use std::sync::Arc;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8 8
9use crate::{ 9use crate::{
10 HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait, 10 HirDatabase, Module, Crate, Name, Function, Trait,
11 ids::TraitId, 11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 12 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{AdtDef, Ty}, 13 ty::{AdtDef, Ty},
14 nameres::CrateModuleId,
15
14}; 16};
15 17
16/// This is used as a key for indexing impls. 18/// This is used as a key for indexing impls.
@@ -33,10 +35,10 @@ impl TyFingerprint {
33 35
34#[derive(Debug, PartialEq, Eq)] 36#[derive(Debug, PartialEq, Eq)]
35pub struct CrateImplBlocks { 37pub struct CrateImplBlocks {
36 /// To make sense of the ModuleIds, we need the source root. 38 /// To make sense of the CrateModuleIds, we need the source root.
37 krate: Crate, 39 krate: Crate,
38 impls: FxHashMap<TyFingerprint, Vec<(ModuleId, ImplId)>>, 40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
39 impls_by_trait: FxHashMap<TraitId, Vec<(ModuleId, ImplId)>>, 41 impls_by_trait: FxHashMap<TraitId, Vec<(CrateModuleId, ImplId)>>,
40} 42}
41 43
42impl CrateImplBlocks { 44impl CrateImplBlocks {
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index 5741ca90d..30aeac48e 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -10,14 +10,6 @@ pub enum UncertainIntTy {
10} 10}
11 11
12impl UncertainIntTy { 12impl UncertainIntTy {
13 pub fn ty_to_string(&self) -> &'static str {
14 match *self {
15 UncertainIntTy::Unknown => "{integer}",
16 UncertainIntTy::Signed(ty) => ty.ty_to_string(),
17 UncertainIntTy::Unsigned(ty) => ty.ty_to_string(),
18 }
19 }
20
21 pub fn from_name(name: &Name) -> Option<UncertainIntTy> { 13 pub fn from_name(name: &Name) -> Option<UncertainIntTy> {
22 if let Some(ty) = IntTy::from_name(name) { 14 if let Some(ty) = IntTy::from_name(name) {
23 Some(UncertainIntTy::Signed(ty)) 15 Some(UncertainIntTy::Signed(ty))
@@ -29,6 +21,16 @@ impl UncertainIntTy {
29 } 21 }
30} 22}
31 23
24impl fmt::Display for UncertainIntTy {
25 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26 match *self {
27 UncertainIntTy::Unknown => write!(f, "{{integer}}"),
28 UncertainIntTy::Signed(ty) => write!(f, "{}", ty),
29 UncertainIntTy::Unsigned(ty) => write!(f, "{}", ty),
30 }
31 }
32}
33
32#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)] 34#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)]
33pub enum UncertainFloatTy { 35pub enum UncertainFloatTy {
34 Unknown, 36 Unknown,
@@ -36,13 +38,6 @@ pub enum UncertainFloatTy {
36} 38}
37 39
38impl UncertainFloatTy { 40impl UncertainFloatTy {
39 pub fn ty_to_string(&self) -> &'static str {
40 match *self {
41 UncertainFloatTy::Unknown => "{float}",
42 UncertainFloatTy::Known(ty) => ty.ty_to_string(),
43 }
44 }
45
46 pub fn from_name(name: &Name) -> Option<UncertainFloatTy> { 41 pub fn from_name(name: &Name) -> Option<UncertainFloatTy> {
47 if let Some(ty) = FloatTy::from_name(name) { 42 if let Some(ty) = FloatTy::from_name(name) {
48 Some(UncertainFloatTy::Known(ty)) 43 Some(UncertainFloatTy::Known(ty))
@@ -52,6 +47,15 @@ impl UncertainFloatTy {
52 } 47 }
53} 48}
54 49
50impl fmt::Display for UncertainFloatTy {
51 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52 match *self {
53 UncertainFloatTy::Unknown => write!(f, "{{float}}"),
54 UncertainFloatTy::Known(ty) => write!(f, "{}", ty),
55 }
56 }
57}
58
55#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] 59#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
56pub enum IntTy { 60pub enum IntTy {
57 Isize, 61 Isize,
@@ -70,22 +74,19 @@ impl fmt::Debug for IntTy {
70 74
71impl fmt::Display for IntTy { 75impl fmt::Display for IntTy {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 write!(f, "{}", self.ty_to_string()) 77 let s = match *self {
74 }
75}
76
77impl IntTy {
78 pub fn ty_to_string(&self) -> &'static str {
79 match *self {
80 IntTy::Isize => "isize", 78 IntTy::Isize => "isize",
81 IntTy::I8 => "i8", 79 IntTy::I8 => "i8",
82 IntTy::I16 => "i16", 80 IntTy::I16 => "i16",
83 IntTy::I32 => "i32", 81 IntTy::I32 => "i32",
84 IntTy::I64 => "i64", 82 IntTy::I64 => "i64",
85 IntTy::I128 => "i128", 83 IntTy::I128 => "i128",
86 } 84 };
85 write!(f, "{}", s)
87 } 86 }
87}
88 88
89impl IntTy {
89 pub fn from_name(name: &Name) -> Option<IntTy> { 90 pub fn from_name(name: &Name) -> Option<IntTy> {
90 match name.as_known_name()? { 91 match name.as_known_name()? {
91 KnownName::Isize => Some(IntTy::Isize), 92 KnownName::Isize => Some(IntTy::Isize),
@@ -109,18 +110,21 @@ pub enum UintTy {
109 U128, 110 U128,
110} 111}
111 112
112impl UintTy { 113impl fmt::Display for UintTy {
113 pub fn ty_to_string(&self) -> &'static str { 114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 match *self { 115 let s = match *self {
115 UintTy::Usize => "usize", 116 UintTy::Usize => "usize",
116 UintTy::U8 => "u8", 117 UintTy::U8 => "u8",
117 UintTy::U16 => "u16", 118 UintTy::U16 => "u16",
118 UintTy::U32 => "u32", 119 UintTy::U32 => "u32",
119 UintTy::U64 => "u64", 120 UintTy::U64 => "u64",
120 UintTy::U128 => "u128", 121 UintTy::U128 => "u128",
121 } 122 };
123 write!(f, "{}", s)
122 } 124 }
125}
123 126
127impl UintTy {
124 pub fn from_name(name: &Name) -> Option<UintTy> { 128 pub fn from_name(name: &Name) -> Option<UintTy> {
125 match name.as_known_name()? { 129 match name.as_known_name()? {
126 KnownName::Usize => Some(UintTy::Usize), 130 KnownName::Usize => Some(UintTy::Usize),
@@ -140,12 +144,6 @@ impl fmt::Debug for UintTy {
140 } 144 }
141} 145}
142 146
143impl fmt::Display for UintTy {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 write!(f, "{}", self.ty_to_string())
146 }
147}
148
149#[derive(Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] 147#[derive(Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)]
150pub enum FloatTy { 148pub enum FloatTy {
151 F32, 149 F32,
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 0f8551a9d..0f2172ddf 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -10,6 +10,7 @@ use test_utils::covers;
10use crate::{ 10use crate::{
11 source_binder, 11 source_binder,
12 mock::MockDatabase, 12 mock::MockDatabase,
13 ty::display::HirDisplay,
13}; 14};
14 15
15// These tests compare the inference results for all expressions in a file 16// These tests compare the inference results for all expressions in a file
@@ -2196,7 +2197,7 @@ fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
2196 let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap(); 2197 let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap();
2197 let expr = body_source_map.node_expr(node).unwrap(); 2198 let expr = body_source_map.node_expr(node).unwrap();
2198 let ty = &inference_result[expr]; 2199 let ty = &inference_result[expr];
2199 ty.to_string() 2200 ty.display(db).to_string()
2200} 2201}
2201 2202
2202fn infer(content: &str) -> String { 2203fn infer(content: &str) -> String {
@@ -2232,7 +2233,7 @@ fn infer(content: &str) -> String {
2232 "{} '{}': {}\n", 2233 "{} '{}': {}\n",
2233 syntax_ptr.range(), 2234 syntax_ptr.range(),
2234 ellipsize(node.text().to_string().replace("\n", " "), 15), 2235 ellipsize(node.text().to_string().replace("\n", " "), 15),
2235 ty 2236 ty.display(&db)
2236 ) 2237 )
2237 .unwrap(); 2238 .unwrap();
2238 } 2239 }
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 0c90ed5b5..26fde91bc 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -223,7 +223,7 @@ impl RootDatabase {
223 self.query(hir::db::FileItemsQuery).sweep(sweep); 223 self.query(hir::db::FileItemsQuery).sweep(sweep);
224 self.query(hir::db::FileItemQuery).sweep(sweep); 224 self.query(hir::db::FileItemQuery).sweep(sweep);
225 225
226 self.query(hir::db::LowerModuleWithSourceMapQuery).sweep(sweep); 226 self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep);
227 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); 227 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);
228 } 228 }
229} 229}
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 71003104b..28c8f83ab 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,7 +1,7 @@
1//! This modules takes care of rendering various defenitions as completion items. 1//! This modules takes care of rendering various defenitions as completion items.
2use join_to_string::join; 2use join_to_string::join;
3use test_utils::tested_by; 3use test_utils::tested_by;
4use hir::{Docs, PerNs, Resolution}; 4use hir::{Docs, PerNs, Resolution, HirDisplay};
5use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
6 6
7use crate::completion::{ 7use crate::completion::{
@@ -22,7 +22,7 @@ impl Completions {
22 field.name(ctx.db).to_string(), 22 field.name(ctx.db).to_string(),
23 ) 23 )
24 .kind(CompletionItemKind::Field) 24 .kind(CompletionItemKind::Field)
25 .detail(field.ty(ctx.db).subst(substs).to_string()) 25 .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string())
26 .set_documentation(field.docs(ctx.db)) 26 .set_documentation(field.docs(ctx.db))
27 .add_to(self); 27 .add_to(self);
28 } 28 }
@@ -30,7 +30,7 @@ impl Completions {
30 pub(crate) fn add_pos_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) { 30 pub(crate) fn add_pos_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
31 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string()) 31 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
32 .kind(CompletionItemKind::Field) 32 .kind(CompletionItemKind::Field)
33 .detail(ty.to_string()) 33 .detail(ty.display(ctx.db).to_string())
34 .add_to(self); 34 .add_to(self);
35 } 35 }
36 36
@@ -154,7 +154,10 @@ impl Completions {
154 None => return, 154 None => return,
155 }; 155 };
156 let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db)); 156 let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
157 let detail = join(detail_types).separator(", ").surround_with("(", ")").to_string(); 157 let detail = join(detail_types.map(|t| t.display(ctx.db).to_string()))
158 .separator(", ")
159 .surround_with("(", ")")
160 .to_string();
158 161
159 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 162 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
160 .kind(CompletionItemKind::EnumVariant) 163 .kind(CompletionItemKind::EnumVariant)
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs
index 4051728e1..d23290b74 100644
--- a/crates/ra_ide_api/src/extend_selection.rs
+++ b/crates/ra_ide_api/src/extend_selection.rs
@@ -1,55 +1,13 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::AstNode;
3 SyntaxNode, AstNode, SourceFile,
4 ast, algo::find_covering_node,
5};
6 3
7use crate::{ 4use crate::{
8 TextRange, FileRange, 5 TextRange, FileRange,
9 db::RootDatabase, 6 db::RootDatabase,
10}; 7};
11 8
9// FIXME: restore macro support
12pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { 10pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
13 let source_file = db.parse(frange.file_id); 11 let source_file = db.parse(frange.file_id);
14 if let Some(range) = extend_selection_in_macro(db, &source_file, frange) {
15 return range;
16 }
17 ra_ide_api_light::extend_selection(source_file.syntax(), frange.range).unwrap_or(frange.range) 12 ra_ide_api_light::extend_selection(source_file.syntax(), frange.range).unwrap_or(frange.range)
18} 13}
19
20fn extend_selection_in_macro(
21 _db: &RootDatabase,
22 source_file: &SourceFile,
23 frange: FileRange,
24) -> Option<TextRange> {
25 let macro_call = find_macro_call(source_file.syntax(), frange.range)?;
26 let (off, exp) = hir::MacroDef::ast_expand(macro_call)?;
27 let dst_range = exp.map_range_forward(frange.range - off)?;
28 let dst_range = ra_ide_api_light::extend_selection(&exp.syntax(), dst_range)?;
29 let src_range = exp.map_range_back(dst_range)? + off;
30 Some(src_range)
31}
32
33fn find_macro_call(node: &SyntaxNode, range: TextRange) -> Option<&ast::MacroCall> {
34 find_covering_node(node, range).ancestors().find_map(ast::MacroCall::cast)
35}
36
37#[cfg(test)]
38mod tests {
39 use ra_syntax::TextRange;
40
41 use crate::mock_analysis::single_file_with_range;
42
43 #[test]
44 fn extend_selection_inside_macros() {
45 let (analysis, frange) = single_file_with_range(
46 "
47 fn main() {
48 vec![foo(|x| <|>x<|>)];
49 }
50 ",
51 );
52 let r = analysis.extend_selection(frange).unwrap();
53 assert_eq!(r, TextRange::from_to(50.into(), 55.into()));
54 }
55}
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 66a625c6c..f6a83dd93 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -3,6 +3,7 @@ use ra_syntax::{
3 AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, 3 AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner},
4 algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}}, 4 algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}},
5}; 5};
6use hir::HirDisplay;
6 7
7use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; 8use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget};
8 9
@@ -134,9 +135,9 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
134 let infer = function.infer(db); 135 let infer = function.infer(db);
135 let source_map = function.body_source_map(db); 136 let source_map = function.body_source_map(db);
136 if let Some(expr) = ast::Expr::cast(node).and_then(|e| source_map.node_expr(e)) { 137 if let Some(expr) = ast::Expr::cast(node).and_then(|e| source_map.node_expr(e)) {
137 Some(infer[expr].to_string()) 138 Some(infer[expr].display(db).to_string())
138 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| source_map.node_pat(p)) { 139 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| source_map.node_pat(p)) {
139 Some(infer[pat].to_string()) 140 Some(infer[pat].display(db).to_string())
140 } else { 141 } else {
141 None 142 None
142 } 143 }
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
index 896b47f10..ee9220a15 100644
--- a/crates/ra_ide_api/src/impls.rs
+++ b/crates/ra_ide_api/src/impls.rs
@@ -81,8 +81,9 @@ mod tests {
81 fn check_goto(fixture: &str, expected: &[&str]) { 81 fn check_goto(fixture: &str, expected: &[&str]) {
82 let (analysis, pos) = analysis_and_position(fixture); 82 let (analysis, pos) = analysis_and_position(fixture);
83 83
84 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info; 84 let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
85 assert_eq!(navs.len(), expected.len()); 85 assert_eq!(navs.len(), expected.len());
86 navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start()));
86 navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i])); 87 navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i]));
87 } 88 }
88 89
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index d64b5a4e0..2395930f0 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -1,7 +1,7 @@
1use itertools::Itertools; 1use itertools::Itertools;
2use ra_syntax::{ 2use ra_syntax::{
3 TextRange, SyntaxNode, 3 TextRange, SyntaxNode,
4 ast::{self, AstNode, NameOwner, ModuleItemOwner}, 4 ast::{self, AstNode, NameOwner, ModuleItemOwner, AttrsOwner},
5}; 5};
6use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
7 7
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index 94fe1d6d7..23c743bef 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -30,7 +30,7 @@ use std::{
30use fst::{self, Streamer}; 30use fst::{self, Streamer};
31use ra_syntax::{ 31use ra_syntax::{
32 SyntaxNode, SyntaxNodePtr, SourceFile, SmolStr, TreeArc, AstNode, 32 SyntaxNode, SyntaxNodePtr, SourceFile, SmolStr, TreeArc, AstNode,
33 algo::{visit::{visitor, Visitor}, find_covering_node}, 33 algo::{visit::{visitor, Visitor}},
34 SyntaxKind::{self, *}, 34 SyntaxKind::{self, *},
35 ast::{self, NameOwner}, 35 ast::{self, NameOwner},
36 WalkEvent, 36 WalkEvent,
@@ -66,14 +66,9 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex>
66 db.check_canceled(); 66 db.check_canceled();
67 let source_file = db.parse(file_id); 67 let source_file = db.parse(file_id);
68 68
69 let mut symbols = source_file_to_file_symbols(&source_file, file_id); 69 let symbols = source_file_to_file_symbols(&source_file, file_id);
70 70
71 for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) { 71 // TODO: add macros here
72 let node = find_covering_node(source_file.syntax(), text_range);
73 let ptr = SyntaxNodePtr::new(node);
74 // TODO: Should we get container name for macro symbols?
75 symbols.push(FileSymbol { file_id, name, ptr, name_range: None, container_name: None })
76 }
77 72
78 Arc::new(SymbolIndex::new(symbols)) 73 Arc::new(SymbolIndex::new(symbols))
79} 74}
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 345b6653d..fdd87bcff 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -1,4 +1,4 @@
1use ra_syntax::{ast, AstNode,}; 1use ra_syntax::AstNode;
2use ra_db::SourceDatabase; 2use ra_db::SourceDatabase;
3 3
4use crate::{ 4use crate::{
@@ -8,37 +8,5 @@ use crate::{
8 8
9pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { 9pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
10 let source_file = db.parse(file_id); 10 let source_file = db.parse(file_id);
11 let mut res = ra_ide_api_light::highlight(source_file.syntax()); 11 ra_ide_api_light::highlight(source_file.syntax())
12 for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
13 if let Some((off, exp)) = hir::MacroDef::ast_expand(macro_call) {
14 let mapped_ranges =
15 ra_ide_api_light::highlight(&exp.syntax()).into_iter().filter_map(|r| {
16 let mapped_range = exp.map_range_back(r.range)?;
17 let res = HighlightedRange { range: mapped_range + off, tag: r.tag };
18 Some(res)
19 });
20 res.extend(mapped_ranges);
21 }
22 }
23 res
24}
25
26#[cfg(test)]
27mod tests {
28 use crate::mock_analysis::single_file;
29
30 use insta::assert_debug_snapshot_matches;
31
32 #[test]
33 fn highlights_code_inside_macros() {
34 let (analysis, file_id) = single_file(
35 "
36 fn main() {
37 vec![{ let x = 92; x}];
38 }
39 ",
40 );
41 let highlights = analysis.highlight(file_id).unwrap();
42 assert_debug_snapshot_matches!("highlights_code_inside_macros", &highlights);
43 }
44} 12}
diff --git a/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap b/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap
index d258820af..5bb953892 100644
--- a/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap
+++ b/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap
@@ -7,7 +7,7 @@ source: "crates\\ra_ide_api\\tests\\test\\main.rs"
7[ 7[
8 Diagnostic { 8 Diagnostic {
9 message: "unresolved module", 9 message: "unresolved module",
10 range: [4; 7), 10 range: [0; 8),
11 fix: Some( 11 fix: Some(
12 SourceChange { 12 SourceChange {
13 label: "create module", 13 label: "create module",
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 2c75b7b4f..989308626 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -42,7 +42,7 @@ pub use crate::syntax_bridge::{ast_to_token_tree, token_tree_to_ast_item_list};
42/// be very confusing is that AST has almost exactly the same shape as 42/// be very confusing is that AST has almost exactly the same shape as
43/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident` 43/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
44/// and `$()*` have special meaning (see `Var` and `Repeat` data structures) 44/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
45#[derive(Debug, PartialEq, Eq)] 45#[derive(Clone, Debug, PartialEq, Eq)]
46pub struct MacroRules { 46pub struct MacroRules {
47 pub(crate) rules: Vec<Rule>, 47 pub(crate) rules: Vec<Rule>,
48} 48}
@@ -56,13 +56,13 @@ impl MacroRules {
56 } 56 }
57} 57}
58 58
59#[derive(Debug, PartialEq, Eq)] 59#[derive(Clone, Debug, PartialEq, Eq)]
60pub(crate) struct Rule { 60pub(crate) struct Rule {
61 pub(crate) lhs: Subtree, 61 pub(crate) lhs: Subtree,
62 pub(crate) rhs: Subtree, 62 pub(crate) rhs: Subtree,
63} 63}
64 64
65#[derive(Debug, PartialEq, Eq)] 65#[derive(Clone, Debug, PartialEq, Eq)]
66pub(crate) enum TokenTree { 66pub(crate) enum TokenTree {
67 Leaf(Leaf), 67 Leaf(Leaf),
68 Subtree(Subtree), 68 Subtree(Subtree),
@@ -70,7 +70,7 @@ pub(crate) enum TokenTree {
70} 70}
71impl_froms!(TokenTree: Leaf, Subtree, Repeat); 71impl_froms!(TokenTree: Leaf, Subtree, Repeat);
72 72
73#[derive(Debug, PartialEq, Eq)] 73#[derive(Clone, Debug, PartialEq, Eq)]
74pub(crate) enum Leaf { 74pub(crate) enum Leaf {
75 Literal(Literal), 75 Literal(Literal),
76 Punct(Punct), 76 Punct(Punct),
@@ -79,37 +79,37 @@ pub(crate) enum Leaf {
79} 79}
80impl_froms!(Leaf: Literal, Punct, Ident, Var); 80impl_froms!(Leaf: Literal, Punct, Ident, Var);
81 81
82#[derive(Debug, PartialEq, Eq)] 82#[derive(Clone, Debug, PartialEq, Eq)]
83pub(crate) struct Subtree { 83pub(crate) struct Subtree {
84 pub(crate) delimiter: Delimiter, 84 pub(crate) delimiter: Delimiter,
85 pub(crate) token_trees: Vec<TokenTree>, 85 pub(crate) token_trees: Vec<TokenTree>,
86} 86}
87 87
88#[derive(Debug, PartialEq, Eq)] 88#[derive(Clone, Debug, PartialEq, Eq)]
89pub(crate) struct Repeat { 89pub(crate) struct Repeat {
90 pub(crate) subtree: Subtree, 90 pub(crate) subtree: Subtree,
91 pub(crate) kind: RepeatKind, 91 pub(crate) kind: RepeatKind,
92 pub(crate) separator: Option<char>, 92 pub(crate) separator: Option<char>,
93} 93}
94 94
95#[derive(Debug, PartialEq, Eq)] 95#[derive(Clone, Debug, PartialEq, Eq)]
96pub(crate) enum RepeatKind { 96pub(crate) enum RepeatKind {
97 ZeroOrMore, 97 ZeroOrMore,
98 OneOrMore, 98 OneOrMore,
99 ZeroOrOne, 99 ZeroOrOne,
100} 100}
101 101
102#[derive(Debug, PartialEq, Eq)] 102#[derive(Clone, Debug, PartialEq, Eq)]
103pub(crate) struct Literal { 103pub(crate) struct Literal {
104 pub(crate) text: SmolStr, 104 pub(crate) text: SmolStr,
105} 105}
106 106
107#[derive(Debug, PartialEq, Eq)] 107#[derive(Clone, Debug, PartialEq, Eq)]
108pub(crate) struct Ident { 108pub(crate) struct Ident {
109 pub(crate) text: SmolStr, 109 pub(crate) text: SmolStr,
110} 110}
111 111
112#[derive(Debug, PartialEq, Eq)] 112#[derive(Clone, Debug, PartialEq, Eq)]
113pub(crate) struct Var { 113pub(crate) struct Var {
114 pub(crate) text: SmolStr, 114 pub(crate) text: SmolStr,
115 pub(crate) kind: Option<SmolStr>, 115 pub(crate) kind: Option<SmolStr>,
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 2dd97b665..2dafd68f6 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -155,7 +155,14 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
155 _ => return Err(ExpandError::UnexpectedToken), 155 _ => return Err(ExpandError::UnexpectedToken),
156 }, 156 },
157 crate::TokenTree::Repeat(crate::Repeat { subtree, kind: _, separator }) => { 157 crate::TokenTree::Repeat(crate::Repeat { subtree, kind: _, separator }) => {
158 // Dirty hack to make macro-expansion terminate.
159 // This should be replaced by a propper macro-by-example implementation
160 let mut limit = 128;
158 while let Ok(nested) = match_lhs(subtree, input) { 161 while let Ok(nested) = match_lhs(subtree, input) {
162 limit -= 1;
163 if limit == 0 {
164 break;
165 }
159 res.push_nested(nested)?; 166 res.push_nested(nested)?;
160 if let Some(separator) = *separator { 167 if let Some(separator) = *separator {
161 if !input.is_eof() { 168 if !input.is_eof() {
@@ -196,7 +203,14 @@ fn expand_tt(
196 crate::TokenTree::Repeat(repeat) => { 203 crate::TokenTree::Repeat(repeat) => {
197 let mut token_trees = Vec::new(); 204 let mut token_trees = Vec::new();
198 nesting.push(0); 205 nesting.push(0);
206 // Dirty hack to make macro-expansion terminate.
207 // This should be replaced by a propper macro-by-example implementation
208 let mut limit = 128;
199 while let Ok(t) = expand_subtree(&repeat.subtree, bindings, nesting) { 209 while let Ok(t) = expand_subtree(&repeat.subtree, bindings, nesting) {
210 limit -= 1;
211 if limit == 0 {
212 break;
213 }
200 let idx = nesting.pop().unwrap(); 214 let idx = nesting.pop().unwrap();
201 nesting.push(idx + 1); 215 nesting.push(idx + 1);
202 token_trees.push(t.into()) 216 token_trees.push(t.into())
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 70c71a8e1..5a3b9f589 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -43,65 +43,64 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
43 attributes::inner_attributes(p); 43 attributes::inner_attributes(p);
44 44
45 while !p.at(EOF) && !p.at(R_CURLY) { 45 while !p.at(EOF) && !p.at(R_CURLY) {
46 match p.current() { 46 // test nocontentexpr
47 // test nocontentexpr 47 // fn foo(){
48 // fn foo(){ 48 // ;;;some_expr();;;;{;;;};;;;Ok(())
49 // ;;;some_expr();;;;{;;;};;;;Ok(()) 49 // }
50 // } 50 if p.current() == SEMI {
51 SEMI => p.bump(), 51 p.bump();
52 _ => { 52 continue;
53 // test block_items 53 }
54 // fn a() { fn b() {} } 54
55 let m = p.start(); 55 // test block_items
56 let has_attrs = p.at(POUND); 56 // fn a() { fn b() {} }
57 attributes::outer_attributes(p); 57 let m = p.start();
58 if p.at(LET_KW) { 58 let has_attrs = p.at(POUND);
59 let_stmt(p, m); 59 attributes::outer_attributes(p);
60 if p.at(LET_KW) {
61 let_stmt(p, m);
62 continue;
63 }
64
65 match items::maybe_item(p, items::ItemFlavor::Mod) {
66 items::MaybeItem::Item(kind) => {
67 m.complete(p, kind);
68 }
69 items::MaybeItem::Modifiers => {
70 m.abandon(p);
71 p.error("expected an item");
72 }
73 // test pub_expr
74 // fn foo() { pub 92; } //FIXME
75 items::MaybeItem::None => {
76 if has_attrs {
77 m.abandon(p);
78 p.error("expected a let statement or an item after attributes in block");
60 } else { 79 } else {
61 match items::maybe_item(p, items::ItemFlavor::Mod) { 80 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block;
62 items::MaybeItem::Item(kind) => { 81 if p.at(R_CURLY) {
63 m.complete(p, kind); 82 m.abandon(p);
64 } 83 } else {
65 items::MaybeItem::Modifiers => { 84 // test no_semi_after_block
66 m.abandon(p); 85 // fn foo() {
67 p.error("expected an item"); 86 // if true {}
68 } 87 // loop {}
69 // test pub_expr 88 // match () {}
70 // fn foo() { pub 92; } //FIXME 89 // while true {}
71 items::MaybeItem::None => { 90 // for _ in () {}
72 if has_attrs { 91 // {}
73 m.abandon(p); 92 // {}
74 p.error( 93 // macro_rules! test {
75 "expected a let statement or an item after attributes in block", 94 // () => {}
76 ); 95 // }
77 } else { 96 // test!{}
78 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block; 97 // }
79 if p.at(R_CURLY) { 98 if is_blocklike {
80 m.abandon(p); 99 p.eat(SEMI);
81 } else { 100 } else {
82 // test no_semi_after_block 101 p.expect(SEMI);
83 // fn foo() {
84 // if true {}
85 // loop {}
86 // match () {}
87 // while true {}
88 // for _ in () {}
89 // {}
90 // {}
91 // macro_rules! test {
92 // () => {}
93 // }
94 // test!{}
95 // }
96 if is_blocklike {
97 p.eat(SEMI);
98 } else {
99 p.expect(SEMI);
100 }
101 m.complete(p, EXPR_STMT);
102 }
103 }
104 } 102 }
103 m.complete(p, EXPR_STMT);
105 } 104 }
106 } 105 }
107 } 106 }
@@ -155,6 +154,7 @@ fn current_op(p: &Parser) -> (u8, Op) {
155 (PLUS, EQ) => return (1, Op::Composite(PLUSEQ, 2)), 154 (PLUS, EQ) => return (1, Op::Composite(PLUSEQ, 2)),
156 (MINUS, EQ) => return (1, Op::Composite(MINUSEQ, 2)), 155 (MINUS, EQ) => return (1, Op::Composite(MINUSEQ, 2)),
157 (STAR, EQ) => return (1, Op::Composite(STAREQ, 2)), 156 (STAR, EQ) => return (1, Op::Composite(STAREQ, 2)),
157 (PERCENT, EQ) => return (1, Op::Composite(PERCENTEQ, 2)),
158 (SLASH, EQ) => return (1, Op::Composite(SLASHEQ, 2)), 158 (SLASH, EQ) => return (1, Op::Composite(SLASHEQ, 2)),
159 (PIPE, EQ) => return (1, Op::Composite(PIPEEQ, 2)), 159 (PIPE, EQ) => return (1, Op::Composite(PIPEEQ, 2)),
160 (AMP, EQ) => return (1, Op::Composite(AMPEQ, 2)), 160 (AMP, EQ) => return (1, Op::Composite(AMPEQ, 2)),
@@ -453,8 +453,13 @@ pub(crate) fn named_field_list(p: &mut Parser) {
453 p.bump(); 453 p.bump();
454 while !p.at(EOF) && !p.at(R_CURLY) { 454 while !p.at(EOF) && !p.at(R_CURLY) {
455 match p.current() { 455 match p.current() {
456 IDENT => { 456 // test struct_literal_field_with_attr
457 // fn main() {
458 // S { #[cfg(test)] field: 1 }
459 // }
460 IDENT | POUND => {
457 let m = p.start(); 461 let m = p.start();
462 attributes::outer_attributes(p);
458 name_ref(p); 463 name_ref(p);
459 if p.eat(COLON) { 464 if p.eat(COLON) {
460 expr(p); 465 expr(p);
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index 53bb26c5f..d933288cd 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -342,21 +342,6 @@ pub(crate) fn match_arm_list(p: &mut Parser) {
342 continue; 342 continue;
343 } 343 }
344 344
345 // test match_arms_outer_attributes
346 // fn foo() {
347 // match () {
348 // #[cfg(feature = "some")]
349 // _ => (),
350 // #[cfg(feature = "other")]
351 // _ => (),
352 // #[cfg(feature = "many")]
353 // #[cfg(feature = "attributes")]
354 // #[cfg(feature = "before")]
355 // _ => (),
356 // }
357 // }
358 attributes::outer_attributes(p);
359
360 // test match_arms_commas 345 // test match_arms_commas
361 // fn foo() { 346 // fn foo() {
362 // match () { 347 // match () {
@@ -387,6 +372,21 @@ pub(crate) fn match_arm_list(p: &mut Parser) {
387// } 372// }
388fn match_arm(p: &mut Parser) -> BlockLike { 373fn match_arm(p: &mut Parser) -> BlockLike {
389 let m = p.start(); 374 let m = p.start();
375 // test match_arms_outer_attributes
376 // fn foo() {
377 // match () {
378 // #[cfg(feature = "some")]
379 // _ => (),
380 // #[cfg(feature = "other")]
381 // _ => (),
382 // #[cfg(feature = "many")]
383 // #[cfg(feature = "attributes")]
384 // #[cfg(feature = "before")]
385 // _ => (),
386 // }
387 // }
388 attributes::outer_attributes(p);
389
390 patterns::pattern_list_r(p, TokenSet::empty()); 390 patterns::pattern_list_r(p, TokenSet::empty());
391 if p.at(IF_KW) { 391 if p.at(IF_KW) {
392 match_guard(p); 392 match_guard(p);
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index befe6687d..9a307559b 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -2,7 +2,7 @@ use super::*;
2 2
3pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST 3pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
4 .union(paths::PATH_FIRST) 4 .union(paths::PATH_FIRST)
5 .union(token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE]); 5 .union(token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]);
6 6
7pub(super) fn pattern(p: &mut Parser) { 7pub(super) fn pattern(p: &mut Parser) {
8 pattern_r(p, PAT_RECOVERY_SET) 8 pattern_r(p, PAT_RECOVERY_SET)
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 81c709bfb..d8c2cb063 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -114,6 +114,9 @@ pub trait AttrsOwner: AstNode {
114 fn attrs(&self) -> AstChildren<Attr> { 114 fn attrs(&self) -> AstChildren<Attr> {
115 children(self) 115 children(self)
116 } 116 }
117 fn has_atom_attr(&self, atom: &str) -> bool {
118 self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom)
119 }
117} 120}
118 121
119pub trait DocCommentsOwner: AstNode { 122pub trait DocCommentsOwner: AstNode {
@@ -153,12 +156,6 @@ pub trait DocCommentsOwner: AstNode {
153 } 156 }
154} 157}
155 158
156impl FnDef {
157 pub fn has_atom_attr(&self, atom: &str) -> bool {
158 self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom)
159 }
160}
161
162impl Attr { 159impl Attr {
163 pub fn is_inner(&self) -> bool { 160 pub fn is_inner(&self) -> bool {
164 let tt = match self.value() { 161 let tt = match self.value() {
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 7572225b8..54b72f8c5 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -2108,6 +2108,7 @@ impl ToOwned for MacroCall {
2108 2108
2109 2109
2110impl ast::NameOwner for MacroCall {} 2110impl ast::NameOwner for MacroCall {}
2111impl ast::AttrsOwner for MacroCall {}
2111impl MacroCall { 2112impl MacroCall {
2112 pub fn token_tree(&self) -> Option<&TokenTree> { 2113 pub fn token_tree(&self) -> Option<&TokenTree> {
2113 super::child_opt(self) 2114 super::child_opt(self)
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 66f1339c1..4f8e19bd0 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -557,7 +557,7 @@ Grammar(
557 "Name": (), 557 "Name": (),
558 "NameRef": (), 558 "NameRef": (),
559 "MacroCall": ( 559 "MacroCall": (
560 traits: [ "NameOwner" ], 560 traits: [ "NameOwner", "AttrsOwner" ],
561 options: [ "TokenTree", "Path" ], 561 options: [ "TokenTree", "Path" ],
562 ), 562 ),
563 "Attr": ( options: [ ["value", "TokenTree"] ] ), 563 "Attr": ( options: [ ["value", "TokenTree"] ] ),
diff --git a/crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt b/crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt
index b7543abc9..ed5735a63 100644
--- a/crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt
+++ b/crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt
@@ -33,11 +33,11 @@ SOURCE_FILE@[0; 293)
33 R_PAREN@[40; 41) 33 R_PAREN@[40; 41)
34 COMMA@[41; 42) 34 COMMA@[41; 42)
35 WHITESPACE@[42; 51) 35 WHITESPACE@[42; 51)
36 ATTR@[51; 52) 36 MATCH_ARM@[51; 78)
37 POUND@[51; 52) 37 ATTR@[51; 52)
38 err: `expected `[`` 38 POUND@[51; 52)
39 err: `expected pattern` 39 err: `expected `[``
40 MATCH_ARM@[52; 78) 40 err: `expected pattern`
41 ERROR@[52; 53) 41 ERROR@[52; 53)
42 EXCL@[52; 53) 42 EXCL@[52; 53)
43 err: `expected FAT_ARROW` 43 err: `expected FAT_ARROW`
@@ -103,11 +103,11 @@ SOURCE_FILE@[0; 293)
103 R_PAREN@[149; 150) 103 R_PAREN@[149; 150)
104 COMMA@[150; 151) 104 COMMA@[150; 151)
105 WHITESPACE@[151; 160) 105 WHITESPACE@[151; 160)
106 ATTR@[160; 161) 106 MATCH_ARM@[160; 179)
107 POUND@[160; 161) 107 ATTR@[160; 161)
108 err: `expected `[`` 108 POUND@[160; 161)
109 err: `expected pattern` 109 err: `expected `[``
110 MATCH_ARM@[161; 179) 110 err: `expected pattern`
111 ERROR@[161; 162) 111 ERROR@[161; 162)
112 EXCL@[161; 162) 112 EXCL@[161; 162)
113 err: `expected FAT_ARROW` 113 err: `expected FAT_ARROW`
@@ -138,22 +138,22 @@ SOURCE_FILE@[0; 293)
138 MATCH_ARM_LIST@[200; 290) 138 MATCH_ARM_LIST@[200; 290)
139 L_CURLY@[200; 201) 139 L_CURLY@[200; 201)
140 WHITESPACE@[201; 210) 140 WHITESPACE@[201; 210)
141 ATTR@[210; 222) 141 MATCH_ARM@[210; 250)
142 POUND@[210; 211) 142 ATTR@[210; 222)
143 TOKEN_TREE@[211; 222) 143 POUND@[210; 211)
144 L_BRACK@[211; 212) 144 TOKEN_TREE@[211; 222)
145 IDENT@[212; 215) "cfg" 145 L_BRACK@[211; 212)
146 TOKEN_TREE@[215; 221) 146 IDENT@[212; 215) "cfg"
147 L_PAREN@[215; 216) 147 TOKEN_TREE@[215; 221)
148 IDENT@[216; 220) "test" 148 L_PAREN@[215; 216)
149 R_PAREN@[220; 221) 149 IDENT@[216; 220) "test"
150 R_BRACK@[221; 222) 150 R_PAREN@[220; 221)
151 WHITESPACE@[222; 231) 151 R_BRACK@[221; 222)
152 ATTR@[231; 232) 152 WHITESPACE@[222; 231)
153 POUND@[231; 232) 153 ATTR@[231; 232)
154 err: `expected `[`` 154 POUND@[231; 232)
155 err: `expected pattern` 155 err: `expected `[``
156 MATCH_ARM@[232; 250) 156 err: `expected pattern`
157 ERROR@[232; 233) 157 ERROR@[232; 233)
158 EXCL@[232; 233) 158 EXCL@[232; 233)
159 err: `expected FAT_ARROW` 159 err: `expected FAT_ARROW`
diff --git a/crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt b/crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt
index 7f8767001..f540409bc 100644
--- a/crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt
+++ b/crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt
@@ -43,21 +43,21 @@ SOURCE_FILE@[0; 89)
43 R_PAREN@[57; 58) 43 R_PAREN@[57; 58)
44 COMMA@[58; 59) 44 COMMA@[58; 59)
45 WHITESPACE@[59; 68) 45 WHITESPACE@[59; 68)
46 ATTR@[68; 80) 46 MATCH_ARM@[68; 80)
47 POUND@[68; 69) 47 ATTR@[68; 80)
48 TOKEN_TREE@[69; 80) 48 POUND@[68; 69)
49 L_BRACK@[69; 70) 49 TOKEN_TREE@[69; 80)
50 IDENT@[70; 73) "cfg" 50 L_BRACK@[69; 70)
51 TOKEN_TREE@[73; 79) 51 IDENT@[70; 73) "cfg"
52 L_PAREN@[73; 74) 52 TOKEN_TREE@[73; 79)
53 IDENT@[74; 78) "test" 53 L_PAREN@[73; 74)
54 R_PAREN@[78; 79) 54 IDENT@[74; 78) "test"
55 R_BRACK@[79; 80) 55 R_PAREN@[78; 79)
56 R_BRACK@[79; 80)
57 err: `expected pattern`
58 err: `expected FAT_ARROW`
59 err: `expected expression`
56 WHITESPACE@[80; 85) 60 WHITESPACE@[80; 85)
57 err: `expected pattern`
58 err: `expected FAT_ARROW`
59 err: `expected expression`
60 MATCH_ARM@[85; 85)
61 R_CURLY@[85; 86) 61 R_CURLY@[85; 86)
62 WHITESPACE@[86; 87) 62 WHITESPACE@[86; 87)
63 R_CURLY@[87; 88) 63 R_CURLY@[87; 88)
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt
index c888fb8f0..e52a290bf 100644
--- a/crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt
@@ -21,22 +21,22 @@ SOURCE_FILE@[0; 259)
21 MATCH_ARM_LIST@[24; 256) 21 MATCH_ARM_LIST@[24; 256)
22 L_CURLY@[24; 25) 22 L_CURLY@[24; 25)
23 WHITESPACE@[25; 34) 23 WHITESPACE@[25; 34)
24 ATTR@[34; 58) 24 MATCH_ARM@[34; 74)
25 POUND@[34; 35) 25 ATTR@[34; 58)
26 TOKEN_TREE@[35; 58) 26 POUND@[34; 35)
27 L_BRACK@[35; 36) 27 TOKEN_TREE@[35; 58)
28 IDENT@[36; 39) "cfg" 28 L_BRACK@[35; 36)
29 TOKEN_TREE@[39; 57) 29 IDENT@[36; 39) "cfg"
30 L_PAREN@[39; 40) 30 TOKEN_TREE@[39; 57)
31 IDENT@[40; 47) "feature" 31 L_PAREN@[39; 40)
32 WHITESPACE@[47; 48) 32 IDENT@[40; 47) "feature"
33 EQ@[48; 49) 33 WHITESPACE@[47; 48)
34 WHITESPACE@[49; 50) 34 EQ@[48; 49)
35 STRING@[50; 56) 35 WHITESPACE@[49; 50)
36 R_PAREN@[56; 57) 36 STRING@[50; 56)
37 R_BRACK@[57; 58) 37 R_PAREN@[56; 57)
38 WHITESPACE@[58; 67) 38 R_BRACK@[57; 58)
39 MATCH_ARM@[67; 74) 39 WHITESPACE@[58; 67)
40 PLACEHOLDER_PAT@[67; 68) 40 PLACEHOLDER_PAT@[67; 68)
41 UNDERSCORE@[67; 68) 41 UNDERSCORE@[67; 68)
42 WHITESPACE@[68; 69) 42 WHITESPACE@[68; 69)
@@ -47,22 +47,22 @@ SOURCE_FILE@[0; 259)
47 R_PAREN@[73; 74) 47 R_PAREN@[73; 74)
48 COMMA@[74; 75) 48 COMMA@[74; 75)
49 WHITESPACE@[75; 84) 49 WHITESPACE@[75; 84)
50 ATTR@[84; 109) 50 MATCH_ARM@[84; 125)
51 POUND@[84; 85) 51 ATTR@[84; 109)
52 TOKEN_TREE@[85; 109) 52 POUND@[84; 85)
53 L_BRACK@[85; 86) 53 TOKEN_TREE@[85; 109)
54 IDENT@[86; 89) "cfg" 54 L_BRACK@[85; 86)
55 TOKEN_TREE@[89; 108) 55 IDENT@[86; 89) "cfg"
56 L_PAREN@[89; 90) 56 TOKEN_TREE@[89; 108)
57 IDENT@[90; 97) "feature" 57 L_PAREN@[89; 90)
58 WHITESPACE@[97; 98) 58 IDENT@[90; 97) "feature"
59 EQ@[98; 99) 59 WHITESPACE@[97; 98)
60 WHITESPACE@[99; 100) 60 EQ@[98; 99)
61 STRING@[100; 107) 61 WHITESPACE@[99; 100)
62 R_PAREN@[107; 108) 62 STRING@[100; 107)
63 R_BRACK@[108; 109) 63 R_PAREN@[107; 108)
64 WHITESPACE@[109; 118) 64 R_BRACK@[108; 109)
65 MATCH_ARM@[118; 125) 65 WHITESPACE@[109; 118)
66 PLACEHOLDER_PAT@[118; 119) 66 PLACEHOLDER_PAT@[118; 119)
67 UNDERSCORE@[118; 119) 67 UNDERSCORE@[118; 119)
68 WHITESPACE@[119; 120) 68 WHITESPACE@[119; 120)
@@ -73,52 +73,52 @@ SOURCE_FILE@[0; 259)
73 R_PAREN@[124; 125) 73 R_PAREN@[124; 125)
74 COMMA@[125; 126) 74 COMMA@[125; 126)
75 WHITESPACE@[126; 135) 75 WHITESPACE@[126; 135)
76 ATTR@[135; 159) 76 MATCH_ARM@[135; 249)
77 POUND@[135; 136) 77 ATTR@[135; 159)
78 TOKEN_TREE@[136; 159) 78 POUND@[135; 136)
79 L_BRACK@[136; 137) 79 TOKEN_TREE@[136; 159)
80 IDENT@[137; 140) "cfg" 80 L_BRACK@[136; 137)
81 TOKEN_TREE@[140; 158) 81 IDENT@[137; 140) "cfg"
82 L_PAREN@[140; 141) 82 TOKEN_TREE@[140; 158)
83 IDENT@[141; 148) "feature" 83 L_PAREN@[140; 141)
84 WHITESPACE@[148; 149) 84 IDENT@[141; 148) "feature"
85 EQ@[149; 150) 85 WHITESPACE@[148; 149)
86 WHITESPACE@[150; 151) 86 EQ@[149; 150)
87 STRING@[151; 157) 87 WHITESPACE@[150; 151)
88 R_PAREN@[157; 158) 88 STRING@[151; 157)
89 R_BRACK@[158; 159) 89 R_PAREN@[157; 158)
90 WHITESPACE@[159; 168) 90 R_BRACK@[158; 159)
91 ATTR@[168; 198) 91 WHITESPACE@[159; 168)
92 POUND@[168; 169) 92 ATTR@[168; 198)
93 TOKEN_TREE@[169; 198) 93 POUND@[168; 169)
94 L_BRACK@[169; 170) 94 TOKEN_TREE@[169; 198)
95 IDENT@[170; 173) "cfg" 95 L_BRACK@[169; 170)
96 TOKEN_TREE@[173; 197) 96 IDENT@[170; 173) "cfg"
97 L_PAREN@[173; 174) 97 TOKEN_TREE@[173; 197)
98 IDENT@[174; 181) "feature" 98 L_PAREN@[173; 174)
99 WHITESPACE@[181; 182) 99 IDENT@[174; 181) "feature"
100 EQ@[182; 183) 100 WHITESPACE@[181; 182)
101 WHITESPACE@[183; 184) 101 EQ@[182; 183)
102 STRING@[184; 196) 102 WHITESPACE@[183; 184)
103 R_PAREN@[196; 197) 103 STRING@[184; 196)
104 R_BRACK@[197; 198) 104 R_PAREN@[196; 197)
105 WHITESPACE@[198; 207) 105 R_BRACK@[197; 198)
106 ATTR@[207; 233) 106 WHITESPACE@[198; 207)
107 POUND@[207; 208) 107 ATTR@[207; 233)
108 TOKEN_TREE@[208; 233) 108 POUND@[207; 208)
109 L_BRACK@[208; 209) 109 TOKEN_TREE@[208; 233)
110 IDENT@[209; 212) "cfg" 110 L_BRACK@[208; 209)
111 TOKEN_TREE@[212; 232) 111 IDENT@[209; 212) "cfg"
112 L_PAREN@[212; 213) 112 TOKEN_TREE@[212; 232)
113 IDENT@[213; 220) "feature" 113 L_PAREN@[212; 213)
114 WHITESPACE@[220; 221) 114 IDENT@[213; 220) "feature"
115 EQ@[221; 222) 115 WHITESPACE@[220; 221)
116 WHITESPACE@[222; 223) 116 EQ@[221; 222)
117 STRING@[223; 231) 117 WHITESPACE@[222; 223)
118 R_PAREN@[231; 232) 118 STRING@[223; 231)
119 R_BRACK@[232; 233) 119 R_PAREN@[231; 232)
120 WHITESPACE@[233; 242) 120 R_BRACK@[232; 233)
121 MATCH_ARM@[242; 249) 121 WHITESPACE@[233; 242)
122 PLACEHOLDER_PAT@[242; 243) 122 PLACEHOLDER_PAT@[242; 243)
123 UNDERSCORE@[242; 243) 123 UNDERSCORE@[242; 243)
124 WHITESPACE@[243; 244) 124 WHITESPACE@[243; 244)
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.rs b/crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.rs
new file mode 100644
index 000000000..a6c7760c7
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.rs
@@ -0,0 +1,3 @@
1fn main() {
2 S { #[cfg(test)] field: 1 }
3}
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.txt
new file mode 100644
index 000000000..34c80500a
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.txt
@@ -0,0 +1,45 @@
1SOURCE_FILE@[0; 46)
2 FN_DEF@[0; 45)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK@[10; 45)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 STRUCT_LIT@[16; 43)
15 PATH@[16; 17)
16 PATH_SEGMENT@[16; 17)
17 NAME_REF@[16; 17)
18 IDENT@[16; 17) "S"
19 WHITESPACE@[17; 18)
20 NAMED_FIELD_LIST@[18; 43)
21 L_CURLY@[18; 19)
22 WHITESPACE@[19; 20)
23 NAMED_FIELD@[20; 41)
24 ATTR@[20; 32)
25 POUND@[20; 21)
26 TOKEN_TREE@[21; 32)
27 L_BRACK@[21; 22)
28 IDENT@[22; 25) "cfg"
29 TOKEN_TREE@[25; 31)
30 L_PAREN@[25; 26)
31 IDENT@[26; 30) "test"
32 R_PAREN@[30; 31)
33 R_BRACK@[31; 32)
34 WHITESPACE@[32; 33)
35 NAME_REF@[33; 38)
36 IDENT@[33; 38) "field"
37 COLON@[38; 39)
38 WHITESPACE@[39; 40)
39 LITERAL@[40; 41)
40 INT_NUMBER@[40; 41) "1"
41 WHITESPACE@[41; 42)
42 R_CURLY@[42; 43)
43 WHITESPACE@[43; 44)
44 R_CURLY@[44; 45)
45 WHITESPACE@[45; 46)
diff --git a/crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.rs b/crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.rs
new file mode 100644
index 000000000..bbd6b0f6e
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.rs
@@ -0,0 +1,27 @@
1// https://github.com/rust-analyzer/rust-analyzer/issues/972
2
3fn main() {
4 match Some(-1) {
5 Some(-1) => (),
6 _ => (),
7 }
8
9 match Some((-1, -1)) {
10 Some((-1, -1)) => (),
11 _ => (),
12 }
13
14 match A::B(-1, -1) {
15 A::B(-1, -1) => (),
16 _ => (),
17 }
18
19 if let Some(-1) = Some(-1) {
20 }
21}
22
23enum A {
24 B(i8, i8)
25}
26
27fn foo(-128..=127: i8) {}
diff --git a/crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.txt b/crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.txt
new file mode 100644
index 000000000..ca66b44bb
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.txt
@@ -0,0 +1,320 @@
1SOURCE_FILE@[0; 395)
2 COMMENT@[0; 60)
3 WHITESPACE@[60; 62)
4 FN_DEF@[62; 341)
5 FN_KW@[62; 64)
6 WHITESPACE@[64; 65)
7 NAME@[65; 69)
8 IDENT@[65; 69) "main"
9 PARAM_LIST@[69; 71)
10 L_PAREN@[69; 70)
11 R_PAREN@[70; 71)
12 WHITESPACE@[71; 72)
13 BLOCK@[72; 341)
14 L_CURLY@[72; 73)
15 WHITESPACE@[73; 78)
16 EXPR_STMT@[78; 141)
17 MATCH_EXPR@[78; 141)
18 MATCH_KW@[78; 83)
19 WHITESPACE@[83; 84)
20 CALL_EXPR@[84; 92)
21 PATH_EXPR@[84; 88)
22 PATH@[84; 88)
23 PATH_SEGMENT@[84; 88)
24 NAME_REF@[84; 88)
25 IDENT@[84; 88) "Some"
26 ARG_LIST@[88; 92)
27 L_PAREN@[88; 89)
28 PREFIX_EXPR@[89; 91)
29 MINUS@[89; 90)
30 LITERAL@[90; 91)
31 INT_NUMBER@[90; 91) "1"
32 R_PAREN@[91; 92)
33 WHITESPACE@[92; 93)
34 MATCH_ARM_LIST@[93; 141)
35 L_CURLY@[93; 94)
36 WHITESPACE@[94; 103)
37 MATCH_ARM@[103; 117)
38 TUPLE_STRUCT_PAT@[103; 111)
39 PATH@[103; 107)
40 PATH_SEGMENT@[103; 107)
41 NAME_REF@[103; 107)
42 IDENT@[103; 107) "Some"
43 L_PAREN@[107; 108)
44 LITERAL_PAT@[108; 110)
45 MINUS@[108; 109)
46 LITERAL@[109; 110)
47 INT_NUMBER@[109; 110) "1"
48 R_PAREN@[110; 111)
49 WHITESPACE@[111; 112)
50 FAT_ARROW@[112; 114)
51 WHITESPACE@[114; 115)
52 TUPLE_EXPR@[115; 117)
53 L_PAREN@[115; 116)
54 R_PAREN@[116; 117)
55 COMMA@[117; 118)
56 WHITESPACE@[118; 127)
57 MATCH_ARM@[127; 134)
58 PLACEHOLDER_PAT@[127; 128)
59 UNDERSCORE@[127; 128)
60 WHITESPACE@[128; 129)
61 FAT_ARROW@[129; 131)
62 WHITESPACE@[131; 132)
63 TUPLE_EXPR@[132; 134)
64 L_PAREN@[132; 133)
65 R_PAREN@[133; 134)
66 COMMA@[134; 135)
67 WHITESPACE@[135; 140)
68 R_CURLY@[140; 141)
69 WHITESPACE@[141; 147)
70 EXPR_STMT@[147; 222)
71 MATCH_EXPR@[147; 222)
72 MATCH_KW@[147; 152)
73 WHITESPACE@[152; 153)
74 CALL_EXPR@[153; 167)
75 PATH_EXPR@[153; 157)
76 PATH@[153; 157)
77 PATH_SEGMENT@[153; 157)
78 NAME_REF@[153; 157)
79 IDENT@[153; 157) "Some"
80 ARG_LIST@[157; 167)
81 L_PAREN@[157; 158)
82 TUPLE_EXPR@[158; 166)
83 L_PAREN@[158; 159)
84 PREFIX_EXPR@[159; 161)
85 MINUS@[159; 160)
86 LITERAL@[160; 161)
87 INT_NUMBER@[160; 161) "1"
88 COMMA@[161; 162)
89 WHITESPACE@[162; 163)
90 PREFIX_EXPR@[163; 165)
91 MINUS@[163; 164)
92 LITERAL@[164; 165)
93 INT_NUMBER@[164; 165) "1"
94 R_PAREN@[165; 166)
95 R_PAREN@[166; 167)
96 WHITESPACE@[167; 168)
97 MATCH_ARM_LIST@[168; 222)
98 L_CURLY@[168; 169)
99 WHITESPACE@[169; 178)
100 MATCH_ARM@[178; 198)
101 TUPLE_STRUCT_PAT@[178; 192)
102 PATH@[178; 182)
103 PATH_SEGMENT@[178; 182)
104 NAME_REF@[178; 182)
105 IDENT@[178; 182) "Some"
106 L_PAREN@[182; 183)
107 TUPLE_PAT@[183; 191)
108 L_PAREN@[183; 184)
109 LITERAL_PAT@[184; 186)
110 MINUS@[184; 185)
111 LITERAL@[185; 186)
112 INT_NUMBER@[185; 186) "1"
113 COMMA@[186; 187)
114 WHITESPACE@[187; 188)
115 LITERAL_PAT@[188; 190)
116 MINUS@[188; 189)
117 LITERAL@[189; 190)
118 INT_NUMBER@[189; 190) "1"
119 R_PAREN@[190; 191)
120 R_PAREN@[191; 192)
121 WHITESPACE@[192; 193)
122 FAT_ARROW@[193; 195)
123 WHITESPACE@[195; 196)
124 TUPLE_EXPR@[196; 198)
125 L_PAREN@[196; 197)
126 R_PAREN@[197; 198)
127 COMMA@[198; 199)
128 WHITESPACE@[199; 208)
129 MATCH_ARM@[208; 215)
130 PLACEHOLDER_PAT@[208; 209)
131 UNDERSCORE@[208; 209)
132 WHITESPACE@[209; 210)
133 FAT_ARROW@[210; 212)
134 WHITESPACE@[212; 213)
135 TUPLE_EXPR@[213; 215)
136 L_PAREN@[213; 214)
137 R_PAREN@[214; 215)
138 COMMA@[215; 216)
139 WHITESPACE@[216; 221)
140 R_CURLY@[221; 222)
141 WHITESPACE@[222; 228)
142 EXPR_STMT@[228; 299)
143 MATCH_EXPR@[228; 299)
144 MATCH_KW@[228; 233)
145 WHITESPACE@[233; 234)
146 CALL_EXPR@[234; 246)
147 PATH_EXPR@[234; 238)
148 PATH@[234; 238)
149 PATH@[234; 235)
150 PATH_SEGMENT@[234; 235)
151 NAME_REF@[234; 235)
152 IDENT@[234; 235) "A"
153 COLONCOLON@[235; 237)
154 PATH_SEGMENT@[237; 238)
155 NAME_REF@[237; 238)
156 IDENT@[237; 238) "B"
157 ARG_LIST@[238; 246)
158 L_PAREN@[238; 239)
159 PREFIX_EXPR@[239; 241)
160 MINUS@[239; 240)
161 LITERAL@[240; 241)
162 INT_NUMBER@[240; 241) "1"
163 COMMA@[241; 242)
164 WHITESPACE@[242; 243)
165 PREFIX_EXPR@[243; 245)
166 MINUS@[243; 244)
167 LITERAL@[244; 245)
168 INT_NUMBER@[244; 245) "1"
169 R_PAREN@[245; 246)
170 WHITESPACE@[246; 247)
171 MATCH_ARM_LIST@[247; 299)
172 L_CURLY@[247; 248)
173 WHITESPACE@[248; 257)
174 MATCH_ARM@[257; 275)
175 TUPLE_STRUCT_PAT@[257; 269)
176 PATH@[257; 261)
177 PATH@[257; 258)
178 PATH_SEGMENT@[257; 258)
179 NAME_REF@[257; 258)
180 IDENT@[257; 258) "A"
181 COLONCOLON@[258; 260)
182 PATH_SEGMENT@[260; 261)
183 NAME_REF@[260; 261)
184 IDENT@[260; 261) "B"
185 L_PAREN@[261; 262)
186 LITERAL_PAT@[262; 264)
187 MINUS@[262; 263)
188 LITERAL@[263; 264)
189 INT_NUMBER@[263; 264) "1"
190 COMMA@[264; 265)
191 WHITESPACE@[265; 266)
192 LITERAL_PAT@[266; 268)
193 MINUS@[266; 267)
194 LITERAL@[267; 268)
195 INT_NUMBER@[267; 268) "1"
196 R_PAREN@[268; 269)
197 WHITESPACE@[269; 270)
198 FAT_ARROW@[270; 272)
199 WHITESPACE@[272; 273)
200 TUPLE_EXPR@[273; 275)
201 L_PAREN@[273; 274)
202 R_PAREN@[274; 275)
203 COMMA@[275; 276)
204 WHITESPACE@[276; 285)
205 MATCH_ARM@[285; 292)
206 PLACEHOLDER_PAT@[285; 286)
207 UNDERSCORE@[285; 286)
208 WHITESPACE@[286; 287)
209 FAT_ARROW@[287; 289)
210 WHITESPACE@[289; 290)
211 TUPLE_EXPR@[290; 292)
212 L_PAREN@[290; 291)
213 R_PAREN@[291; 292)
214 COMMA@[292; 293)
215 WHITESPACE@[293; 298)
216 R_CURLY@[298; 299)
217 WHITESPACE@[299; 305)
218 IF_EXPR@[305; 339)
219 IF_KW@[305; 307)
220 WHITESPACE@[307; 308)
221 CONDITION@[308; 331)
222 LET_KW@[308; 311)
223 WHITESPACE@[311; 312)
224 TUPLE_STRUCT_PAT@[312; 320)
225 PATH@[312; 316)
226 PATH_SEGMENT@[312; 316)
227 NAME_REF@[312; 316)
228 IDENT@[312; 316) "Some"
229 L_PAREN@[316; 317)
230 LITERAL_PAT@[317; 319)
231 MINUS@[317; 318)
232 LITERAL@[318; 319)
233 INT_NUMBER@[318; 319) "1"
234 R_PAREN@[319; 320)
235 WHITESPACE@[320; 321)
236 EQ@[321; 322)
237 WHITESPACE@[322; 323)
238 CALL_EXPR@[323; 331)
239 PATH_EXPR@[323; 327)
240 PATH@[323; 327)
241 PATH_SEGMENT@[323; 327)
242 NAME_REF@[323; 327)
243 IDENT@[323; 327) "Some"
244 ARG_LIST@[327; 331)
245 L_PAREN@[327; 328)
246 PREFIX_EXPR@[328; 330)
247 MINUS@[328; 329)
248 LITERAL@[329; 330)
249 INT_NUMBER@[329; 330) "1"
250 R_PAREN@[330; 331)
251 WHITESPACE@[331; 332)
252 BLOCK@[332; 339)
253 L_CURLY@[332; 333)
254 WHITESPACE@[333; 338)
255 R_CURLY@[338; 339)
256 WHITESPACE@[339; 340)
257 R_CURLY@[340; 341)
258 WHITESPACE@[341; 343)
259 ENUM_DEF@[343; 367)
260 ENUM_KW@[343; 347)
261 WHITESPACE@[347; 348)
262 NAME@[348; 349)
263 IDENT@[348; 349) "A"
264 WHITESPACE@[349; 350)
265 ENUM_VARIANT_LIST@[350; 367)
266 L_CURLY@[350; 351)
267 WHITESPACE@[351; 356)
268 ENUM_VARIANT@[356; 365)
269 NAME@[356; 357)
270 IDENT@[356; 357) "B"
271 POS_FIELD_DEF_LIST@[357; 365)
272 L_PAREN@[357; 358)
273 POS_FIELD_DEF@[358; 360)
274 PATH_TYPE@[358; 360)
275 PATH@[358; 360)
276 PATH_SEGMENT@[358; 360)
277 NAME_REF@[358; 360)
278 IDENT@[358; 360) "i8"
279 COMMA@[360; 361)
280 WHITESPACE@[361; 362)
281 POS_FIELD_DEF@[362; 364)
282 PATH_TYPE@[362; 364)
283 PATH@[362; 364)
284 PATH_SEGMENT@[362; 364)
285 NAME_REF@[362; 364)
286 IDENT@[362; 364) "i8"
287 R_PAREN@[364; 365)
288 WHITESPACE@[365; 366)
289 R_CURLY@[366; 367)
290 WHITESPACE@[367; 369)
291 FN_DEF@[369; 394)
292 FN_KW@[369; 371)
293 WHITESPACE@[371; 372)
294 NAME@[372; 375)
295 IDENT@[372; 375) "foo"
296 PARAM_LIST@[375; 391)
297 L_PAREN@[375; 376)
298 PARAM@[376; 390)
299 RANGE_PAT@[376; 386)
300 LITERAL_PAT@[376; 380)
301 MINUS@[376; 377)
302 LITERAL@[377; 380)
303 INT_NUMBER@[377; 380) "128"
304 DOTDOTEQ@[380; 383)
305 LITERAL_PAT@[383; 386)
306 LITERAL@[383; 386)
307 INT_NUMBER@[383; 386) "127"
308 COLON@[386; 387)
309 WHITESPACE@[387; 388)
310 PATH_TYPE@[388; 390)
311 PATH@[388; 390)
312 PATH_SEGMENT@[388; 390)
313 NAME_REF@[388; 390)
314 IDENT@[388; 390) "i8"
315 R_PAREN@[390; 391)
316 WHITESPACE@[391; 392)
317 BLOCK@[392; 394)
318 L_CURLY@[392; 393)
319 R_CURLY@[393; 394)
320 WHITESPACE@[394; 395)
diff --git a/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.rs b/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.rs
new file mode 100644
index 000000000..871720a49
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.rs
@@ -0,0 +1,17 @@
1// https://github.com/rust-analyzer/rust-analyzer/pull/983
2
3fn compound_assignment() {
4 let mut a = 0;
5 a += 1;
6 a -= 2;
7 a *= 3;
8 a %= 4;
9 a /= 5;
10 a |= 6;
11 a &= 7;
12 a ^= 8;
13 a <= 9;
14 a >= 10;
15 a >>= 11;
16 a <<= 12;
17}
diff --git a/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt b/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt
new file mode 100644
index 000000000..c5ff06823
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt
@@ -0,0 +1,200 @@
1SOURCE_FILE@[0; 257)
2 COMMENT@[0; 58)
3 WHITESPACE@[58; 60)
4 FN_DEF@[60; 256)
5 FN_KW@[60; 62)
6 WHITESPACE@[62; 63)
7 NAME@[63; 82)
8 IDENT@[63; 82) "compound_assignment"
9 PARAM_LIST@[82; 84)
10 L_PAREN@[82; 83)
11 R_PAREN@[83; 84)
12 WHITESPACE@[84; 85)
13 BLOCK@[85; 256)
14 L_CURLY@[85; 86)
15 WHITESPACE@[86; 91)
16 LET_STMT@[91; 105)
17 LET_KW@[91; 94)
18 WHITESPACE@[94; 95)
19 BIND_PAT@[95; 100)
20 MUT_KW@[95; 98)
21 WHITESPACE@[98; 99)
22 NAME@[99; 100)
23 IDENT@[99; 100) "a"
24 WHITESPACE@[100; 101)
25 EQ@[101; 102)
26 WHITESPACE@[102; 103)
27 LITERAL@[103; 104)
28 INT_NUMBER@[103; 104) "0"
29 SEMI@[104; 105)
30 WHITESPACE@[105; 110)
31 EXPR_STMT@[110; 117)
32 BIN_EXPR@[110; 116)
33 PATH_EXPR@[110; 111)
34 PATH@[110; 111)
35 PATH_SEGMENT@[110; 111)
36 NAME_REF@[110; 111)
37 IDENT@[110; 111) "a"
38 WHITESPACE@[111; 112)
39 PLUSEQ@[112; 114)
40 WHITESPACE@[114; 115)
41 LITERAL@[115; 116)
42 INT_NUMBER@[115; 116) "1"
43 SEMI@[116; 117)
44 WHITESPACE@[117; 122)
45 EXPR_STMT@[122; 129)
46 BIN_EXPR@[122; 128)
47 PATH_EXPR@[122; 123)
48 PATH@[122; 123)
49 PATH_SEGMENT@[122; 123)
50 NAME_REF@[122; 123)
51 IDENT@[122; 123) "a"
52 WHITESPACE@[123; 124)
53 MINUSEQ@[124; 126)
54 WHITESPACE@[126; 127)
55 LITERAL@[127; 128)
56 INT_NUMBER@[127; 128) "2"
57 SEMI@[128; 129)
58 WHITESPACE@[129; 134)
59 EXPR_STMT@[134; 141)
60 BIN_EXPR@[134; 140)
61 PATH_EXPR@[134; 135)
62 PATH@[134; 135)
63 PATH_SEGMENT@[134; 135)
64 NAME_REF@[134; 135)
65 IDENT@[134; 135) "a"
66 WHITESPACE@[135; 136)
67 STAREQ@[136; 138)
68 WHITESPACE@[138; 139)
69 LITERAL@[139; 140)
70 INT_NUMBER@[139; 140) "3"
71 SEMI@[140; 141)
72 WHITESPACE@[141; 146)
73 EXPR_STMT@[146; 153)
74 BIN_EXPR@[146; 152)
75 PATH_EXPR@[146; 147)
76 PATH@[146; 147)
77 PATH_SEGMENT@[146; 147)
78 NAME_REF@[146; 147)
79 IDENT@[146; 147) "a"
80 WHITESPACE@[147; 148)
81 PERCENTEQ@[148; 150)
82 WHITESPACE@[150; 151)
83 LITERAL@[151; 152)
84 INT_NUMBER@[151; 152) "4"
85 SEMI@[152; 153)
86 WHITESPACE@[153; 158)
87 EXPR_STMT@[158; 165)
88 BIN_EXPR@[158; 164)
89 PATH_EXPR@[158; 159)
90 PATH@[158; 159)
91 PATH_SEGMENT@[158; 159)
92 NAME_REF@[158; 159)
93 IDENT@[158; 159) "a"
94 WHITESPACE@[159; 160)
95 SLASHEQ@[160; 162)
96 WHITESPACE@[162; 163)
97 LITERAL@[163; 164)
98 INT_NUMBER@[163; 164) "5"
99 SEMI@[164; 165)
100 WHITESPACE@[165; 170)
101 EXPR_STMT@[170; 177)
102 BIN_EXPR@[170; 176)
103 PATH_EXPR@[170; 171)
104 PATH@[170; 171)
105 PATH_SEGMENT@[170; 171)
106 NAME_REF@[170; 171)
107 IDENT@[170; 171) "a"
108 WHITESPACE@[171; 172)
109 PIPEEQ@[172; 174)
110 WHITESPACE@[174; 175)
111 LITERAL@[175; 176)
112 INT_NUMBER@[175; 176) "6"
113 SEMI@[176; 177)
114 WHITESPACE@[177; 182)
115 EXPR_STMT@[182; 189)
116 BIN_EXPR@[182; 188)
117 PATH_EXPR@[182; 183)
118 PATH@[182; 183)
119 PATH_SEGMENT@[182; 183)
120 NAME_REF@[182; 183)
121 IDENT@[182; 183) "a"
122 WHITESPACE@[183; 184)
123 AMPEQ@[184; 186)
124 WHITESPACE@[186; 187)
125 LITERAL@[187; 188)
126 INT_NUMBER@[187; 188) "7"
127 SEMI@[188; 189)
128 WHITESPACE@[189; 194)
129 EXPR_STMT@[194; 201)
130 BIN_EXPR@[194; 200)
131 PATH_EXPR@[194; 195)
132 PATH@[194; 195)
133 PATH_SEGMENT@[194; 195)
134 NAME_REF@[194; 195)
135 IDENT@[194; 195) "a"
136 WHITESPACE@[195; 196)
137 CARETEQ@[196; 198)
138 WHITESPACE@[198; 199)
139 LITERAL@[199; 200)
140 INT_NUMBER@[199; 200) "8"
141 SEMI@[200; 201)
142 WHITESPACE@[201; 206)
143 EXPR_STMT@[206; 213)
144 BIN_EXPR@[206; 212)
145 PATH_EXPR@[206; 207)
146 PATH@[206; 207)
147 PATH_SEGMENT@[206; 207)
148 NAME_REF@[206; 207)
149 IDENT@[206; 207) "a"
150 WHITESPACE@[207; 208)
151 LTEQ@[208; 210)
152 WHITESPACE@[210; 211)
153 LITERAL@[211; 212)
154 INT_NUMBER@[211; 212) "9"
155 SEMI@[212; 213)
156 WHITESPACE@[213; 218)
157 EXPR_STMT@[218; 226)
158 BIN_EXPR@[218; 225)
159 PATH_EXPR@[218; 219)
160 PATH@[218; 219)
161 PATH_SEGMENT@[218; 219)
162 NAME_REF@[218; 219)
163 IDENT@[218; 219) "a"
164 WHITESPACE@[219; 220)
165 GTEQ@[220; 222)
166 WHITESPACE@[222; 223)
167 LITERAL@[223; 225)
168 INT_NUMBER@[223; 225) "10"
169 SEMI@[225; 226)
170 WHITESPACE@[226; 231)
171 EXPR_STMT@[231; 240)
172 BIN_EXPR@[231; 239)
173 PATH_EXPR@[231; 232)
174 PATH@[231; 232)
175 PATH_SEGMENT@[231; 232)
176 NAME_REF@[231; 232)
177 IDENT@[231; 232) "a"
178 WHITESPACE@[232; 233)
179 SHREQ@[233; 236)
180 WHITESPACE@[236; 237)
181 LITERAL@[237; 239)
182 INT_NUMBER@[237; 239) "11"
183 SEMI@[239; 240)
184 WHITESPACE@[240; 245)
185 EXPR_STMT@[245; 254)
186 BIN_EXPR@[245; 253)
187 PATH_EXPR@[245; 246)
188 PATH@[245; 246)
189 PATH_SEGMENT@[245; 246)
190 NAME_REF@[245; 246)
191 IDENT@[245; 246) "a"
192 WHITESPACE@[246; 247)
193 SHLEQ@[247; 250)
194 WHITESPACE@[250; 251)
195 LITERAL@[251; 253)
196 INT_NUMBER@[251; 253) "12"
197 SEMI@[253; 254)
198 WHITESPACE@[254; 255)
199 R_CURLY@[255; 256)
200 WHITESPACE@[256; 257)
diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/marks.rs
index 107432926..1c268b49c 100644
--- a/crates/test_utils/src/marks.rs
+++ b/crates/test_utils/src/marks.rs
@@ -30,13 +30,13 @@ use std::sync::atomic::{AtomicUsize, Ordering};
30 30
31#[macro_export] 31#[macro_export]
32macro_rules! tested_by { 32macro_rules! tested_by {
33 ($ident:ident) => { 33 ($ident:ident) => {{
34 #[cfg(test)] 34 #[cfg(test)]
35 { 35 {
36 // sic! use call-site crate 36 // sic! use call-site crate
37 crate::marks::$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst); 37 crate::marks::$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
38 } 38 }
39 }; 39 }};
40} 40}
41 41
42#[macro_export] 42#[macro_export]
diff --git a/editors/README.md b/editors/README.md
index 6e1189cad..ddc6ee048 100644
--- a/editors/README.md
+++ b/editors/README.md
@@ -1,5 +1,5 @@
1 1
2Preqrequisites: 2Prerequisites:
3 3
4In order to build the VS Code plugin, you need to have node.js and npm with 4In order to build the VS Code plugin, you need to have node.js and npm with
5a minimum version of 10 installed. Please refer to 5a minimum version of 10 installed. Please refer to
diff --git a/editors/code/package.json b/editors/code/package.json
index 0a1e84b4a..3834f2847 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -46,7 +46,8 @@
46 "activationEvents": [ 46 "activationEvents": [
47 "onLanguage:rust", 47 "onLanguage:rust",
48 "onCommand:rust-analyzer.analyzerStatus", 48 "onCommand:rust-analyzer.analyzerStatus",
49 "onCommand:rust-analyzer.collectGarbage" 49 "onCommand:rust-analyzer.collectGarbage",
50 "workspaceContains:**/Cargo.toml"
50 ], 51 ],
51 "main": "./out/extension", 52 "main": "./out/extension",
52 "contributes": { 53 "contributes": {
diff --git a/editors/emacs/ra-emacs-lsp.el b/editors/emacs/ra-emacs-lsp.el
index 780182f8a..955703edb 100644
--- a/editors/emacs/ra-emacs-lsp.el
+++ b/editors/emacs/ra-emacs-lsp.el
@@ -58,17 +58,16 @@
58 58
59(defun rust-analyzer--apply-source-change (data) 59(defun rust-analyzer--apply-source-change (data)
60 ;; TODO fileSystemEdits 60 ;; TODO fileSystemEdits
61 (--each (-> data (ht-get "workspaceEdit") (ht-get "documentChanges")) 61 (seq-doseq (it (-> data (ht-get "workspaceEdit") (ht-get "documentChanges")))
62 (rust-analyzer--apply-text-document-edit it)) 62 (rust-analyzer--apply-text-document-edit it))
63 (-when-let (cursor-position (ht-get data "cursorPosition")) 63 (-when-let (cursor-position (ht-get data "cursorPosition"))
64 (let ((filename (rust-analyzer--uri-filename (ht-get cursor-position "textDocument"))) 64 (let ((filename (rust-analyzer--uri-filename (ht-get cursor-position "textDocument")))
65 (position (ht-get cursor-position "position"))) 65 (position (ht-get cursor-position "position")))
66 (find-file filename) 66 (find-file filename)
67 (rust-analyzer--goto-lsp-loc position) 67 (rust-analyzer--goto-lsp-loc position))))
68 )))
69 68
70(defun rust-analyzer--apply-source-change-command (p) 69(defun rust-analyzer--apply-source-change-command (p)
71 (let ((data (-> p (ht-get "arguments") (car)))) 70 (let ((data (-> p (ht-get "arguments") (seq-first))))
72 (rust-analyzer--apply-source-change data))) 71 (rust-analyzer--apply-source-change data)))
73 72
74(lsp-register-client 73(lsp-register-client
@@ -126,7 +125,7 @@
126 "rust-analyzer/extendSelection" 125 "rust-analyzer/extendSelection"
127 (rust-analyzer--extend-selection-params))) 126 (rust-analyzer--extend-selection-params)))
128 (ht-get "selections") 127 (ht-get "selections")
129 (car))) 128 (seq-first)))
130 129
131(defun rust-analyzer--add-er-expansion () 130(defun rust-analyzer--add-er-expansion ()
132 (make-variable-buffer-local 'er/try-expand-list) 131 (make-variable-buffer-local 'er/try-expand-list)