aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock26
-rw-r--r--README.md49
-rw-r--r--crates/ra_assists/src/auto_import.rs96
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/remove_dbg.rs8
-rw-r--r--crates/ra_db/src/cancellation.rs2
-rw-r--r--crates/ra_db/src/input.rs44
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_hir/src/code_model_api.rs15
-rw-r--r--crates/ra_hir/src/expr/scope.rs2
-rw-r--r--crates/ra_hir/src/ids.rs16
-rw-r--r--crates/ra_hir/src/macros.rs2
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/mock.rs18
-rw-r--r--crates/ra_hir/src/nameres.rs129
-rw-r--r--crates/ra_hir/src/nameres/lower.rs18
-rw-r--r--crates/ra_hir/src/nameres/tests.rs112
-rw-r--r--crates/ra_hir/src/path.rs2
-rw-r--r--crates/ra_hir/src/resolve.rs24
-rw-r--r--crates/ra_hir/src/ty.rs4
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_nested_generics_crash.snap12
-rw-r--r--crates/ra_hir/src/ty/tests.rs19
-rw-r--r--crates/ra_ide_api/src/completion.rs5
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs20
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs21
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap54
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap26
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs8
-rw-r--r--crates/ra_ide_api/src/hover.rs4
-rw-r--r--crates/ra_ide_api/src/impls.rs4
-rw-r--r--crates/ra_ide_api/src/lib.rs13
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs8
-rw-r--r--crates/ra_ide_api/src/navigation_target.rs11
-rw-r--r--crates/ra_ide_api/src/references.rs6
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs64
-rw-r--r--crates/ra_ide_api/tests/test/main.rs54
-rw-r--r--crates/ra_ide_api_light/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs2
-rw-r--r--crates/ra_mbe/src/lib.rs6
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs2
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs8
-rw-r--r--crates/ra_project_model/src/lib.rs8
-rw-r--r--crates/ra_syntax/src/ast.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs3
-rw-r--r--crates/ra_syntax/src/ast/generated.rs.tera2
-rw-r--r--crates/ra_syntax/src/grammar.ron3
-rw-r--r--crates/ra_syntax/src/lib.rs8
-rw-r--r--crates/ra_syntax/src/parser_impl.rs2
-rw-r--r--crates/ra_syntax/src/parser_impl/event.rs2
-rw-r--r--crates/ra_syntax/src/reparsing.rs4
-rw-r--r--crates/ra_syntax/src/syntax_node.rs (renamed from crates/ra_syntax/src/yellow.rs)0
-rw-r--r--crates/ra_syntax/src/syntax_node/builder.rs (renamed from crates/ra_syntax/src/yellow/builder.rs)2
-rw-r--r--crates/ra_syntax/src/syntax_node/syntax_error.rs (renamed from crates/ra_syntax/src/yellow/syntax_error.rs)0
-rw-r--r--crates/ra_syntax/src/syntax_node/syntax_text.rs (renamed from crates/ra_syntax/src/yellow/syntax_text.rs)0
-rw-r--r--crates/ra_syntax/src/validation.rs2
-rw-r--r--crates/ra_syntax/src/validation/block.rs2
-rw-r--r--crates/ra_syntax/src/validation/byte.rs2
-rw-r--r--crates/ra_syntax/src/validation/byte_string.rs2
-rw-r--r--crates/ra_syntax/src/validation/char.rs2
-rw-r--r--crates/ra_syntax/src/validation/string.rs2
-rw-r--r--crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs4
-rw-r--r--crates/ra_tt/src/lib.rs10
-rw-r--r--crates/ra_vfs/src/io.rs4
-rw-r--r--crates/ra_vfs/src/lib.rs14
-rw-r--r--crates/test_utils/src/lib.rs4
-rw-r--r--crates/test_utils/src/marks.rs8
-rw-r--r--crates/thread_worker/src/lib.rs2
-rw-r--r--editors/README.md3
-rw-r--r--editors/code/package.json2
70 files changed, 781 insertions, 241 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ff24b9dc8..65ffff90a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5,7 +5,7 @@ name = "aho-corasick"
5version = "0.6.9" 5version = "0.6.9"
6source = "registry+https://github.com/rust-lang/crates.io-index" 6source = "registry+https://github.com/rust-lang/crates.io-index"
7dependencies = [ 7dependencies = [
8 "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 8 "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
9] 9]
10 10
11[[package]] 11[[package]]
@@ -667,12 +667,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
667 667
668[[package]] 668[[package]]
669name = "memchr" 669name = "memchr"
670version = "2.1.3" 670version = "2.2.0"
671source = "registry+https://github.com/rust-lang/crates.io-index" 671source = "registry+https://github.com/rust-lang/crates.io-index"
672dependencies = [
673 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
674 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
675]
676 672
677[[package]] 673[[package]]
678name = "memmap" 674name = "memmap"
@@ -786,7 +782,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
786 782
787[[package]] 783[[package]]
788name = "num_cpus" 784name = "num_cpus"
789version = "1.9.0" 785version = "1.10.0"
790source = "registry+https://github.com/rust-lang/crates.io-index" 786source = "registry+https://github.com/rust-lang/crates.io-index"
791dependencies = [ 787dependencies = [
792 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", 788 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1042,7 +1038,7 @@ dependencies = [
1042 "ra_syntax 0.1.0", 1038 "ra_syntax 0.1.0",
1043 "ra_text_edit 0.1.0", 1039 "ra_text_edit 0.1.0",
1044 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1040 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1045 "superslice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1041 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1046 "test_utils 0.1.0", 1042 "test_utils 0.1.0",
1047] 1043]
1048 1044
@@ -1266,7 +1262,7 @@ dependencies = [
1266 "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1262 "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1267 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1263 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1268 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", 1264 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
1269 "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1265 "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
1270] 1266]
1271 1267
1272[[package]] 1268[[package]]
@@ -1296,7 +1292,7 @@ version = "1.1.0"
1296source = "registry+https://github.com/rust-lang/crates.io-index" 1292source = "registry+https://github.com/rust-lang/crates.io-index"
1297dependencies = [ 1293dependencies = [
1298 "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 1294 "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
1299 "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 1295 "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1300 "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1296 "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
1301 "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 1297 "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
1302 "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1298 "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1530,7 +1526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1530 1526
1531[[package]] 1527[[package]]
1532name = "superslice" 1528name = "superslice"
1533version = "0.1.0" 1529version = "1.0.0"
1534source = "registry+https://github.com/rust-lang/crates.io-index" 1530source = "registry+https://github.com/rust-lang/crates.io-index"
1535 1531
1536[[package]] 1532[[package]]
@@ -1664,7 +1660,7 @@ name = "threadpool"
1664version = "1.7.1" 1660version = "1.7.1"
1665source = "registry+https://github.com/rust-lang/crates.io-index" 1661source = "registry+https://github.com/rust-lang/crates.io-index"
1666dependencies = [ 1662dependencies = [
1667 "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1663 "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
1668] 1664]
1669 1665
1670[[package]] 1666[[package]]
@@ -1997,7 +1993,7 @@ dependencies = [
1997"checksum lsp-types 0.55.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9092adbc87fcf30f9d371ecea86dafee55e56f282ee19ca282384e3a04926ba9" 1993"checksum lsp-types 0.55.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9092adbc87fcf30f9d371ecea86dafee55e56f282ee19ca282384e3a04926ba9"
1998"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" 1994"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
1999"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1995"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
2000"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8" 1996"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
2001"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" 1997"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
2002"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 1998"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
2003"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" 1999"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
@@ -2009,7 +2005,7 @@ dependencies = [
2009"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d" 2005"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d"
2010"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" 2006"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
2011"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 2007"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
2012"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" 2008"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
2013"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" 2009"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
2014"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" 2010"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
2015"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" 2011"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
@@ -2067,7 +2063,7 @@ dependencies = [
2067"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" 2063"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
2068"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 2064"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
2069"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 2065"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
2070"checksum superslice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50b13d42370e0f5fc62eafdd5c2d20065eaf5458dab215ff3e20e63eea96b30" 2066"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
2071"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" 2067"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
2072"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" 2068"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
2073"checksum tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "37daa55a7240c4931c84559f03b3cad7d19535840d1c4a0cc4e9b2fb0dcf70ff" 2069"checksum tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "37daa55a7240c4931c84559f03b3cad7d19535840d1c4a0cc4e9b2fb0dcf70ff"
diff --git a/README.md b/README.md
index cffc00953..15da30f2d 100644
--- a/README.md
+++ b/README.md
@@ -3,12 +3,10 @@
3[![Build Status](https://travis-ci.org/rust-analyzer/rust-analyzer.svg?branch=master)](https://travis-ci.org/rust-analyzer/rust-analyzer) 3[![Build Status](https://travis-ci.org/rust-analyzer/rust-analyzer.svg?branch=master)](https://travis-ci.org/rust-analyzer/rust-analyzer)
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, which aims to lay a foundation for excellent IDE support. 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:
7 8
8It doesn't implement much of compiler functionality yet, but the white-space 9https://github.com/rust-analyzer/WG-rls2.0
9preserving Rust parser works, and there are significant chunks of overall
10architecture (indexing, on-demand & lazy computation, snapshotable world view)
11in place. Some basic IDE functionality is provided via a language server.
12 10
13Work on the Rust Analyzer is sponsored by 11Work on the Rust Analyzer is sponsored by
14 12
@@ -41,37 +39,15 @@ features (some of which are VS Code specific).
41 39
42See [these instructions](./DEBUGGING.md) on how to debug the vscode extension and the lsp server. 40See [these instructions](./DEBUGGING.md) on how to debug the vscode extension and the lsp server.
43 41
44## Current Status and Plans 42## Getting in touch
45
46Rust analyzer aims to fill the same niche as the official [Rust Language
47Server](https://github.com/rust-lang-nursery/rls), but uses a significantly
48different architecture. More details can be found [in this
49thread](https://internals.rust-lang.org/t/2019-strategy-for-rustc-and-the-rls/8361),
50but the core issue is that RLS works in the "wait until user stops typing, run
51the build process, save the results of the analysis" mode, which arguably is the
52wrong foundation for IDE.
53
54Rust Analyzer is an experimental project at the moment, there's exactly zero
55guarantees that it becomes production-ready one day.
56 43
57The near/mid term plan is to work independently of the main rustc compiler and 44We are on the rust-lang Zulip!
58implement at least simplistic versions of name resolution, macro expansion and
59type inference. The purpose is two fold:
60 45
61- to quickly bootstrap usable and useful language server: solution that covers 46https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0
62 80% of Rust code will be useful for IDEs, and will be vastly simpler than 100%
63 solution.
64 47
65- to understand how the consumer-side of compiler API should look like 48## Contributing
66 (especially it's on-demand aspects). If you have `get_expression_type`
67 function, you can write a ton of purely-IDE features on top of it, even if the
68 function is only partially correct. Pluging in the precise function afterwards
69 should just make IDE features more reliable.
70 49
71The long term plan is to merge with the mainline rustc compiler, probably around 50See [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHITECTURE.md](./ARCHITECTURE.md)
72the HIR boundary? That is, use rust analyzer for parsing, macro expansion and
73related bits of name resolution, but leave the rest (including type inference
74and trait selection) to the existing rustc.
75 51
76## Supported LSP features 52## Supported LSP features
77 53
@@ -146,15 +122,6 @@ and trait selection) to the existing rustc.
146- [x] [textDocument/prepareRename](https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareRename) 122- [x] [textDocument/prepareRename](https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareRename)
147- [x] [textDocument/foldingRange](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange) 123- [x] [textDocument/foldingRange](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange)
148 124
149## Getting in touch
150
151We have a Discord server dedicated to compilers and language servers
152implemented in Rust: [https://discord.gg/sx3RQZB](https://discord.gg/sx3RQZB).
153
154## Contributing
155
156See [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHITECTURE.md](./ARCHITECTURE.md)
157
158## License 125## License
159 126
160Rust analyzer is primarily distributed under the terms of both the MIT 127Rust analyzer is primarily distributed under the terms of both the MIT
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index b251c9369..52c2a0b2b 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -1,6 +1,6 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 ast, AstNode, SyntaxNode, Direction, TextRange, 3 ast::{ self, NameOwner }, AstNode, SyntaxNode, Direction, TextRange,
4 SyntaxKind::{ PATH, PATH_SEGMENT, COLONCOLON, COMMA } 4 SyntaxKind::{ PATH, PATH_SEGMENT, COLONCOLON, COMMA }
5}; 5};
6use crate::assist_ctx::{AssistCtx, Assist, AssistBuilder}; 6use crate::assist_ctx::{AssistCtx, Assist, AssistBuilder};
@@ -345,9 +345,9 @@ fn best_action_for_target<'b, 'a: 'b>(
345 match best_action { 345 match best_action {
346 Some(action) => return action, 346 Some(action) => return action,
347 None => { 347 None => {
348 // We have no action we no use item was found in container so we find 348 // We have no action and no UseItem was found in container so we find
349 // another item and we use it as anchor. 349 // another item and we use it as anchor.
350 // If there are not items, we choose the target path itself as anchor. 350 // If there are no items, we choose the target path itself as anchor.
351 let anchor = container 351 let anchor = container
352 .children() 352 .children()
353 .find_map(ast::ModuleItem::cast) 353 .find_map(ast::ModuleItem::cast)
@@ -480,6 +480,24 @@ fn make_assist_add_nested_import(
480 } 480 }
481} 481}
482 482
483fn apply_auto_import<'a>(
484 container: &SyntaxNode,
485 path: &ast::Path,
486 target: &[&'a ast::PathSegment],
487 edit: &mut AssistBuilder,
488) {
489 let action = best_action_for_target(container, path, target);
490 make_assist(&action, target, edit);
491 if let (Some(first), Some(last)) = (target.first(), target.last()) {
492 // Here we are assuming the assist will provide a correct use statement
493 // so we can delete the path qualifier
494 edit.delete(TextRange::from_to(
495 first.syntax().range().start(),
496 last.syntax().range().start(),
497 ));
498 }
499}
500
483pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 501pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
484 let node = ctx.covering_node(); 502 let node = ctx.covering_node();
485 let current_file = node.ancestors().find_map(ast::SourceFile::cast)?; 503 let current_file = node.ancestors().find_map(ast::SourceFile::cast)?;
@@ -495,18 +513,20 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
495 return None; 513 return None;
496 } 514 }
497 515
498 ctx.add_action(format!("import {} in the current file", fmt_segments(&segments)), |edit| { 516 if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) {
499 let action = best_action_for_target(current_file.syntax(), path, &segments); 517 if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) {
500 make_assist(&action, segments.as_slice(), edit); 518 ctx.add_action(
501 if let Some(last_segment) = path.segment() { 519 format!("import {} in mod {}", fmt_segments(&segments), name.text()),
502 // Here we are assuming the assist will provide a correct use statement 520 |edit| {
503 // so we can delete the path qualifier 521 apply_auto_import(item_list.syntax(), path, &segments, edit);
504 edit.delete(TextRange::from_to( 522 },
505 path.syntax().range().start(), 523 );
506 last_segment.syntax().range().start(),
507 ));
508 } 524 }
509 }); 525 } else {
526 ctx.add_action(format!("import {} in the current file", fmt_segments(&segments)), |edit| {
527 apply_auto_import(current_file.syntax(), path, &segments, edit);
528 });
529 }
510 530
511 ctx.build() 531 ctx.build()
512} 532}
@@ -532,6 +552,21 @@ Debug<|>
532 } 552 }
533 553
534 #[test] 554 #[test]
555 fn test_auto_import_file_add_use_no_anchor_2seg() {
556 check_assist(
557 auto_import,
558 "
559std::fmt<|>::Debug
560 ",
561 "
562use std::fmt;
563
564fmt<|>::Debug
565 ",
566 );
567 }
568
569 #[test]
535 fn test_auto_import_file_add_use() { 570 fn test_auto_import_file_add_use() {
536 check_assist( 571 check_assist(
537 auto_import, 572 auto_import,
@@ -728,4 +763,37 @@ impl foo<|> for Foo {
728", 763",
729 ); 764 );
730 } 765 }
766
767 #[test]
768 fn test_auto_import_not_applicable_in_use() {
769 check_assist_not_applicable(
770 auto_import,
771 "
772use std::fmt<|>;
773",
774 );
775 }
776
777 #[test]
778 fn test_auto_import_file_add_use_no_anchor_in_mod_mod() {
779 check_assist(
780 auto_import,
781 "
782mod foo {
783 mod bar {
784 std::fmt::Debug<|>
785 }
786}
787 ",
788 "
789mod foo {
790 mod bar {
791 use std::fmt::Debug;
792
793 Debug<|>
794 }
795}
796 ",
797 );
798 }
731} 799}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index c607a5142..7bd9b5ae6 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -1,4 +1,4 @@
1//! `ra_assits` crate provides a bunch of code assists, aslo known as code 1//! `ra_assits` crate provides a bunch of code assists, also known as code
2//! actions (in LSP) or intentions (in IntelliJ). 2//! actions (in LSP) or intentions (in IntelliJ).
3//! 3//!
4//! An assist is a micro-refactoring, which is automatically activated in 4//! An assist is a micro-refactoring, which is automatically activated in
diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs
index db260c6ca..2bed270a1 100644
--- a/crates/ra_assists/src/remove_dbg.rs
+++ b/crates/ra_assists/src/remove_dbg.rs
@@ -17,9 +17,9 @@ pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
17 17
18 let macro_range = macro_call.syntax().range(); 18 let macro_range = macro_call.syntax().range();
19 19
20 // If the cursor is inside the macrocall, we'll try to maintain 20 // If the cursor is inside the macro call, we'll try to maintain the cursor
21 // the cursor position by subtracting the length of dbg!( from the start 21 // position by subtracting the length of dbg!( from the start of the file
22 // of the filerange, otherwise we'll default to using the start of the macrocall 22 // range, otherwise we'll default to using the start of the macro call
23 let cursor_pos = { 23 let cursor_pos = {
24 let file_range = ctx.frange.range; 24 let file_range = ctx.frange.range;
25 25
@@ -61,7 +61,7 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b
61 let path = macro_call.path()?; 61 let path = macro_call.path()?;
62 let name_ref = path.segment()?.name_ref()?; 62 let name_ref = path.segment()?.name_ref()?;
63 63
64 // Make sure it is actually a dbg-macrocall, dbg followed by ! 64 // Make sure it is actually a dbg-macro call, dbg followed by !
65 let excl = path.syntax().next_sibling()?; 65 let excl = path.syntax().next_sibling()?;
66 66
67 if name_ref.text() != macro_name || excl.kind() != EXCL { 67 if name_ref.text() != macro_name || excl.kind() != EXCL {
diff --git a/crates/ra_db/src/cancellation.rs b/crates/ra_db/src/cancellation.rs
index 439080075..7420a1976 100644
--- a/crates/ra_db/src/cancellation.rs
+++ b/crates/ra_db/src/cancellation.rs
@@ -15,7 +15,7 @@
15//! any background processing (this bit is handled by salsa, see the 15//! any background processing (this bit is handled by salsa, see the
16//! `BaseDatabase::check_canceled` method). 16//! `BaseDatabase::check_canceled` method).
17 17
18/// An "error" signifing that the operation was canceled. 18/// An "error" signifying that the operation was canceled.
19#[derive(Clone, PartialEq, Eq, Hash)] 19#[derive(Clone, PartialEq, Eq, Hash)]
20pub struct Canceled { 20pub struct Canceled {
21 _private: (), 21 _private: (),
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 8decc65c5..e45a510b3 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -56,15 +56,31 @@ pub struct CyclicDependencies;
56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
57pub struct CrateId(pub u32); 57pub struct CrateId(pub u32);
58 58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60pub enum Edition {
61 Edition2018,
62 Edition2015,
63}
64
65impl Edition {
66 pub fn from_string(s: &str) -> Edition {
67 match s {
68 "2015" => Edition::Edition2015,
69 "2018" | _ => Edition::Edition2018,
70 }
71 }
72}
73
59#[derive(Debug, Clone, PartialEq, Eq)] 74#[derive(Debug, Clone, PartialEq, Eq)]
60struct CrateData { 75struct CrateData {
61 file_id: FileId, 76 file_id: FileId,
77 edition: Edition,
62 dependencies: Vec<Dependency>, 78 dependencies: Vec<Dependency>,
63} 79}
64 80
65impl CrateData { 81impl CrateData {
66 fn new(file_id: FileId) -> CrateData { 82 fn new(file_id: FileId, edition: Edition) -> CrateData {
67 CrateData { file_id, dependencies: Vec::new() } 83 CrateData { file_id, edition, dependencies: Vec::new() }
68 } 84 }
69 85
70 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 86 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
@@ -85,9 +101,9 @@ impl Dependency {
85} 101}
86 102
87impl CrateGraph { 103impl CrateGraph {
88 pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { 104 pub fn add_crate_root(&mut self, file_id: FileId, edition: Edition) -> CrateId {
89 let crate_id = CrateId(self.arena.len() as u32); 105 let crate_id = CrateId(self.arena.len() as u32);
90 let prev = self.arena.insert(crate_id, CrateData::new(file_id)); 106 let prev = self.arena.insert(crate_id, CrateData::new(file_id, edition));
91 assert!(prev.is_none()); 107 assert!(prev.is_none());
92 crate_id 108 crate_id
93 } 109 }
@@ -112,6 +128,10 @@ impl CrateGraph {
112 self.arena[&crate_id].file_id 128 self.arena[&crate_id].file_id
113 } 129 }
114 130
131 pub fn edition(&self, crate_id: CrateId) -> Edition {
132 self.arena[&crate_id].edition
133 }
134
115 // TODO: this only finds one crate with the given root; we could have multiple 135 // TODO: this only finds one crate with the given root; we could have multiple
116 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 136 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
117 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; 137 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;
@@ -159,14 +179,14 @@ impl CrateGraph {
159 179
160#[cfg(test)] 180#[cfg(test)]
161mod tests { 181mod tests {
162 use super::{CrateGraph, FileId, SmolStr}; 182 use super::{CrateGraph, FileId, SmolStr, Edition::Edition2018};
163 183
164 #[test] 184 #[test]
165 fn it_should_painc_because_of_cycle_dependencies() { 185 fn it_should_panic_because_of_cycle_dependencies() {
166 let mut graph = CrateGraph::default(); 186 let mut graph = CrateGraph::default();
167 let crate1 = graph.add_crate_root(FileId(1u32)); 187 let crate1 = graph.add_crate_root(FileId(1u32), Edition2018);
168 let crate2 = graph.add_crate_root(FileId(2u32)); 188 let crate2 = graph.add_crate_root(FileId(2u32), Edition2018);
169 let crate3 = graph.add_crate_root(FileId(3u32)); 189 let crate3 = graph.add_crate_root(FileId(3u32), Edition2018);
170 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); 190 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
171 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); 191 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
172 assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err()); 192 assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err());
@@ -175,9 +195,9 @@ mod tests {
175 #[test] 195 #[test]
176 fn it_works() { 196 fn it_works() {
177 let mut graph = CrateGraph::default(); 197 let mut graph = CrateGraph::default();
178 let crate1 = graph.add_crate_root(FileId(1u32)); 198 let crate1 = graph.add_crate_root(FileId(1u32), Edition2018);
179 let crate2 = graph.add_crate_root(FileId(2u32)); 199 let crate2 = graph.add_crate_root(FileId(2u32), Edition2018);
180 let crate3 = graph.add_crate_root(FileId(3u32)); 200 let crate3 = graph.add_crate_root(FileId(3u32), Edition2018);
181 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); 201 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
182 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); 202 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
183 } 203 }
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 31442713d..e006c6d27 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -14,7 +14,7 @@ pub use ::salsa as salsa;
14pub use crate::{ 14pub use crate::{
15 cancellation::Canceled, 15 cancellation::Canceled,
16 input::{ 16 input::{
17 FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, 17 FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, Edition,
18 }, 18 },
19 loc2id::LocationIntener, 19 loc2id::LocationIntener,
20}; 20};
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 94a08aa63..fb7ad0867 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use ra_db::{CrateId, FileId, SourceRootId}; 4use ra_db::{CrateId, FileId, SourceRootId, Edition};
5use ra_syntax::{ast::self, TreeArc, SyntaxNode}; 5use ra_syntax::{ast::self, TreeArc, SyntaxNode};
6 6
7use crate::{ 7use crate::{
@@ -38,13 +38,20 @@ impl Crate {
38 pub fn crate_id(&self) -> CrateId { 38 pub fn crate_id(&self) -> CrateId {
39 self.crate_id 39 self.crate_id
40 } 40 }
41
41 pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> { 42 pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> {
42 self.dependencies_impl(db) 43 self.dependencies_impl(db)
43 } 44 }
45
44 pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 46 pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
45 self.root_module_impl(db) 47 self.root_module_impl(db)
46 } 48 }
47 49
50 pub fn edition(&self, db: &impl PersistentHirDatabase) -> Edition {
51 let crate_graph = db.crate_graph();
52 crate_graph.edition(self.crate_id)
53 }
54
48 // TODO: should this be in source_binder? 55 // TODO: should this be in source_binder?
49 pub fn source_root_crates( 56 pub fn source_root_crates(
50 db: &impl PersistentHirDatabase, 57 db: &impl PersistentHirDatabase,
@@ -134,7 +141,7 @@ impl Module {
134 141
135 /// Topmost parent of this module. Every module has a `crate_root`, but some 142 /// Topmost parent of this module. Every module has a `crate_root`, but some
136 /// might be missing `krate`. This can happen if a module's file is not included 143 /// might be missing `krate`. This can happen if a module's file is not included
137 /// in the module tree of any target in Cargo.toml. 144 /// in the module tree of any target in `Cargo.toml`.
138 pub fn crate_root(&self, db: &impl PersistentHirDatabase) -> Module { 145 pub fn crate_root(&self, db: &impl PersistentHirDatabase) -> Module {
139 self.crate_root_impl(db) 146 self.crate_root_impl(db)
140 } 147 }
@@ -351,7 +358,7 @@ impl Enum {
351 db.type_for_def((*self).into()) 358 db.type_for_def((*self).into())
352 } 359 }
353 360
354 // TODO move to a more general type 361 // TODO: move to a more general type
355 /// Builds a resolver for type references inside this struct. 362 /// Builds a resolver for type references inside this struct.
356 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 363 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
357 // take the outer scope... 364 // take the outer scope...
@@ -495,7 +502,7 @@ impl Function {
495 db.generic_params((*self).into()) 502 db.generic_params((*self).into())
496 } 503 }
497 504
498 // TODO move to a more general type for 'body-having' items 505 // TODO: move to a more general type for 'body-having' items
499 /// Builds a resolver for code inside this item. 506 /// Builds a resolver for code inside this item.
500 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 507 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
501 // take the outer scope... 508 // take the outer scope...
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index 44d5c2429..bb8d50db8 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -84,7 +84,7 @@ impl ExprScopes {
84 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { 84 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
85 match &body[pat] { 85 match &body[pat] {
86 Pat::Bind { name, .. } => { 86 Pat::Bind { name, .. } => {
87 // bind can have a subpattern, but it's actually not allowed 87 // bind can have a sub pattern, but it's actually not allowed
88 // to bind to things in there 88 // to bind to things in there
89 let entry = ScopeEntry { name: name.clone(), pat }; 89 let entry = ScopeEntry { name: name.clone(), pat };
90 self.scopes[scope].entries.push(entry) 90 self.scopes[scope].entries.push(entry)
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index d3fa7d266..8d81d5ebf 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -46,24 +46,24 @@ impl HirInterner {
46/// This module defines a bunch of ids we are using. The most important ones are 46/// This module defines a bunch of ids we are using. The most important ones are
47/// probably `HirFileId` and `DefId`. 47/// probably `HirFileId` and `DefId`.
48 48
49/// Input to the analyzer is a set of files, where each file is indentified by 49/// Input to the analyzer is a set of files, where each file is identified by
50/// `FileId` and contains source code. However, another source of source code in 50/// `FileId` and contains source code. However, another source of source code in
51/// Rust are macros: each macro can be thought of as producing a "temporary 51/// Rust are macros: each macro can be thought of as producing a "temporary
52/// file". To assign an id to such a file, we use the id of the macro call that 52/// file". To assign an id to such a file, we use the id of the macro call that
53/// produced the file. So, a `HirFileId` is either a `FileId` (source code 53/// produced the file. So, a `HirFileId` is either a `FileId` (source code
54/// written by user), or a `MacroCallId` (source code produced by macro). 54/// written by user), or a `MacroCallId` (source code produced by macro).
55/// 55///
56/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file containin 56/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
57/// the call plus the offset of the macro call in the file. Note that this is a 57/// containing the call plus the offset of the macro call in the file. Note that
58/// recursive definition! However, the size_of of `HirFileId` is finite 58/// this is a recursive definition! However, the size_of of `HirFileId` is
59/// (because everything bottoms out at the real `FileId`) and small 59/// finite (because everything bottoms out at the real `FileId`) and small
60/// (`MacroCallId` uses the location interner). 60/// (`MacroCallId` uses the location interner).
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62pub struct HirFileId(HirFileIdRepr); 62pub struct HirFileId(HirFileIdRepr);
63 63
64impl HirFileId { 64impl HirFileId {
65 /// For macro-expansion files, returns the file original source file the 65 /// For macro-expansion files, returns the file original source file the
66 /// expansionoriginated from. 66 /// expansion originated from.
67 pub fn original_file(self, db: &impl PersistentHirDatabase) -> FileId { 67 pub fn original_file(self, db: &impl PersistentHirDatabase) -> FileId {
68 match self.0 { 68 match self.0 {
69 HirFileIdRepr::File(file_id) => file_id, 69 HirFileIdRepr::File(file_id) => file_id,
@@ -324,9 +324,9 @@ impl SourceFileItems {
324 324
325 fn init(&mut self, source_file: &SourceFile) { 325 fn init(&mut self, source_file: &SourceFile) {
326 // By walking the tree in bread-first order we make sure that parents 326 // By walking the tree in bread-first order we make sure that parents
327 // get lower ids then children. That is, addding a new child does not 327 // get lower ids then children. That is, adding a new child does not
328 // change parent's id. This means that, say, adding a new function to a 328 // change parent's id. This means that, say, adding a new function to a
329 // trait does not chage ids of top-level items, which helps caching. 329 // trait does not change ids of top-level items, which helps caching.
330 bfs(source_file.syntax(), |it| { 330 bfs(source_file.syntax(), |it| {
331 if let Some(module_item) = ast::ModuleItem::cast(it) { 331 if let Some(module_item) = ast::ModuleItem::cast(it) {
332 self.alloc(module_item.syntax()); 332 self.alloc(module_item.syntax());
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs
index dd477e9f9..45128c7df 100644
--- a/crates/ra_hir/src/macros.rs
+++ b/crates/ra_hir/src/macros.rs
@@ -67,7 +67,7 @@ impl MacroDef {
67 } 67 }
68} 68}
69 69
70#[derive(Debug, Clone, PartialEq, Eq, Hash)] 70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct MacroInput { 71pub struct MacroInput {
72 // Should be token trees 72 // Should be token trees
73 pub text: String, 73 pub text: String,
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 50d4e824c..16852a6a1 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -6,4 +6,5 @@ test_utils::marks!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 glob_enum 7 glob_enum
8 glob_across_crates 8 glob_across_crates
9 std_prelude
9); 10);
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 5ca870867..f1cad77c5 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -3,6 +3,7 @@ use std::{sync::Arc, panic};
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use ra_db::{ 4use ra_db::{
5 FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa, 5 FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa,
6 Edition,
6}; 7};
7use relative_path::RelativePathBuf; 8use relative_path::RelativePathBuf;
8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 9use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
@@ -58,12 +59,12 @@ impl MockDatabase {
58 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { 59 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) {
59 let mut ids = FxHashMap::default(); 60 let mut ids = FxHashMap::default();
60 let mut crate_graph = CrateGraph::default(); 61 let mut crate_graph = CrateGraph::default();
61 for (crate_name, (crate_root, _)) in graph.0.iter() { 62 for (crate_name, (crate_root, edition, _)) in graph.0.iter() {
62 let crate_root = self.file_id_of(&crate_root); 63 let crate_root = self.file_id_of(&crate_root);
63 let crate_id = crate_graph.add_crate_root(crate_root); 64 let crate_id = crate_graph.add_crate_root(crate_root, *edition);
64 ids.insert(crate_name, crate_id); 65 ids.insert(crate_name, crate_id);
65 } 66 }
66 for (crate_name, (_, deps)) in graph.0.iter() { 67 for (crate_name, (_, _, deps)) in graph.0.iter() {
67 let from = ids[crate_name]; 68 let from = ids[crate_name];
68 for dep in deps { 69 for dep in deps {
69 let to = ids[dep]; 70 let to = ids[dep];
@@ -144,7 +145,7 @@ impl MockDatabase {
144 145
145 if is_crate_root { 146 if is_crate_root {
146 let mut crate_graph = CrateGraph::default(); 147 let mut crate_graph = CrateGraph::default();
147 crate_graph.add_crate_root(file_id); 148 crate_graph.add_crate_root(file_id, Edition::Edition2018);
148 self.set_crate_graph(Arc::new(crate_graph)); 149 self.set_crate_graph(Arc::new(crate_graph));
149 } 150 }
150 file_id 151 file_id
@@ -232,16 +233,19 @@ impl MockDatabase {
232} 233}
233 234
234#[derive(Default)] 235#[derive(Default)]
235pub struct CrateGraphFixture(pub FxHashMap<String, (String, Vec<String>)>); 236pub struct CrateGraphFixture(pub FxHashMap<String, (String, Edition, Vec<String>)>);
236 237
237#[macro_export] 238#[macro_export]
238macro_rules! crate_graph { 239macro_rules! crate_graph {
239 ($($crate_name:literal: ($crate_path:literal, [$($dep:literal),*]),)*) => {{ 240 ($($crate_name:literal: ($crate_path:literal, $($edition:literal,)? [$($dep:literal),*]),)*) => {{
240 let mut res = $crate::mock::CrateGraphFixture::default(); 241 let mut res = $crate::mock::CrateGraphFixture::default();
241 $( 242 $(
243 #[allow(unused_mut, unused_assignments)]
244 let mut edition = ra_db::Edition::Edition2018;
245 $(edition = ra_db::Edition::from_string($edition);)?
242 res.0.insert( 246 res.0.insert(
243 $crate_name.to_string(), 247 $crate_name.to_string(),
244 ($crate_path.to_string(), vec![$($dep.to_string()),*]) 248 ($crate_path.to_string(), edition, vec![$($dep.to_string()),*])
245 ); 249 );
246 )* 250 )*
247 res 251 res
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 261ebdf97..e35b4b129 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -18,9 +18,11 @@ pub(crate) mod lower;
18 18
19use std::{time, sync::Arc}; 19use std::{time, sync::Arc};
20 20
21use rustc_hash::{FxHashMap, FxHashSet};
22
21use ra_arena::map::ArenaMap; 23use ra_arena::map::ArenaMap;
24use ra_db::Edition;
22use test_utils::tested_by; 25use test_utils::tested_by;
23use rustc_hash::{FxHashMap, FxHashSet};
24 26
25use crate::{ 27use crate::{
26 Module, ModuleDef, 28 Module, ModuleDef,
@@ -32,8 +34,13 @@ use crate::{
32 34
33/// `ItemMap` is the result of module name resolution. It contains, for each 35/// `ItemMap` is the result of module name resolution. It contains, for each
34/// module, the set of visible items. 36/// module, the set of visible items.
35#[derive(Default, Debug, PartialEq, Eq)] 37#[derive(Debug, PartialEq, Eq)]
36pub struct ItemMap { 38pub struct ItemMap {
39 edition: Edition,
40 /// 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
42 /// a dependency (`std` or `core`).
43 pub(crate) prelude: Option<Module>,
37 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>, 44 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>,
38 per_module: ArenaMap<ModuleId, ModuleScope>, 45 per_module: ArenaMap<ModuleId, ModuleScope>,
39} 46}
@@ -176,7 +183,12 @@ where
176 module_tree, 183 module_tree,
177 processed_imports: FxHashSet::default(), 184 processed_imports: FxHashSet::default(),
178 glob_imports: FxHashMap::default(), 185 glob_imports: FxHashMap::default(),
179 result: ItemMap::default(), 186 result: ItemMap {
187 edition: krate.edition(db),
188 prelude: None,
189 extern_prelude: FxHashMap::default(),
190 per_module: ArenaMap::default(),
191 },
180 } 192 }
181 } 193 }
182 194
@@ -211,6 +223,13 @@ where
211 if let Some(module) = dep.krate.root_module(self.db) { 223 if let Some(module) = dep.krate.root_module(self.db) {
212 self.result.extern_prelude.insert(dep.name.clone(), module.into()); 224 self.result.extern_prelude.insert(dep.name.clone(), module.into());
213 } 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 }
214 } 233 }
215 } 234 }
216 235
@@ -266,10 +285,20 @@ where
266 import_id: ImportId, 285 import_id: ImportId,
267 import: &ImportData, 286 import: &ImportData,
268 ) -> ReachedFixedPoint { 287 ) -> ReachedFixedPoint {
269 log::debug!("resolving import: {:?}", import); 288 log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
270 let original_module = Module { krate: self.krate, module_id }; 289 let original_module = Module { krate: self.krate, module_id };
271 let (def, reached_fixedpoint) = 290
272 self.result.resolve_path_fp(self.db, original_module, &import.path); 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 self.result.resolve_path_fp(self.db, ResolveMode::Import, original_module, &import.path)
301 };
273 302
274 if reached_fixedpoint != ReachedFixedPoint::Yes { 303 if reached_fixedpoint != ReachedFixedPoint::Yes {
275 return reached_fixedpoint; 304 return reached_fixedpoint;
@@ -279,7 +308,10 @@ where
279 log::debug!("glob import: {:?}", import); 308 log::debug!("glob import: {:?}", import);
280 match def.take_types() { 309 match def.take_types() {
281 Some(ModuleDef::Module(m)) => { 310 Some(ModuleDef::Module(m)) => {
282 if m.krate != self.krate { 311 if import.is_prelude {
312 tested_by!(std_prelude);
313 self.result.prelude = Some(m);
314 } else if m.krate != self.krate {
283 tested_by!(glob_across_crates); 315 tested_by!(glob_across_crates);
284 // glob import from other crate => we can just import everything once 316 // glob import from other crate => we can just import everything once
285 let item_map = self.db.item_map(m.krate); 317 let item_map = self.db.item_map(m.krate);
@@ -404,6 +436,12 @@ where
404} 436}
405 437
406#[derive(Debug, Clone, Copy, PartialEq, Eq)] 438#[derive(Debug, Clone, Copy, PartialEq, Eq)]
439enum ResolveMode {
440 Import,
441 Other,
442}
443
444#[derive(Debug, Clone, Copy, PartialEq, Eq)]
407enum ReachedFixedPoint { 445enum ReachedFixedPoint {
408 Yes, 446 Yes,
409 No, 447 No,
@@ -431,15 +469,61 @@ impl ItemMap {
431 original_module: Module, 469 original_module: Module,
432 path: &Path, 470 path: &Path,
433 ) -> PerNs<ModuleDef> { 471 ) -> PerNs<ModuleDef> {
434 self.resolve_path_fp(db, original_module, path).0 472 self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0
473 }
474
475 fn resolve_in_prelude(
476 &self,
477 db: &impl PersistentHirDatabase,
478 original_module: Module,
479 name: &Name,
480 ) -> PerNs<ModuleDef> {
481 if let Some(prelude) = self.prelude {
482 let resolution = if prelude.krate == original_module.krate {
483 self[prelude.module_id].items.get(name).cloned()
484 } else {
485 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
486 };
487 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
488 } else {
489 PerNs::none()
490 }
435 } 491 }
436 492
437 pub(crate) fn resolve_name_in_module(&self, module: Module, name: &Name) -> PerNs<ModuleDef> { 493 pub(crate) fn resolve_name_in_module(
494 &self,
495 db: &impl PersistentHirDatabase,
496 module: Module,
497 name: &Name,
498 ) -> PerNs<ModuleDef> {
499 // Resolve in:
500 // - current module / scope
501 // - extern prelude
502 // - std prelude
438 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); 503 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
439 let from_extern_prelude = 504 let from_extern_prelude =
440 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 505 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
506 let from_prelude = self.resolve_in_prelude(db, module, name);
507
508 from_scope.or(from_extern_prelude).or(from_prelude)
509 }
510
511 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
512 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
513 }
441 514
442 from_scope.or(from_extern_prelude) 515 fn resolve_name_in_crate_root_or_extern_prelude(
516 &self,
517 db: &impl PersistentHirDatabase,
518 module: Module,
519 name: &Name,
520 ) -> PerNs<ModuleDef> {
521 let crate_root = module.crate_root(db);
522 let from_crate_root =
523 self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
524 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
525
526 from_crate_root.or(from_extern_prelude)
443 } 527 }
444 528
445 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 529 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -447,6 +531,7 @@ impl ItemMap {
447 fn resolve_path_fp( 531 fn resolve_path_fp(
448 &self, 532 &self,
449 db: &impl PersistentHirDatabase, 533 db: &impl PersistentHirDatabase,
534 mode: ResolveMode,
450 original_module: Module, 535 original_module: Module,
451 path: &Path, 536 path: &Path,
452 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 537 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
@@ -454,12 +539,32 @@ impl ItemMap {
454 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 539 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
455 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 540 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
456 PathKind::Self_ => PerNs::types(original_module.into()), 541 PathKind::Self_ => PerNs::types(original_module.into()),
542 // plain import or absolute path in 2015: crate-relative with
543 // fallback to extern prelude (with the simplification in
544 // rust-lang/rust#57745)
545 // TODO there must be a nicer way to write this condition
546 PathKind::Plain | PathKind::Abs
547 if self.edition == Edition::Edition2015
548 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
549 {
550 let segment = match segments.next() {
551 Some((_, segment)) => segment,
552 None => return (PerNs::none(), ReachedFixedPoint::Yes),
553 };
554 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
555 self.resolve_name_in_crate_root_or_extern_prelude(
556 db,
557 original_module,
558 &segment.name,
559 )
560 }
457 PathKind::Plain => { 561 PathKind::Plain => {
458 let segment = match segments.next() { 562 let segment = match segments.next() {
459 Some((_, segment)) => segment, 563 Some((_, segment)) => segment,
460 None => return (PerNs::none(), ReachedFixedPoint::Yes), 564 None => return (PerNs::none(), ReachedFixedPoint::Yes),
461 }; 565 };
462 self.resolve_name_in_module(original_module, &segment.name) 566 log::debug!("resolving {:?} in module", segment);
567 self.resolve_name_in_module(db, original_module, &segment.name)
463 } 568 }
464 PathKind::Super => { 569 PathKind::Super => {
465 if let Some(p) = original_module.parent(db) { 570 if let Some(p) = original_module.parent(db) {
@@ -490,7 +595,7 @@ impl ItemMap {
490 None => { 595 None => {
491 // we still have path segments left, but the path so far 596 // we still have path segments left, but the path so far
492 // didn't resolve in the types namespace => no resolution 597 // didn't resolve in the types namespace => no resolution
493 // (don't break here because curr_per_ns might contain 598 // (don't break here because `curr_per_ns` might contain
494 // something in the value namespace, and it would be wrong 599 // something in the value namespace, and it would be wrong
495 // to return that) 600 // to return that)
496 return (PerNs::none(), ReachedFixedPoint::No); 601 return (PerNs::none(), ReachedFixedPoint::No);
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index 7e9a3de2b..81d80654c 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -2,13 +2,13 @@ use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, SourceFile, TreeArc, AstPtr, 4 AstNode, SourceFile, TreeArc, AstPtr,
5 ast::{self, ModuleItemOwner, NameOwner}, 5 ast::{self, ModuleItemOwner, NameOwner, AttrsOwner},
6}; 6};
7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9 9
10use crate::{ 10use crate::{
11 SourceItemId, Path, PathKind, ModuleSource, Name, 11 SourceItemId, Path, ModuleSource, Name,
12 HirFileId, MacroCallLoc, AsName, PerNs, Function, 12 HirFileId, MacroCallLoc, AsName, PerNs, Function,
13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type, 13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type,
14 ids::LocationCtx, PersistentHirDatabase, 14 ids::LocationCtx, PersistentHirDatabase,
@@ -23,6 +23,7 @@ pub(super) struct ImportData {
23 pub(super) path: Path, 23 pub(super) path: Path,
24 pub(super) alias: Option<Name>, 24 pub(super) alias: Option<Name>,
25 pub(super) is_glob: bool, 25 pub(super) is_glob: bool,
26 pub(super) is_prelude: bool,
26 pub(super) is_extern_crate: bool, 27 pub(super) is_extern_crate: bool,
27} 28}
28 29
@@ -179,18 +180,14 @@ impl LoweredModule {
179 self.add_use_item(source_map, it); 180 self.add_use_item(source_map, it);
180 } 181 }
181 ast::ModuleItemKind::ExternCrateItem(it) => { 182 ast::ModuleItemKind::ExternCrateItem(it) => {
182 // Lower `extern crate x` to `use ::x`. This is kind of cheating
183 // and only works if we always interpret absolute paths in the
184 // 2018 style; otherwise `::x` could also refer to a module in
185 // the crate root.
186 if let Some(name_ref) = it.name_ref() { 183 if let Some(name_ref) = it.name_ref() {
187 let mut path = Path::from_name_ref(name_ref); 184 let path = Path::from_name_ref(name_ref);
188 path.kind = PathKind::Abs;
189 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name); 185 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
190 self.imports.alloc(ImportData { 186 self.imports.alloc(ImportData {
191 path, 187 path,
192 alias, 188 alias,
193 is_glob: false, 189 is_glob: false,
190 is_prelude: false,
194 is_extern_crate: true, 191 is_extern_crate: true,
195 }); 192 });
196 } 193 }
@@ -208,17 +205,20 @@ impl LoweredModule {
208 } 205 }
209 } 206 }
210 ast::ModuleItemKind::Module(_) => { 207 ast::ModuleItemKind::Module(_) => {
211 // modules are handled separately direclty by nameres 208 // modules are handled separately directly by name res
212 } 209 }
213 }; 210 };
214 } 211 }
215 212
216 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) { 213 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
214 let is_prelude =
215 item.attrs().any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false));
217 Path::expand_use_item(item, |path, segment, alias| { 216 Path::expand_use_item(item, |path, segment, alias| {
218 let import = self.imports.alloc(ImportData { 217 let import = self.imports.alloc(ImportData {
219 path, 218 path,
220 alias, 219 alias,
221 is_glob: segment.is_none(), 220 is_glob: segment.is_none(),
221 is_prelude,
222 is_extern_crate: false, 222 is_extern_crate: false,
223 }); 223 });
224 if let Some(segment) = segment { 224 if let Some(segment) = segment {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 6dbe759d1..6402c89c0 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -266,6 +266,45 @@ fn glob_across_crates() {
266} 266}
267 267
268#[test] 268#[test]
269fn edition_2015_imports() {
270 let mut db = MockDatabase::with_files(
271 "
272 //- /main.rs
273 mod foo;
274 mod bar;
275
276 //- /bar.rs
277 struct Bar;
278
279 //- /foo.rs
280 use bar::Bar;
281 use other_crate::FromLib;
282
283 //- /lib.rs
284 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 ",
304 );
305}
306
307#[test]
269fn module_resolution_works_for_non_standard_filenames() { 308fn module_resolution_works_for_non_standard_filenames() {
270 let mut db = MockDatabase::with_files( 309 let mut db = MockDatabase::with_files(
271 " 310 "
@@ -297,6 +336,43 @@ fn module_resolution_works_for_non_standard_filenames() {
297} 336}
298 337
299#[test] 338#[test]
339fn std_prelude() {
340 covers!(std_prelude);
341 let mut db = MockDatabase::with_files(
342 "
343 //- /main.rs
344 use Foo::*;
345
346 //- /lib.rs
347 mod prelude;
348 #[prelude_import]
349 use prelude::*;
350
351 //- /prelude.rs
352 pub enum Foo { Bar, Baz };
353 ",
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 );
373}
374
375#[test]
300fn name_res_works_for_broken_modules() { 376fn name_res_works_for_broken_modules() {
301 covers!(name_res_works_for_broken_modules); 377 covers!(name_res_works_for_broken_modules);
302 let (item_map, module_id) = item_map( 378 let (item_map, module_id) = item_map(
@@ -467,6 +543,42 @@ fn extern_crate_rename() {
467} 543}
468 544
469#[test] 545#[test]
546fn extern_crate_rename_2015_edition() {
547 let mut db = MockDatabase::with_files(
548 "
549 //- /main.rs
550 extern crate alloc as alloc_crate;
551
552 mod alloc;
553 mod sync;
554
555 //- /sync.rs
556 use alloc_crate::Arc;
557
558 //- /lib.rs
559 struct Arc;
560 ",
561 );
562 db.set_crate_graph_from_fixture(crate_graph! {
563 "main": ("/main.rs", "2015", ["alloc"]),
564 "alloc": ("/lib.rs", []),
565 });
566 let sync_id = db.file_id_of("/sync.rs");
567
568 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
569 let krate = module.krate(&db).unwrap();
570 let item_map = db.item_map(krate);
571
572 check_module_item_map(
573 &item_map,
574 module.module_id,
575 "
576 Arc: t v
577 ",
578 );
579}
580
581#[test]
470fn import_across_source_roots() { 582fn import_across_source_roots() {
471 let mut db = MockDatabase::with_files( 583 let mut db = MockDatabase::with_files(
472 " 584 "
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 6a24c8aa7..8ed54607a 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -97,7 +97,7 @@ impl Path {
97 return Some(q); 97 return Some(q);
98 } 98 }
99 // TODO: this bottom up traversal is not too precise. 99 // TODO: this bottom up traversal is not too precise.
100 // Should we handle do a top-down analysiss, recording results? 100 // Should we handle do a top-down analysis, recording results?
101 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; 101 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
102 let use_tree = use_tree_list.parent_use_tree(); 102 let use_tree = use_tree_list.parent_use_tree();
103 use_tree.path() 103 use_tree.path()
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 40c860cf4..91a531801 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -56,10 +56,10 @@ pub enum Resolution {
56} 56}
57 57
58impl Resolver { 58impl Resolver {
59 pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { 59 pub fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
60 let mut resolution = PerNs::none(); 60 let mut resolution = PerNs::none();
61 for scope in self.scopes.iter().rev() { 61 for scope in self.scopes.iter().rev() {
62 resolution = resolution.or(scope.resolve_name(name)); 62 resolution = resolution.or(scope.resolve_name(db, name));
63 if resolution.is_both() { 63 if resolution.is_both() {
64 return resolution; 64 return resolution;
65 } 65 }
@@ -69,9 +69,9 @@ impl Resolver {
69 69
70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { 70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> {
71 if let Some(name) = path.as_ident() { 71 if let Some(name) = path.as_ident() {
72 self.resolve_name(name) 72 self.resolve_name(db, name)
73 } else if path.is_self() { 73 } else if path.is_self() {
74 self.resolve_name(&Name::self_param()) 74 self.resolve_name(db, &Name::self_param())
75 } else { 75 } else {
76 let (item_map, module) = match self.module() { 76 let (item_map, module) = match self.module() {
77 Some(m) => m, 77 Some(m) => m,
@@ -82,10 +82,10 @@ impl Resolver {
82 } 82 }
83 } 83 }
84 84
85 pub fn all_names(&self) -> FxHashMap<Name, PerNs<Resolution>> { 85 pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> {
86 let mut names = FxHashMap::default(); 86 let mut names = FxHashMap::default();
87 for scope in self.scopes.iter().rev() { 87 for scope in self.scopes.iter().rev() {
88 scope.collect_names(&mut |name, res| { 88 scope.collect_names(db, &mut |name, res| {
89 let current: &mut PerNs<Resolution> = names.entry(name).or_default(); 89 let current: &mut PerNs<Resolution> = names.entry(name).or_default();
90 if current.types.is_none() { 90 if current.types.is_none() {
91 current.types = res.types; 91 current.types = res.types;
@@ -143,13 +143,13 @@ impl Resolver {
143} 143}
144 144
145impl Scope { 145impl Scope {
146 fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { 146 fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
147 match self { 147 match self {
148 Scope::ModuleScope(m) => { 148 Scope::ModuleScope(m) => {
149 if let Some(KnownName::SelfParam) = name.as_known_name() { 149 if let Some(KnownName::SelfParam) = name.as_known_name() {
150 PerNs::types(Resolution::Def(m.module.into())) 150 PerNs::types(Resolution::Def(m.module.into()))
151 } else { 151 } else {
152 m.item_map.resolve_name_in_module(m.module, name).map(Resolution::Def) 152 m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def)
153 } 153 }
154 } 154 }
155 Scope::GenericParams(gp) => match gp.find_by_name(name) { 155 Scope::GenericParams(gp) => match gp.find_by_name(name) {
@@ -174,7 +174,7 @@ impl Scope {
174 } 174 }
175 } 175 }
176 176
177 fn collect_names(&self, f: &mut dyn FnMut(Name, PerNs<Resolution>)) { 177 fn collect_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, PerNs<Resolution>)) {
178 match self { 178 match self {
179 Scope::ModuleScope(m) => { 179 Scope::ModuleScope(m) => {
180 // TODO: should we provide `self` here? 180 // TODO: should we provide `self` here?
@@ -190,6 +190,12 @@ impl Scope {
190 m.item_map.extern_prelude.iter().for_each(|(name, def)| { 190 m.item_map.extern_prelude.iter().for_each(|(name, def)| {
191 f(name.clone(), PerNs::types(Resolution::Def(*def))); 191 f(name.clone(), PerNs::types(Resolution::Def(*def)));
192 }); 192 });
193 if let Some(prelude) = m.item_map.prelude {
194 let prelude_item_map = db.item_map(prelude.krate);
195 prelude_item_map[prelude.module_id].entries().for_each(|(name, res)| {
196 f(name.clone(), res.def.map(Resolution::Def));
197 });
198 }
193 } 199 }
194 Scope::GenericParams(gp) => { 200 Scope::GenericParams(gp) => {
195 for param in &gp.params { 201 for param in &gp.params {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 2dc1de41a..f28a7e731 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -450,7 +450,6 @@ impl Ty {
450 } 450 }
451 451
452 pub fn walk(&self, f: &mut impl FnMut(&Ty)) { 452 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
453 f(self);
454 match self { 453 match self {
455 Ty::Slice(t) | Ty::Array(t) => t.walk(f), 454 Ty::Slice(t) | Ty::Array(t) => t.walk(f),
456 Ty::RawPtr(t, _) => t.walk(f), 455 Ty::RawPtr(t, _) => t.walk(f),
@@ -490,10 +489,10 @@ impl Ty {
490 | Ty::Infer(_) 489 | Ty::Infer(_)
491 | Ty::Unknown => {} 490 | Ty::Unknown => {}
492 } 491 }
492 f(self);
493 } 493 }
494 494
495 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 495 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
496 f(self);
497 match self { 496 match self {
498 Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f), 497 Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f),
499 Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f), 498 Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f),
@@ -544,6 +543,7 @@ impl Ty {
544 | Ty::Infer(_) 543 | Ty::Infer(_)
545 | Ty::Unknown => {} 544 | Ty::Unknown => {}
546 } 545 }
546 f(self);
547 } 547 }
548 548
549 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty { 549 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty {
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_nested_generics_crash.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_nested_generics_crash.snap
new file mode 100644
index 000000000..209454a91
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_nested_generics_crash.snap
@@ -0,0 +1,12 @@
1---
2created: "2019-02-11T21:59:04.302375838Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[92; 106) 'query_response': Canonical<QueryResponse<R>>
8[137; 167) '{ ...lue; }': ()
9[143; 164) '&query....value': &QueryResponse<R>
10[144; 158) 'query_response': Canonical<QueryResponse<R>>
11[144; 164) 'query_....value': QueryResponse<R>
12
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index e64fd2749..203f1fe4d 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -719,6 +719,25 @@ fn extra_compiler_flags() {
719 ); 719 );
720} 720}
721 721
722#[test]
723fn infer_nested_generics_crash() {
724 // another crash found typechecking rustc
725 check_inference(
726 "infer_nested_generics_crash",
727 r#"
728struct Canonical<V> {
729 value: V,
730}
731struct QueryResponse<V> {
732 value: V,
733}
734fn test<R>(query_response: Canonical<QueryResponse<R>>) {
735 &query_response.value;
736}
737"#,
738 );
739}
740
722fn infer(content: &str) -> String { 741fn infer(content: &str) -> String {
723 let (db, _, file_id) = MockDatabase::with_single_file(content); 742 let (db, _, file_id) = MockDatabase::with_single_file(content);
724 let source_file = db.parse(file_id); 743 let source_file = db.parse(file_id);
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index 83c243944..4a38d62bb 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -30,7 +30,7 @@ pub use crate::completion::completion_item::{CompletionItem, CompletionItemKind,
30/// incomplete and can look really weird. 30/// incomplete and can look really weird.
31/// 31///
32/// Once the context is collected, we run a series of completion routines which 32/// Once the context is collected, we run a series of completion routines which
33/// look at the context and produce completion items. One subtelty about this 33/// look at the context and produce completion items. One subtlety about this
34/// phase is that completion engine should not filter by the substring which is 34/// phase is that completion engine should not filter by the substring which is
35/// already present, it should give all possible variants for the identifier at 35/// already present, it should give all possible variants for the identifier at
36/// the caret. In other words, for 36/// the caret. In other words, for
@@ -71,6 +71,7 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> {
71 .children() 71 .children()
72 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body 72 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
73 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments 73 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
74 .filter(|child| ast::Attr::cast(child).is_none()) // Filter out attributes
74 .map(|node| node.text().to_string()) 75 .map(|node| node.text().to_string())
75 .collect(); 76 .collect();
76 label 77 label
@@ -86,6 +87,7 @@ pub fn const_label(node: &ast::ConstDef) -> String {
86 .syntax() 87 .syntax()
87 .children() 88 .children()
88 .filter(|child| ast::Comment::cast(child).is_none()) 89 .filter(|child| ast::Comment::cast(child).is_none())
90 .filter(|child| ast::Attr::cast(child).is_none())
89 .map(|node| node.text().to_string()) 91 .map(|node| node.text().to_string())
90 .collect(); 92 .collect();
91 93
@@ -97,6 +99,7 @@ pub fn type_label(node: &ast::TypeDef) -> String {
97 .syntax() 99 .syntax()
98 .children() 100 .children()
99 .filter(|child| ast::Comment::cast(child).is_none()) 101 .filter(|child| ast::Comment::cast(child).is_none())
102 .filter(|child| ast::Attr::cast(child).is_none())
100 .map(|node| node.text().to_string()) 103 .map(|node| node.text().to_string())
101 .collect(); 104 .collect();
102 105
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index a673dbdcf..be839345f 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -180,6 +180,26 @@ mod tests {
180 } 180 }
181 181
182 #[test] 182 #[test]
183 fn test_method_attr_filtering() {
184 check_ref_completion(
185 "method_attr_filtering",
186 r"
187 struct A {}
188 impl A {
189 #[inline]
190 fn the_method(&self) {
191 let x = 1;
192 let y = 2;
193 }
194 }
195 fn foo(a: A) {
196 a.<|>
197 }
198 ",
199 );
200 }
201
202 #[test]
183 fn test_tuple_field_completion() { 203 fn test_tuple_field_completion() {
184 check_ref_completion( 204 check_ref_completion(
185 "tuple_field_completion", 205 "tuple_field_completion",
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs
index 43532226f..4d6416284 100644
--- a/crates/ra_ide_api/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs
@@ -7,7 +7,7 @@ use rustc_hash::FxHashMap;
7 7
8use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem}; 8use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem};
9 9
10/// Complete repeated parametes, both name and type. For example, if all 10/// Complete repeated parameters, both name and type. For example, if all
11/// functions in a file have a `spam: &mut Spam` parameter, a completion with 11/// functions in a file have a `spam: &mut Spam` parameter, a completion with
12/// `spam: &mut Spam` insert text/label and `spam` lookup string will be 12/// `spam: &mut Spam` insert text/label and `spam` lookup string will be
13/// suggested. 13/// suggested.
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 445788407..eeaf26d93 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -4,7 +4,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
4 if !ctx.is_trivial_path { 4 if !ctx.is_trivial_path {
5 return; 5 return;
6 } 6 }
7 let names = ctx.resolver.all_names(); 7 let names = ctx.resolver.all_names(ctx.db);
8 8
9 names.into_iter().for_each(|(name, res)| { 9 names.into_iter().for_each(|(name, res)| {
10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
@@ -165,4 +165,23 @@ mod tests {
165 fn completes_self_in_methods() { 165 fn completes_self_in_methods() {
166 check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }") 166 check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }")
167 } 167 }
168
169 #[test]
170 fn completes_prelude() {
171 check_reference_completion(
172 "completes_prelude",
173 "
174 //- /main.rs
175 fn foo() { let x: <|> }
176
177 //- /std/lib.rs
178 #[prelude_import]
179 use prelude::*;
180
181 mod prelude {
182 struct Option;
183 }
184 ",
185 );
186 }
168} 187}
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap
new file mode 100644
index 000000000..2b5a1a8ea
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap
@@ -0,0 +1,54 @@
1---
2created: "2019-02-13T19:52:43.734834624Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions
6---
7[
8 CompletionItem {
9 completion_kind: Reference,
10 label: "Option",
11 kind: Some(
12 Struct
13 ),
14 detail: None,
15 documentation: None,
16 lookup: None,
17 insert_text: None,
18 insert_text_format: PlainText,
19 source_range: [18; 18),
20 text_edit: None
21 },
22 CompletionItem {
23 completion_kind: Reference,
24 label: "foo",
25 kind: Some(
26 Function
27 ),
28 detail: Some(
29 "fn foo()"
30 ),
31 documentation: None,
32 lookup: None,
33 insert_text: Some(
34 "foo()$0"
35 ),
36 insert_text_format: Snippet,
37 source_range: [18; 18),
38 text_edit: None
39 },
40 CompletionItem {
41 completion_kind: Reference,
42 label: "std",
43 kind: Some(
44 Module
45 ),
46 detail: None,
47 documentation: None,
48 lookup: None,
49 insert_text: None,
50 insert_text_format: PlainText,
51 source_range: [18; 18),
52 text_edit: None
53 }
54]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap
new file mode 100644
index 000000000..46f9fa971
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap
@@ -0,0 +1,26 @@
1---
2created: "2019-02-12T18:32:09.428929418Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions
6---
7[
8 CompletionItem {
9 completion_kind: Reference,
10 label: "the_method",
11 kind: Some(
12 Method
13 ),
14 detail: Some(
15 "fn the_method(&self)"
16 ),
17 documentation: None,
18 lookup: None,
19 insert_text: Some(
20 "the_method()$0"
21 ),
22 insert_text_format: Snippet,
23 source_range: [249; 249),
24 text_edit: None
25 }
26]
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 413720960..96ed8c8e9 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -93,10 +93,10 @@ pub(crate) fn reference_definition(
93 return Exact(nav); 93 return Exact(nav);
94 } 94 }
95 Some(Resolution::GenericParam(..)) => { 95 Some(Resolution::GenericParam(..)) => {
96 // TODO go to the generic param def 96 // TODO: go to the generic param def
97 } 97 }
98 Some(Resolution::SelfType(_impl_block)) => { 98 Some(Resolution::SelfType(_impl_block)) => {
99 // TODO go to the implemented type 99 // TODO: go to the implemented type
100 } 100 }
101 None => {} 101 None => {}
102 } 102 }
@@ -133,8 +133,8 @@ mod tests {
133 133
134 use crate::mock_analysis::analysis_and_position; 134 use crate::mock_analysis::analysis_and_position;
135 135
136 fn check_goto(fixuture: &str, expected: &str) { 136 fn check_goto(fixture: &str, expected: &str) {
137 let (analysis, pos) = analysis_and_position(fixuture); 137 let (analysis, pos) = analysis_and_position(fixture);
138 138
139 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 139 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
140 assert_eq!(navs.len(), 1); 140 assert_eq!(navs.len(), 1);
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 60b81567c..0888ab6de 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -71,8 +71,8 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
71 } 71 }
72} 72}
73 73
74// FIXME: this should not really use navigation target. Rather, approximatelly 74// FIXME: this should not really use navigation target. Rather, approximately
75// resovled symbol should return a `DefId`. 75// resolved symbol should return a `DefId`.
76fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> { 76fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
77 match (nav.description(db), nav.docs(db)) { 77 match (nav.description(db), nav.docs(db)) {
78 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs), 78 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs),
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
index 444c4aeb2..681bd808d 100644
--- a/crates/ra_ide_api/src/impls.rs
+++ b/crates/ra_ide_api/src/impls.rs
@@ -78,8 +78,8 @@ fn impls_for_trait(
78mod tests { 78mod tests {
79 use crate::mock_analysis::analysis_and_position; 79 use crate::mock_analysis::analysis_and_position;
80 80
81 fn check_goto(fixuture: &str, expected: &[&str]) { 81 fn check_goto(fixture: &str, expected: &[&str]) {
82 let (analysis, pos) = analysis_and_position(fixuture); 82 let (analysis, pos) = analysis_and_position(fixture);
83 83
84 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info; 84 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
85 assert_eq!(navs.len(), expected.len()); 85 assert_eq!(navs.len(), expected.len());
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 2d090d9b4..d77a56ce8 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -7,7 +7,7 @@
7//! However, IDE specific bits of the analysis (most notably completion) happen 7//! However, IDE specific bits of the analysis (most notably completion) happen
8//! in this crate. 8//! in this crate.
9//! 9//!
10//! The sibling `ra_ide_api_light` handles thouse bits of IDE functionality 10//! The sibling `ra_ide_api_light` handles those bits of IDE functionality
11//! which are restricted to a single file and need only syntax. 11//! which are restricted to a single file and need only syntax.
12 12
13// For proving that RootDatabase is RefUnwindSafe. 13// For proving that RootDatabase is RefUnwindSafe.
@@ -62,12 +62,13 @@ pub use ra_ide_api_light::{
62 LineIndex, LineCol, translate_offset_with_edit, 62 LineIndex, LineCol, translate_offset_with_edit,
63}; 63};
64pub use ra_db::{ 64pub use ra_db::{
65 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId 65 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId,
66 Edition
66}; 67};
67pub use hir::Documentation; 68pub use hir::Documentation;
68 69
69// We use jemalloc mainly to get heap usage statistics, actual performance 70// We use jemalloc mainly to get heap usage statistics, actual performance
70// differnece is not measures. 71// difference is not measures.
71#[cfg(feature = "jemalloc")] 72#[cfg(feature = "jemalloc")]
72#[global_allocator] 73#[global_allocator]
73static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 74static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
@@ -221,12 +222,12 @@ impl Analysis {
221 self.db.line_index(file_id) 222 self.db.line_index(file_id)
222 } 223 }
223 224
224 /// Selects the next syntactic nodes encopasing the range. 225 /// Selects the next syntactic nodes encompassing the range.
225 pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> { 226 pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> {
226 self.with_db(|db| extend_selection::extend_selection(db, frange)) 227 self.with_db(|db| extend_selection::extend_selection(db, frange))
227 } 228 }
228 229
229 /// Returns position of the mathcing brace (all types of braces are 230 /// Returns position of the matching brace (all types of braces are
230 /// supported). 231 /// supported).
231 pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> { 232 pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> {
232 let file = self.db.parse(position.file_id); 233 let file = self.db.parse(position.file_id);
@@ -316,7 +317,7 @@ impl Analysis {
316 self.with_db(|db| references::find_all_refs(db, position)) 317 self.with_db(|db| references::find_all_refs(db, position))
317 } 318 }
318 319
319 /// Returns a short text descrbing element at position. 320 /// Returns a short text describing element at position.
320 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { 321 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> {
321 self.with_db(|db| hover::hover(db, position)) 322 self.with_db(|db| hover::hover(db, position))
322 } 323 }
diff --git a/crates/ra_ide_api/src/mock_analysis.rs b/crates/ra_ide_api/src/mock_analysis.rs
index 8d8603062..550d69641 100644
--- a/crates/ra_ide_api/src/mock_analysis.rs
+++ b/crates/ra_ide_api/src/mock_analysis.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
5 5
6use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId}; 6use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId, Edition::Edition2018};
7 7
8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
9/// from a set of in-memory files. 9/// from a set of in-memory files.
@@ -18,7 +18,7 @@ impl MockAnalysis {
18 } 18 }
19 /// Creates `MockAnalysis` using a fixture data in the following format: 19 /// Creates `MockAnalysis` using a fixture data in the following format:
20 /// 20 ///
21 /// ```notrust 21 /// ```rust,ignore
22 /// //- /main.rs 22 /// //- /main.rs
23 /// mod foo; 23 /// mod foo;
24 /// fn main() {} 24 /// fn main() {}
@@ -89,9 +89,9 @@ impl MockAnalysis {
89 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 89 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
90 let file_id = FileId(i as u32 + 1); 90 let file_id = FileId(i as u32 + 1);
91 if path == "/lib.rs" || path == "/main.rs" { 91 if path == "/lib.rs" || path == "/main.rs" {
92 root_crate = Some(crate_graph.add_crate_root(file_id)); 92 root_crate = Some(crate_graph.add_crate_root(file_id, Edition2018));
93 } else if path.ends_with("/lib.rs") { 93 } else if path.ends_with("/lib.rs") {
94 let other_crate = crate_graph.add_crate_root(file_id); 94 let other_crate = crate_graph.add_crate_root(file_id, Edition2018);
95 let crate_name = path.parent().unwrap().file_name().unwrap(); 95 let crate_name = path.parent().unwrap().file_name().unwrap();
96 if let Some(root_crate) = root_crate { 96 if let Some(root_crate) = root_crate {
97 crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap(); 97 crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap();
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs
index a2e4b6506..c559dca11 100644
--- a/crates/ra_ide_api/src/navigation_target.rs
+++ b/crates/ra_ide_api/src/navigation_target.rs
@@ -19,6 +19,7 @@ pub struct NavigationTarget {
19 kind: SyntaxKind, 19 kind: SyntaxKind,
20 full_range: TextRange, 20 full_range: TextRange,
21 focus_range: Option<TextRange>, 21 focus_range: Option<TextRange>,
22 container_name: Option<SmolStr>,
22} 23}
23 24
24impl NavigationTarget { 25impl NavigationTarget {
@@ -26,6 +27,10 @@ impl NavigationTarget {
26 &self.name 27 &self.name
27 } 28 }
28 29
30 pub fn container_name(&self) -> Option<&SmolStr> {
31 self.container_name.as_ref()
32 }
33
29 pub fn kind(&self) -> SyntaxKind { 34 pub fn kind(&self) -> SyntaxKind {
30 self.kind 35 self.kind
31 } 36 }
@@ -53,6 +58,7 @@ impl NavigationTarget {
53 kind: symbol.ptr.kind(), 58 kind: symbol.ptr.kind(),
54 full_range: symbol.ptr.range(), 59 full_range: symbol.ptr.range(),
55 focus_range: None, 60 focus_range: None,
61 container_name: symbol.container_name.clone(),
56 } 62 }
57 } 63 }
58 64
@@ -67,6 +73,7 @@ impl NavigationTarget {
67 full_range: ptr.range(), 73 full_range: ptr.range(),
68 focus_range: None, 74 focus_range: None,
69 kind: NAME, 75 kind: NAME,
76 container_name: None,
70 } 77 }
71 } 78 }
72 79
@@ -170,6 +177,9 @@ impl NavigationTarget {
170 if let Some(focus_range) = self.focus_range() { 177 if let Some(focus_range) = self.focus_range() {
171 buf.push_str(&format!(" {:?}", focus_range)) 178 buf.push_str(&format!(" {:?}", focus_range))
172 } 179 }
180 if let Some(container_name) = self.container_name() {
181 buf.push_str(&format!(" {:?}", container_name))
182 }
173 buf 183 buf
174 } 184 }
175 185
@@ -192,6 +202,7 @@ impl NavigationTarget {
192 full_range: node.range(), 202 full_range: node.range(),
193 focus_range, 203 focus_range,
194 // ptr: Some(LocalSyntaxPtr::new(node)), 204 // ptr: Some(LocalSyntaxPtr::new(node)),
205 container_name: None,
195 } 206 }
196 } 207 }
197} 208}
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 2cb1cc9be..ca145f3e4 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -295,17 +295,17 @@ mod tests {
295 fn test_rename(text: &str, new_name: &str, expected: &str) { 295 fn test_rename(text: &str, new_name: &str, expected: &str) {
296 let (analysis, position) = single_file_with_position(text); 296 let (analysis, position) = single_file_with_position(text);
297 let source_change = analysis.rename(position, new_name).unwrap(); 297 let source_change = analysis.rename(position, new_name).unwrap();
298 let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default(); 298 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
299 let mut file_id: Option<FileId> = None; 299 let mut file_id: Option<FileId> = None;
300 if let Some(change) = source_change { 300 if let Some(change) = source_change {
301 for edit in change.source_file_edits { 301 for edit in change.source_file_edits {
302 file_id = Some(edit.file_id); 302 file_id = Some(edit.file_id);
303 for atom in edit.edit.as_atoms() { 303 for atom in edit.edit.as_atoms() {
304 text_edit_bulder.replace(atom.delete, atom.insert.clone()); 304 text_edit_builder.replace(atom.delete, atom.insert.clone());
305 } 305 }
306 } 306 }
307 } 307 }
308 let result = text_edit_bulder.finish().apply(&*analysis.file_text(file_id.unwrap())); 308 let result = text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()));
309 assert_eq_text!(expected, &*result); 309 assert_eq_text!(expected, &*result);
310 } 310 }
311} 311}
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index de0f46134..afb10fa92 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -5,20 +5,20 @@
5//! symbols. The backbone of the index is the **awesome** `fst` crate by 5//! symbols. The backbone of the index is the **awesome** `fst` crate by
6//! @BurntSushi. 6//! @BurntSushi.
7//! 7//!
8//! In a nutshell, you give a set of strings to the `fst`, and it builds a 8//! In a nutshell, you give a set of strings to `fst`, and it builds a
9//! finite state machine describing this set of strings. The strings which 9//! finite state machine describing this set of strings. The strings which
10//! could fuzzy-match a pattern can also be described by a finite state machine. 10//! could fuzzy-match a pattern can also be described by a finite state machine.
11//! What is freakingly cool is that you can now traverse both state machines in 11//! What is freaking cool is that you can now traverse both state machines in
12//! lock-step to enumerate the strings which are both in the input set and 12//! lock-step to enumerate the strings which are both in the input set and
13//! fuzz-match the query. Or, more formally, given two languages described by 13//! fuzz-match the query. Or, more formally, given two languages described by
14//! fsts, one can build an product fst which describes the intersection of the 14//! FSTs, one can build a product FST which describes the intersection of the
15//! languages. 15//! languages.
16//! 16//!
17//! `fst` does not support cheap updating of the index, but it supports unioning 17//! `fst` does not support cheap updating of the index, but it supports unioning
18//! of state machines. So, to account for changing source code, we build an fst 18//! of state machines. So, to account for changing source code, we build an FST
19//! for each library (which is assumed to never change) and an fst for each rust 19//! for each library (which is assumed to never change) and an FST for each Rust
20//! file in the current workspace, and run a query against the union of all 20//! file in the current workspace, and run a query against the union of all
21//! those fsts. 21//! those FSTs.
22use std::{ 22use std::{
23 cmp::Ordering, 23 cmp::Ordering,
24 hash::{Hash, Hasher}, 24 hash::{Hash, Hasher},
@@ -32,6 +32,7 @@ use ra_syntax::{
32 algo::{visit::{visitor, Visitor}, find_covering_node}, 32 algo::{visit::{visitor, Visitor}, find_covering_node},
33 SyntaxKind::{self, *}, 33 SyntaxKind::{self, *},
34 ast::{self, NameOwner}, 34 ast::{self, NameOwner},
35 WalkEvent,
35}; 36};
36use ra_db::{ 37use ra_db::{
37 SourceRootId, SourceDatabase, 38 SourceRootId, SourceDatabase,
@@ -62,17 +63,14 @@ pub(crate) trait SymbolsDatabase: hir::db::HirDatabase {
62fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 63fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
63 db.check_canceled(); 64 db.check_canceled();
64 let source_file = db.parse(file_id); 65 let source_file = db.parse(file_id);
65 let mut symbols = source_file 66
66 .syntax() 67 let mut symbols = source_file_to_file_symbols(&source_file, file_id);
67 .descendants()
68 .filter_map(to_symbol)
69 .map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
70 .collect::<Vec<_>>();
71 68
72 for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) { 69 for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) {
73 let node = find_covering_node(source_file.syntax(), text_range); 70 let node = find_covering_node(source_file.syntax(), text_range);
74 let ptr = SyntaxNodePtr::new(node); 71 let ptr = SyntaxNodePtr::new(node);
75 symbols.push(FileSymbol { file_id, name, ptr }) 72 // TODO: Should we get container name for macro symbols?
73 symbols.push(FileSymbol { file_id, name, ptr, container_name: None })
76 } 74 }
77 75
78 Arc::new(SymbolIndex::new(symbols)) 76 Arc::new(SymbolIndex::new(symbols))
@@ -158,13 +156,7 @@ impl SymbolIndex {
158 files: impl ParallelIterator<Item = (FileId, TreeArc<SourceFile>)>, 156 files: impl ParallelIterator<Item = (FileId, TreeArc<SourceFile>)>,
159 ) -> SymbolIndex { 157 ) -> SymbolIndex {
160 let symbols = files 158 let symbols = files
161 .flat_map(|(file_id, file)| { 159 .flat_map(|(file_id, file)| source_file_to_file_symbols(&file, file_id))
162 file.syntax()
163 .descendants()
164 .filter_map(to_symbol)
165 .map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
166 .collect::<Vec<_>>()
167 })
168 .collect::<Vec<_>>(); 160 .collect::<Vec<_>>();
169 SymbolIndex::new(symbols) 161 SymbolIndex::new(symbols)
170 } 162 }
@@ -215,12 +207,40 @@ pub(crate) struct FileSymbol {
215 pub(crate) file_id: FileId, 207 pub(crate) file_id: FileId,
216 pub(crate) name: SmolStr, 208 pub(crate) name: SmolStr,
217 pub(crate) ptr: SyntaxNodePtr, 209 pub(crate) ptr: SyntaxNodePtr,
210 pub(crate) container_name: Option<SmolStr>,
211}
212
213fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec<FileSymbol> {
214 let mut symbols = Vec::new();
215 let mut stack = Vec::new();
216
217 for event in source_file.syntax().preorder() {
218 match event {
219 WalkEvent::Enter(node) => {
220 if let Some(mut symbol) = to_file_symbol(node, file_id) {
221 symbol.container_name = stack.last().cloned();
222
223 stack.push(symbol.name.clone());
224 symbols.push(symbol);
225 }
226 }
227
228 WalkEvent::Leave(node) => {
229 if to_symbol(node).is_some() {
230 stack.pop();
231 }
232 }
233 }
234 }
235
236 symbols
218} 237}
219 238
220fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> { 239fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
221 fn decl<N: NameOwner>(node: &N) -> Option<(SmolStr, SyntaxNodePtr)> { 240 fn decl<N: NameOwner>(node: &N) -> Option<(SmolStr, SyntaxNodePtr)> {
222 let name = node.name()?.text().clone(); 241 let name = node.name()?.text().clone();
223 let ptr = SyntaxNodePtr::new(node.syntax()); 242 let ptr = SyntaxNodePtr::new(node.syntax());
243
224 Some((name, ptr)) 244 Some((name, ptr))
225 } 245 }
226 visitor() 246 visitor()
@@ -234,3 +254,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
234 .visit(decl::<ast::StaticDef>) 254 .visit(decl::<ast::StaticDef>)
235 .accept(node)? 255 .accept(node)?
236} 256}
257
258fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
259 to_symbol(node).map(move |(name, ptr)| FileSymbol { name, ptr, file_id, container_name: None })
260}
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs
index 7d1695cfd..0526f7584 100644
--- a/crates/ra_ide_api/tests/test/main.rs
+++ b/crates/ra_ide_api/tests/test/main.rs
@@ -1,9 +1,9 @@
1use insta::assert_debug_snapshot_matches; 1use insta::assert_debug_snapshot_matches;
2use ra_ide_api::{ 2use ra_ide_api::{
3 mock_analysis::{single_file, single_file_with_position, MockAnalysis}, 3 mock_analysis::{single_file, single_file_with_position, MockAnalysis},
4 AnalysisChange, CrateGraph, FileId, Query, 4 AnalysisChange, CrateGraph, Edition::Edition2018, FileId, Query, NavigationTarget
5}; 5};
6use ra_syntax::TextRange; 6use ra_syntax::{TextRange, SmolStr};
7 7
8#[test] 8#[test]
9fn test_unresolved_module_diagnostic() { 9fn test_unresolved_module_diagnostic() {
@@ -36,7 +36,7 @@ fn test_resolve_crate_root() {
36 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); 36 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
37 37
38 let mut crate_graph = CrateGraph::default(); 38 let mut crate_graph = CrateGraph::default();
39 let crate_id = crate_graph.add_crate_root(root_file); 39 let crate_id = crate_graph.add_crate_root(root_file, Edition2018);
40 let mut change = AnalysisChange::new(); 40 let mut change = AnalysisChange::new();
41 change.set_crate_graph(crate_graph); 41 change.set_crate_graph(crate_graph);
42 host.apply_change(change); 42 host.apply_change(change);
@@ -49,6 +49,11 @@ fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
49 analysis.find_all_refs(position).unwrap() 49 analysis.find_all_refs(position).unwrap()
50} 50}
51 51
52fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
53 let (analysis, _) = single_file(text);
54 analysis.symbol_search(Query::new(query.into())).unwrap()
55}
56
52#[test] 57#[test]
53fn test_find_all_refs_for_local() { 58fn test_find_all_refs_for_local() {
54 let code = r#" 59 let code = r#"
@@ -91,6 +96,49 @@ fn test_find_all_refs_for_fn_param() {
91} 96}
92 97
93#[test] 98#[test]
99fn test_world_symbols_with_no_container() {
100 let code = r#"
101 enum FooInner { }
102 "#;
103
104 let mut symbols = get_symbols_matching(code, "FooInner");
105
106 let s = symbols.pop().unwrap();
107
108 assert_eq!(s.name(), "FooInner");
109 assert!(s.container_name().is_none());
110}
111
112#[test]
113fn test_world_symbols_include_container_name() {
114 let code = r#"
115fn foo() {
116 enum FooInner { }
117}
118 "#;
119
120 let mut symbols = get_symbols_matching(code, "FooInner");
121
122 let s = symbols.pop().unwrap();
123
124 assert_eq!(s.name(), "FooInner");
125 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
126
127 let code = r#"
128mod foo {
129 struct FooInner;
130}
131 "#;
132
133 let mut symbols = get_symbols_matching(code, "FooInner");
134
135 let s = symbols.pop().unwrap();
136
137 assert_eq!(s.name(), "FooInner");
138 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
139}
140
141#[test]
94#[ignore] 142#[ignore]
95fn world_symbols_include_stuff_from_macros() { 143fn world_symbols_include_stuff_from_macros() {
96 let (analysis, _) = single_file( 144 let (analysis, _) = single_file(
diff --git a/crates/ra_ide_api_light/Cargo.toml b/crates/ra_ide_api_light/Cargo.toml
index 0735e6ae1..29c1f4639 100644
--- a/crates/ra_ide_api_light/Cargo.toml
+++ b/crates/ra_ide_api_light/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
7 7
8[dependencies] 8[dependencies]
9itertools = "0.8.0" 9itertools = "0.8.0"
10superslice = "0.1.0" 10superslice = "1.0.0"
11join_to_string = "0.1.1" 11join_to_string = "0.1.1"
12rustc-hash = "1.0" 12rustc-hash = "1.0"
13 13
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 0cdb39c32..09d896c40 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -190,7 +190,7 @@ pub fn handle_workspace_symbol(
190 name: nav.name().to_string(), 190 name: nav.name().to_string(),
191 kind: nav.kind().conv(), 191 kind: nav.kind().conv(),
192 location: nav.try_conv_with(world)?, 192 location: nav.try_conv_with(world)?,
193 container_name: None, 193 container_name: nav.container_name().map(|v| v.to_string()),
194 deprecated: None, 194 deprecated: None,
195 }; 195 };
196 res.push(info); 196 res.push(info);
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index ec2fd1eb5..cdca3cafb 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -109,7 +109,7 @@ mod tests {
109 109
110 use super::*; 110 use super::*;
111 111
112 // Good first issue (although a slightly chellegning one): 112 // Good first issue (although a slightly challenging one):
113 // 113 //
114 // * Pick a random test from here 114 // * Pick a random test from here
115 // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt 115 // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
@@ -171,8 +171,8 @@ impl_froms!(TokenTree: Leaf, Subtree);
171 171
172 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); 172 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
173 173
174 let expaned = rules.expand(&invocation_tt).unwrap(); 174 let expanded = rules.expand(&invocation_tt).unwrap();
175 assert_eq!(expaned.to_string(), expansion); 175 assert_eq!(expanded.to_string(), expansion);
176 } 176 }
177 177
178 #[test] 178 #[test]
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index f6177f078..1acba86ea 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -58,7 +58,7 @@ fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> Option<tt::Subtree> {
58/// 58///
59/// The other side of the puzzle is `expand_subtree`, where we use the bindings 59/// The other side of the puzzle is `expand_subtree`, where we use the bindings
60/// to substitute meta variables in the output template. When expanding, we 60/// to substitute meta variables in the output template. When expanding, we
61/// maintain a `nesteing` stack of indicies whihc tells us which occurence from 61/// maintain a `nesting` stack of indices which tells us which occurrence from
62/// the `Bindings` we should take. We push to the stack when we enter a 62/// the `Bindings` we should take. We push to the stack when we enter a
63/// repetition. 63/// repetition.
64/// 64///
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 8adf463a6..81cb506b7 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -4,6 +4,7 @@ use cargo_metadata::{MetadataCommand, CargoOpt};
4use ra_arena::{Arena, RawId, impl_arena_id}; 4use ra_arena::{Arena, RawId, impl_arena_id};
5use rustc_hash::FxHashMap; 5use rustc_hash::FxHashMap;
6use failure::format_err; 6use failure::format_err;
7use ra_db::Edition;
7 8
8use crate::Result; 9use crate::Result;
9 10
@@ -12,7 +13,7 @@ use crate::Result;
12/// 13///
13/// Note that internally, rust analyzer uses a different structure: 14/// Note that internally, rust analyzer uses a different structure:
14/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, 15/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
15/// while this knows about `Pacakges` & `Targets`: purely cargo-related 16/// while this knows about `Packages` & `Targets`: purely cargo-related
16/// concepts. 17/// concepts.
17#[derive(Debug, Clone)] 18#[derive(Debug, Clone)]
18pub struct CargoWorkspace { 19pub struct CargoWorkspace {
@@ -35,6 +36,7 @@ struct PackageData {
35 targets: Vec<Target>, 36 targets: Vec<Target>,
36 is_member: bool, 37 is_member: bool,
37 dependencies: Vec<PackageDependency>, 38 dependencies: Vec<PackageDependency>,
39 edition: Edition,
38} 40}
39 41
40#[derive(Debug, Clone)] 42#[derive(Debug, Clone)]
@@ -84,6 +86,9 @@ impl Package {
84 pub fn root(self, ws: &CargoWorkspace) -> &Path { 86 pub fn root(self, ws: &CargoWorkspace) -> &Path {
85 ws.packages[self].manifest.parent().unwrap() 87 ws.packages[self].manifest.parent().unwrap()
86 } 88 }
89 pub fn edition(self, ws: &CargoWorkspace) -> Edition {
90 ws.packages[self].edition
91 }
87 pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a { 92 pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a {
88 ws.packages[self].targets.iter().cloned() 93 ws.packages[self].targets.iter().cloned()
89 } 94 }
@@ -135,6 +140,7 @@ impl CargoWorkspace {
135 manifest: meta_pkg.manifest_path.clone(), 140 manifest: meta_pkg.manifest_path.clone(),
136 targets: Vec::new(), 141 targets: Vec::new(),
137 is_member, 142 is_member,
143 edition: Edition::from_string(&meta_pkg.edition),
138 dependencies: Vec::new(), 144 dependencies: Vec::new(),
139 }); 145 });
140 let pkg_data = &mut packages[pkg]; 146 let pkg_data = &mut packages[pkg];
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 3b1e07149..1b18ac836 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
6use failure::bail; 6use failure::bail;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8 8
9use ra_db::{CrateGraph, FileId}; 9use ra_db::{CrateGraph, FileId, Edition};
10 10
11pub use crate::{ 11pub use crate::{
12 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, 12 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind},
@@ -36,7 +36,8 @@ impl ProjectWorkspace {
36 let mut sysroot_crates = FxHashMap::default(); 36 let mut sysroot_crates = FxHashMap::default();
37 for krate in self.sysroot.crates() { 37 for krate in self.sysroot.crates() {
38 if let Some(file_id) = load(krate.root(&self.sysroot)) { 38 if let Some(file_id) = load(krate.root(&self.sysroot)) {
39 sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); 39 sysroot_crates
40 .insert(krate, crate_graph.add_crate_root(file_id, Edition::Edition2015));
40 } 41 }
41 } 42 }
42 for from in self.sysroot.crates() { 43 for from in self.sysroot.crates() {
@@ -62,7 +63,8 @@ impl ProjectWorkspace {
62 for tgt in pkg.targets(&self.cargo) { 63 for tgt in pkg.targets(&self.cargo) {
63 let root = tgt.root(&self.cargo); 64 let root = tgt.root(&self.cargo);
64 if let Some(file_id) = load(root) { 65 if let Some(file_id) = load(root) {
65 let crate_id = crate_graph.add_crate_root(file_id); 66 let edition = pkg.edition(&self.cargo);
67 let crate_id = crate_graph.add_crate_root(file_id, edition);
66 if tgt.kind(&self.cargo) == TargetKind::Lib { 68 if tgt.kind(&self.cargo) == TargetKind::Lib {
67 lib_tgt = Some(crate_id); 69 lib_tgt = Some(crate_id);
68 pkg_to_lib_crate.insert(pkg, crate_id); 70 pkg_to_lib_crate.insert(pkg, crate_id);
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index cf5cfecc2..22105d6c9 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
6 6
7pub use self::generated::*; 7pub use self::generated::*;
8use crate::{ 8use crate::{
9 yellow::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes}, 9 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes},
10 SmolStr, 10 SmolStr,
11 SyntaxKind::*, 11 SyntaxKind::*,
12}; 12};
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index d2b080743..7c5e8ce5e 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -13,7 +13,7 @@ use rowan::TransparentNewType;
13 13
14use crate::{ 14use crate::{
15 SyntaxNode, SyntaxKind::*, 15 SyntaxNode, SyntaxKind::*,
16 yellow::{RaTypes, TreeArc}, 16 syntax_node::{RaTypes, TreeArc},
17 ast::{self, AstNode}, 17 ast::{self, AstNode},
18}; 18};
19 19
@@ -4210,6 +4210,7 @@ impl ToOwned for UseItem {
4210} 4210}
4211 4211
4212 4212
4213impl ast::AttrsOwner for UseItem {}
4213impl UseItem { 4214impl UseItem {
4214 pub fn use_tree(&self) -> Option<&UseTree> { 4215 pub fn use_tree(&self) -> Option<&UseTree> {
4215 super::child_opt(self) 4216 super::child_opt(self)
diff --git a/crates/ra_syntax/src/ast/generated.rs.tera b/crates/ra_syntax/src/ast/generated.rs.tera
index ea0fc35fd..ca7a28581 100644
--- a/crates/ra_syntax/src/ast/generated.rs.tera
+++ b/crates/ra_syntax/src/ast/generated.rs.tera
@@ -15,7 +15,7 @@ use rowan::TransparentNewType;
15 15
16use crate::{ 16use crate::{
17 SyntaxNode, SyntaxKind::*, 17 SyntaxNode, SyntaxKind::*,
18 yellow::{RaTypes, TreeArc}, 18 syntax_node::{RaTypes, TreeArc},
19 ast::{self, AstNode}, 19 ast::{self, AstNode},
20}; 20};
21{% for node, methods in ast %} 21{% for node, methods in ast %}
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 2e4b2d776..304bc5909 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -596,7 +596,8 @@ Grammar(
596 options: [ "Pat", "TypeRef" ], 596 options: [ "Pat", "TypeRef" ],
597 ), 597 ),
598 "UseItem": ( 598 "UseItem": (
599 options: [ "UseTree" ] 599 traits: ["AttrsOwner"],
600 options: [ "UseTree" ],
600 ), 601 ),
601 "UseTree": ( 602 "UseTree": (
602 options: [ "Path", "UseTreeList", "Alias" ] 603 options: [ "Path", "UseTreeList", "Alias" ]
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 088b2f5d7..cbba1d4ae 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -30,7 +30,7 @@ mod syntax_kinds;
30/// Utilities for simple uses of the parser. 30/// Utilities for simple uses of the parser.
31pub mod utils; 31pub mod utils;
32mod validation; 32mod validation;
33mod yellow; 33mod syntax_node;
34mod ptr; 34mod ptr;
35 35
36pub use rowan::{SmolStr, TextRange, TextUnit}; 36pub use rowan::{SmolStr, TextRange, TextUnit};
@@ -38,12 +38,12 @@ pub use crate::{
38 ast::AstNode, 38 ast::AstNode,
39 lexer::{tokenize, Token}, 39 lexer::{tokenize, Token},
40 syntax_kinds::SyntaxKind, 40 syntax_kinds::SyntaxKind,
41 yellow::{Direction, SyntaxError, SyntaxNode, WalkEvent, Location, TreeArc}, 41 syntax_node::{Direction, SyntaxError, SyntaxNode, WalkEvent, Location, TreeArc},
42 ptr::{SyntaxNodePtr, AstPtr}, 42 ptr::{SyntaxNodePtr, AstPtr},
43}; 43};
44 44
45use ra_text_edit::AtomTextEdit; 45use ra_text_edit::AtomTextEdit;
46use crate::yellow::GreenNode; 46use crate::syntax_node::GreenNode;
47 47
48/// `SourceFile` represents a parse tree for a single Rust file. 48/// `SourceFile` represents a parse tree for a single Rust file.
49pub use crate::ast::SourceFile; 49pub use crate::ast::SourceFile;
@@ -61,7 +61,7 @@ impl SourceFile {
61 pub fn parse(text: &str) -> TreeArc<SourceFile> { 61 pub fn parse(text: &str) -> TreeArc<SourceFile> {
62 let tokens = tokenize(&text); 62 let tokens = tokenize(&text);
63 let (green, errors) = 63 let (green, errors) =
64 parser_impl::parse_with(yellow::GreenBuilder::new(), text, &tokens, grammar::root); 64 parser_impl::parse_with(syntax_node::GreenBuilder::new(), text, &tokens, grammar::root);
65 SourceFile::new(green, errors) 65 SourceFile::new(green, errors)
66 } 66 }
67 67
diff --git a/crates/ra_syntax/src/parser_impl.rs b/crates/ra_syntax/src/parser_impl.rs
index f255dc23b..d99615d72 100644
--- a/crates/ra_syntax/src/parser_impl.rs
+++ b/crates/ra_syntax/src/parser_impl.rs
@@ -11,7 +11,7 @@ use crate::{
11 input::{InputPosition, ParserInput}, 11 input::{InputPosition, ParserInput},
12 }, 12 },
13 SmolStr, 13 SmolStr,
14 yellow::syntax_error::{ 14 syntax_node::syntax_error::{
15 ParseError, 15 ParseError,
16 SyntaxError, 16 SyntaxError,
17 }, 17 },
diff --git a/crates/ra_syntax/src/parser_impl/event.rs b/crates/ra_syntax/src/parser_impl/event.rs
index 677876ab5..b45830c61 100644
--- a/crates/ra_syntax/src/parser_impl/event.rs
+++ b/crates/ra_syntax/src/parser_impl/event.rs
@@ -13,7 +13,7 @@ use crate::{
13 SmolStr, 13 SmolStr,
14 SyntaxKind::{self, *}, 14 SyntaxKind::{self, *},
15 TextRange, TextUnit, 15 TextRange, TextUnit,
16 yellow::syntax_error::{ 16 syntax_node::syntax_error::{
17 ParseError, 17 ParseError,
18 SyntaxError, 18 SyntaxError,
19 SyntaxErrorKind, 19 SyntaxErrorKind,
diff --git a/crates/ra_syntax/src/reparsing.rs b/crates/ra_syntax/src/reparsing.rs
index c5c609ad5..dd751465c 100644
--- a/crates/ra_syntax/src/reparsing.rs
+++ b/crates/ra_syntax/src/reparsing.rs
@@ -3,7 +3,7 @@ use crate::grammar;
3use crate::lexer::{tokenize, Token}; 3use crate::lexer::{tokenize, Token};
4use crate::parser_api::Parser; 4use crate::parser_api::Parser;
5use crate::parser_impl; 5use crate::parser_impl;
6use crate::yellow::{self, GreenNode, SyntaxError, SyntaxNode}; 6use crate::syntax_node::{self, GreenNode, SyntaxError, SyntaxNode};
7use crate::{SyntaxKind::*, TextRange, TextUnit}; 7use crate::{SyntaxKind::*, TextRange, TextUnit};
8use ra_text_edit::AtomTextEdit; 8use ra_text_edit::AtomTextEdit;
9 9
@@ -56,7 +56,7 @@ fn reparse_block<'node>(
56 return None; 56 return None;
57 } 57 }
58 let (green, new_errors) = 58 let (green, new_errors) =
59 parser_impl::parse_with(yellow::GreenBuilder::new(), &text, &tokens, reparser); 59 parser_impl::parse_with(syntax_node::GreenBuilder::new(), &text, &tokens, reparser);
60 Some((node, green, new_errors)) 60 Some((node, green, new_errors))
61} 61}
62 62
diff --git a/crates/ra_syntax/src/yellow.rs b/crates/ra_syntax/src/syntax_node.rs
index ed48739f8..ed48739f8 100644
--- a/crates/ra_syntax/src/yellow.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
diff --git a/crates/ra_syntax/src/yellow/builder.rs b/crates/ra_syntax/src/syntax_node/builder.rs
index e8b9112d4..8abd0f051 100644
--- a/crates/ra_syntax/src/yellow/builder.rs
+++ b/crates/ra_syntax/src/syntax_node/builder.rs
@@ -1,6 +1,6 @@
1use crate::{ 1use crate::{
2 parser_impl::Sink, 2 parser_impl::Sink,
3 yellow::{GreenNode, RaTypes, SyntaxError}, 3 syntax_node::{GreenNode, RaTypes, SyntaxError},
4 SmolStr, SyntaxKind, 4 SmolStr, SyntaxKind,
5}; 5};
6use rowan::GreenNodeBuilder; 6use rowan::GreenNodeBuilder;
diff --git a/crates/ra_syntax/src/yellow/syntax_error.rs b/crates/ra_syntax/src/syntax_node/syntax_error.rs
index 412cf82cc..412cf82cc 100644
--- a/crates/ra_syntax/src/yellow/syntax_error.rs
+++ b/crates/ra_syntax/src/syntax_node/syntax_error.rs
diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/syntax_node/syntax_text.rs
index 84e5b231a..84e5b231a 100644
--- a/crates/ra_syntax/src/yellow/syntax_text.rs
+++ b/crates/ra_syntax/src/syntax_node/syntax_text.rs
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index ac6cc3dd6..10672d6bf 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -5,7 +5,7 @@ mod string;
5mod block; 5mod block;
6 6
7use crate::{ 7use crate::{
8 SourceFile, yellow::SyntaxError, AstNode, 8 SourceFile, syntax_node::SyntaxError, AstNode,
9 ast, 9 ast,
10 algo::visit::{visitor_ctx, VisitorCtx}, 10 algo::visit::{visitor_ctx, VisitorCtx},
11}; 11};
diff --git a/crates/ra_syntax/src/validation/block.rs b/crates/ra_syntax/src/validation/block.rs
index 4e77c15b6..de949d967 100644
--- a/crates/ra_syntax/src/validation/block.rs
+++ b/crates/ra_syntax/src/validation/block.rs
@@ -1,6 +1,6 @@
1use crate::{SyntaxKind::*, 1use crate::{SyntaxKind::*,
2 ast::{self, AttrsOwner, AstNode}, 2 ast::{self, AttrsOwner, AstNode},
3 yellow::{ 3 syntax_node::{
4 SyntaxError, 4 SyntaxError,
5 SyntaxErrorKind::*, 5 SyntaxErrorKind::*,
6 }, 6 },
diff --git a/crates/ra_syntax/src/validation/byte.rs b/crates/ra_syntax/src/validation/byte.rs
index d51fabcf9..acdc12552 100644
--- a/crates/ra_syntax/src/validation/byte.rs
+++ b/crates/ra_syntax/src/validation/byte.rs
@@ -5,7 +5,7 @@ use crate::{
5 string_lexing::{self, StringComponentKind}, 5 string_lexing::{self, StringComponentKind},
6 TextRange, 6 TextRange,
7 validation::char, 7 validation::char,
8 yellow::{ 8 syntax_node::{
9 SyntaxError, 9 SyntaxError,
10 SyntaxErrorKind::*, 10 SyntaxErrorKind::*,
11 }, 11 },
diff --git a/crates/ra_syntax/src/validation/byte_string.rs b/crates/ra_syntax/src/validation/byte_string.rs
index 7abe8f330..69a98b640 100644
--- a/crates/ra_syntax/src/validation/byte_string.rs
+++ b/crates/ra_syntax/src/validation/byte_string.rs
@@ -1,7 +1,7 @@
1use crate::{ 1use crate::{
2 ast::{self, AstNode, AstToken}, 2 ast::{self, AstNode, AstToken},
3 string_lexing::{self, StringComponentKind}, 3 string_lexing::{self, StringComponentKind},
4 yellow::{ 4 syntax_node::{
5 SyntaxError, 5 SyntaxError,
6 SyntaxErrorKind::*, 6 SyntaxErrorKind::*,
7 }, 7 },
diff --git a/crates/ra_syntax/src/validation/char.rs b/crates/ra_syntax/src/validation/char.rs
index 012594db3..26c15e36d 100644
--- a/crates/ra_syntax/src/validation/char.rs
+++ b/crates/ra_syntax/src/validation/char.rs
@@ -8,7 +8,7 @@ use crate::{
8 ast::{self, AstNode, AstToken}, 8 ast::{self, AstNode, AstToken},
9 string_lexing::{self, StringComponentKind}, 9 string_lexing::{self, StringComponentKind},
10 TextRange, 10 TextRange,
11 yellow::{ 11 syntax_node::{
12 SyntaxError, 12 SyntaxError,
13 SyntaxErrorKind::*, 13 SyntaxErrorKind::*,
14 }, 14 },
diff --git a/crates/ra_syntax/src/validation/string.rs b/crates/ra_syntax/src/validation/string.rs
index 4fd7fffdf..2f7f9c7c4 100644
--- a/crates/ra_syntax/src/validation/string.rs
+++ b/crates/ra_syntax/src/validation/string.rs
@@ -1,7 +1,7 @@
1use crate::{ 1use crate::{
2 ast::{self, AstNode, AstToken}, 2 ast::{self, AstNode, AstToken},
3 string_lexing, 3 string_lexing,
4 yellow::{ 4 syntax_node::{
5 SyntaxError, 5 SyntaxError,
6 SyntaxErrorKind::*, 6 SyntaxErrorKind::*,
7 }, 7 },
diff --git a/crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs b/crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs
index 59cd11495..e0437d163 100644
--- a/crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs
+++ b/crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs
@@ -5,7 +5,7 @@
5 } 5 }
6 pub fn parse(text: &str) -> File { 6 pub fn parse(text: &str) -> File {
7 let tokens = tokenize(&text); 7 let tokens = tokenize(&text);
8 let (green, errors) = parser_impl::parse_with::<yellow::GreenBuilder>( 8 let (green, errors) = parser_impl::parse_with::<syntax_node::GreenBuilder>(
9 text, &tokens, grammar::root, 9 text, &tokens, grammar::root,
10 ); 10 );
11 File::new(green, errors) 11 File::new(green, errors)
@@ -24,7 +24,7 @@
24 if !is_balanced(&tokens) { 24 if !is_balanced(&tokens) {
25 return None; 25 return None;
26 } 26 }
27 let (green, new_errors) = parser_impl::parse_with::<yellow::GreenBuilder>( 27 let (green, new_errors) = parser_impl::parse_with::<syntax_node::GreenBuilder>(
28 &te2t, &tokens, reparser, 28 &te2t, &tokens, reparser,
29 ); 29 );
30 let green_root = node.replace_with(green); 30 let green_root = node.replace_with(green);
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index c1f37b889..0b0b9b4d2 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -33,14 +33,14 @@ impl TokenId {
33 } 33 }
34} 34}
35 35
36#[derive(Debug, Clone)] 36#[derive(Debug, Clone, PartialEq, Eq)]
37pub enum TokenTree { 37pub enum TokenTree {
38 Leaf(Leaf), 38 Leaf(Leaf),
39 Subtree(Subtree), 39 Subtree(Subtree),
40} 40}
41impl_froms!(TokenTree: Leaf, Subtree); 41impl_froms!(TokenTree: Leaf, Subtree);
42 42
43#[derive(Debug, Clone)] 43#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum Leaf { 44pub enum Leaf {
45 Literal(Literal), 45 Literal(Literal),
46 Punct(Punct), 46 Punct(Punct),
@@ -48,7 +48,7 @@ pub enum Leaf {
48} 48}
49impl_froms!(Leaf: Literal, Punct, Ident); 49impl_froms!(Leaf: Literal, Punct, Ident);
50 50
51#[derive(Debug, Clone)] 51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct Subtree { 52pub struct Subtree {
53 pub delimiter: Delimiter, 53 pub delimiter: Delimiter,
54 pub token_trees: Vec<TokenTree>, 54 pub token_trees: Vec<TokenTree>,
@@ -62,7 +62,7 @@ pub enum Delimiter {
62 None, 62 None,
63} 63}
64 64
65#[derive(Debug, Clone)] 65#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct Literal { 66pub struct Literal {
67 pub text: SmolStr, 67 pub text: SmolStr,
68} 68}
@@ -79,7 +79,7 @@ pub enum Spacing {
79 Joint, 79 Joint,
80} 80}
81 81
82#[derive(Debug, Clone)] 82#[derive(Debug, Clone, PartialEq, Eq)]
83pub struct Ident { 83pub struct Ident {
84 pub text: SmolStr, 84 pub text: SmolStr,
85 pub id: TokenId, 85 pub id: TokenId,
diff --git a/crates/ra_vfs/src/io.rs b/crates/ra_vfs/src/io.rs
index dc0b84d5a..3952b200b 100644
--- a/crates/ra_vfs/src/io.rs
+++ b/crates/ra_vfs/src/io.rs
@@ -169,7 +169,7 @@ fn convert_notify_event(event: DebouncedEvent, sender: &Sender<(PathBuf, ChangeK
169 // ignore 169 // ignore
170 } 170 }
171 DebouncedEvent::Rescan => { 171 DebouncedEvent::Rescan => {
172 // TODO rescan all roots 172 // TODO: rescan all roots
173 } 173 }
174 DebouncedEvent::Create(path) => { 174 DebouncedEvent::Create(path) => {
175 sender.send((path, ChangeKind::Create)).unwrap(); 175 sender.send((path, ChangeKind::Create)).unwrap();
@@ -185,7 +185,7 @@ fn convert_notify_event(event: DebouncedEvent, sender: &Sender<(PathBuf, ChangeK
185 sender.send((dst, ChangeKind::Create)).unwrap(); 185 sender.send((dst, ChangeKind::Create)).unwrap();
186 } 186 }
187 DebouncedEvent::Error(err, path) => { 187 DebouncedEvent::Error(err, path) => {
188 // TODO should we reload the file contents? 188 // TODO: should we reload the file contents?
189 log::warn!("watcher error \"{}\", {:?}", err, path); 189 log::warn!("watcher error \"{}\", {:?}", err, path);
190 } 190 }
191 } 191 }
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs
index d589a254b..f07657db6 100644
--- a/crates/ra_vfs/src/lib.rs
+++ b/crates/ra_vfs/src/lib.rs
@@ -7,8 +7,10 @@
7//! 7//!
8//! It is also responsible for watching the disk for changes, and for merging 8//! It is also responsible for watching the disk for changes, and for merging
9//! editor state (modified, unsaved files) with disk state. 9//! editor state (modified, unsaved files) with disk state.
10//! TODO: Some LSP clients support watching the disk, so this crate should 10//!
11//! to support custom watcher events (related to https://github.com/rust-analyzer/rust-analyzer/issues/131) 11//! TODO: Some LSP clients support watching the disk, so this crate should to
12//! support custom watcher events (related to
13//! <https://github.com/rust-analyzer/rust-analyzer/issues/131>)
12//! 14//!
13//! VFS is based on a concept of roots: a set of directories on the file system 15//! VFS is based on a concept of roots: a set of directories on the file system
14//! which are watched for changes. Typically, there will be a root for each 16//! which are watched for changes. Typically, there will be a root for each
@@ -225,12 +227,12 @@ impl Vfs {
225 let mut cur_files = Vec::new(); 227 let mut cur_files = Vec::new();
226 // While we were scanning the root in the background, a file might have 228 // While we were scanning the root in the background, a file might have
227 // been open in the editor, so we need to account for that. 229 // been open in the editor, so we need to account for that.
228 let exising = self.root2files[root] 230 let existing = self.root2files[root]
229 .iter() 231 .iter()
230 .map(|&file| (self.files[file].path.clone(), file)) 232 .map(|&file| (self.files[file].path.clone(), file))
231 .collect::<FxHashMap<_, _>>(); 233 .collect::<FxHashMap<_, _>>();
232 for (path, text) in files { 234 for (path, text) in files {
233 if let Some(&file) = exising.get(&path) { 235 if let Some(&file) = existing.get(&path) {
234 let text = Arc::clone(&self.files[file].text); 236 let text = Arc::clone(&self.files[file].text);
235 cur_files.push((file, path, text)); 237 cur_files.push((file, path, text));
236 continue; 238 continue;
@@ -335,7 +337,7 @@ impl Vfs {
335 mem::replace(&mut self.pending_changes, Vec::new()) 337 mem::replace(&mut self.pending_changes, Vec::new())
336 } 338 }
337 339
338 /// Sutdown the VFS and terminate the background watching thread. 340 /// Shutdown the VFS and terminate the background watching thread.
339 pub fn shutdown(self) -> thread::Result<()> { 341 pub fn shutdown(self) -> thread::Result<()> {
340 self.worker.shutdown() 342 self.worker.shutdown()
341 } 343 }
@@ -360,7 +362,7 @@ impl Vfs {
360 } 362 }
361 363
362 fn remove_file(&mut self, file: VfsFile) { 364 fn remove_file(&mut self, file: VfsFile) {
363 //FIXME: use arena with removal 365 // FIXME: use arena with removal
364 self.files[file].text = Default::default(); 366 self.files[file].text = Default::default();
365 self.files[file].path = Default::default(); 367 self.files[file].path = Default::default();
366 let root = self.files[file].root; 368 let root = self.files[file].root;
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 09fc2e659..4d83af00c 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -113,9 +113,9 @@ pub struct FixtureEntry {
113 pub text: String, 113 pub text: String,
114} 114}
115 115
116/// Parses text wich looks like this: 116/// Parses text which looks like this:
117/// 117///
118/// ```notrust 118/// ```rust,ignore
119/// //- some meta 119/// //- some meta
120/// line 1 120/// line 1
121/// line 2 121/// line 2
diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/marks.rs
index d2a84643c..107432926 100644
--- a/crates/test_utils/src/marks.rs
+++ b/crates/test_utils/src/marks.rs
@@ -1,10 +1,10 @@
1//! This module implements manually tracked test coverage, which useful for 1//! This module implements manually tracked test coverage, which useful for
2//! quickly finding a test responsible for testing a particular bit of code. 2//! quickly finding a test responsible for testing a particular bit of code.
3//! 3//!
4//! See https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html 4//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html>
5//! for details, but the TL;DR is that you write your test as 5//! for details, but the TL;DR is that you write your test as
6//! 6//!
7//! ```no-run 7//! ```rust,no_run
8//! #[test] 8//! #[test]
9//! fn test_foo() { 9//! fn test_foo() {
10//! covers!(test_foo); 10//! covers!(test_foo);
@@ -13,7 +13,9 @@
13//! 13//!
14//! and in the code under test you write 14//! and in the code under test you write
15//! 15//!
16//! ```no-run 16//! ```rust,no_run
17//! # use test_utils::tested_by;
18//! # fn some_condition() -> bool { true }
17//! fn foo() { 19//! fn foo() {
18//! if some_condition() { 20//! if some_condition() {
19//! tested_by!(test_foo); 21//! tested_by!(test_foo);
diff --git a/crates/thread_worker/src/lib.rs b/crates/thread_worker/src/lib.rs
index ca0aad136..a522a0843 100644
--- a/crates/thread_worker/src/lib.rs
+++ b/crates/thread_worker/src/lib.rs
@@ -65,7 +65,7 @@ impl WorkerHandle {
65 } 65 }
66} 66}
67 67
68/// Sets up worker channels in a deadlock-avoind way. 68/// Sets up worker channels in a deadlock-avoiding way.
69/// If one sets both input and output buffers to a fixed size, 69/// If one sets both input and output buffers to a fixed size,
70/// a worker might get stuck. 70/// a worker might get stuck.
71fn worker_chan<I, O>(buf: usize) -> (Worker<I, O>, Receiver<I>, Sender<O>) { 71fn worker_chan<I, O>(buf: usize) -> (Worker<I, O>, Receiver<I>, Sender<O>) {
diff --git a/editors/README.md b/editors/README.md
index eb1004914..6e1189cad 100644
--- a/editors/README.md
+++ b/editors/README.md
@@ -5,6 +5,9 @@ In 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
6[node.js and npm documentation](https://nodejs.org) for installation instructions. 6[node.js and npm documentation](https://nodejs.org) for installation instructions.
7 7
8You will also need the most recent version of VS Code: we don't try to
9maintain compatibility with older versions yet.
10
8The experimental VS Code plugin can then be built and installed by executing the 11The experimental VS Code plugin can then be built and installed by executing the
9following commands: 12following commands:
10 13
diff --git a/editors/code/package.json b/editors/code/package.json
index 045d372e7..4fc2cb754 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -13,7 +13,7 @@
13 "Other" 13 "Other"
14 ], 14 ],
15 "engines": { 15 "engines": {
16 "vscode": "^1.30.0" 16 "vscode": "^1.31.0"
17 }, 17 },
18 "scripts": { 18 "scripts": {
19 "vscode:prepublish": "npm run compile", 19 "vscode:prepublish": "npm run compile",