diff options
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" | |||
5 | version = "0.6.9" | 5 | version = "0.6.9" |
6 | source = "registry+https://github.com/rust-lang/crates.io-index" | 6 | source = "registry+https://github.com/rust-lang/crates.io-index" |
7 | dependencies = [ | 7 | dependencies = [ |
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]] |
669 | name = "memchr" | 669 | name = "memchr" |
670 | version = "2.1.3" | 670 | version = "2.2.0" |
671 | source = "registry+https://github.com/rust-lang/crates.io-index" | 671 | source = "registry+https://github.com/rust-lang/crates.io-index" |
672 | dependencies = [ | ||
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]] |
678 | name = "memmap" | 674 | name = "memmap" |
@@ -786,7 +782,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
786 | 782 | ||
787 | [[package]] | 783 | [[package]] |
788 | name = "num_cpus" | 784 | name = "num_cpus" |
789 | version = "1.9.0" | 785 | version = "1.10.0" |
790 | source = "registry+https://github.com/rust-lang/crates.io-index" | 786 | source = "registry+https://github.com/rust-lang/crates.io-index" |
791 | dependencies = [ | 787 | dependencies = [ |
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" | |||
1296 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1297 | dependencies = [ | 1293 | dependencies = [ |
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]] |
1532 | name = "superslice" | 1528 | name = "superslice" |
1533 | version = "0.1.0" | 1529 | version = "1.0.0" |
1534 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1535 | 1531 | ||
1536 | [[package]] | 1532 | [[package]] |
@@ -1664,7 +1660,7 @@ name = "threadpool" | |||
1664 | version = "1.7.1" | 1660 | version = "1.7.1" |
1665 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1666 | dependencies = [ | 1662 | dependencies = [ |
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" |
@@ -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 | ||
5 | Rust Analyzer is an **experimental** modular compiler frontend for the Rust | 5 | Rust Analyzer is an **experimental** modular compiler frontend for the Rust |
6 | language, which aims to lay a foundation for excellent IDE support. | 6 | language. It is a part of a larger rls-2.0 effort to create excellent IDE |
7 | support for Rust. If you want to get involved, check rls-2.0 working group repository: | ||
7 | 8 | ||
8 | It doesn't implement much of compiler functionality yet, but the white-space | 9 | https://github.com/rust-analyzer/WG-rls2.0 |
9 | preserving Rust parser works, and there are significant chunks of overall | ||
10 | architecture (indexing, on-demand & lazy computation, snapshotable world view) | ||
11 | in place. Some basic IDE functionality is provided via a language server. | ||
12 | 10 | ||
13 | Work on the Rust Analyzer is sponsored by | 11 | Work on the Rust Analyzer is sponsored by |
14 | 12 | ||
@@ -41,37 +39,15 @@ features (some of which are VS Code specific). | |||
41 | 39 | ||
42 | See [these instructions](./DEBUGGING.md) on how to debug the vscode extension and the lsp server. | 40 | See [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 | |||
46 | Rust analyzer aims to fill the same niche as the official [Rust Language | ||
47 | Server](https://github.com/rust-lang-nursery/rls), but uses a significantly | ||
48 | different architecture. More details can be found [in this | ||
49 | thread](https://internals.rust-lang.org/t/2019-strategy-for-rustc-and-the-rls/8361), | ||
50 | but the core issue is that RLS works in the "wait until user stops typing, run | ||
51 | the build process, save the results of the analysis" mode, which arguably is the | ||
52 | wrong foundation for IDE. | ||
53 | |||
54 | Rust Analyzer is an experimental project at the moment, there's exactly zero | ||
55 | guarantees that it becomes production-ready one day. | ||
56 | 43 | ||
57 | The near/mid term plan is to work independently of the main rustc compiler and | 44 | We are on the rust-lang Zulip! |
58 | implement at least simplistic versions of name resolution, macro expansion and | ||
59 | type inference. The purpose is two fold: | ||
60 | 45 | ||
61 | - to quickly bootstrap usable and useful language server: solution that covers | 46 | https://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 | ||
71 | The long term plan is to merge with the mainline rustc compiler, probably around | 50 | See [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHITECTURE.md](./ARCHITECTURE.md) |
72 | the HIR boundary? That is, use rust analyzer for parsing, macro expansion and | ||
73 | related bits of name resolution, but leave the rest (including type inference | ||
74 | and 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 | |||
151 | We have a Discord server dedicated to compilers and language servers | ||
152 | implemented in Rust: [https://discord.gg/sx3RQZB](https://discord.gg/sx3RQZB). | ||
153 | |||
154 | ## Contributing | ||
155 | |||
156 | See [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHITECTURE.md](./ARCHITECTURE.md) | ||
157 | |||
158 | ## License | 125 | ## License |
159 | 126 | ||
160 | Rust analyzer is primarily distributed under the terms of both the MIT | 127 | Rust 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 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 2 | use 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 | }; |
6 | use crate::assist_ctx::{AssistCtx, Assist, AssistBuilder}; | 6 | use 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 | ||
483 | fn 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 | |||
483 | pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 501 | pub(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 | " | ||
559 | std::fmt<|>::Debug | ||
560 | ", | ||
561 | " | ||
562 | use std::fmt; | ||
563 | |||
564 | fmt<|>::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 | " | ||
772 | use 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 | " | ||
782 | mod foo { | ||
783 | mod bar { | ||
784 | std::fmt::Debug<|> | ||
785 | } | ||
786 | } | ||
787 | ", | ||
788 | " | ||
789 | mod 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)] |
20 | pub struct Canceled { | 20 | pub 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)] |
57 | pub struct CrateId(pub u32); | 57 | pub struct CrateId(pub u32); |
58 | 58 | ||
59 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
60 | pub enum Edition { | ||
61 | Edition2018, | ||
62 | Edition2015, | ||
63 | } | ||
64 | |||
65 | impl 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)] |
60 | struct CrateData { | 75 | struct CrateData { |
61 | file_id: FileId, | 76 | file_id: FileId, |
77 | edition: Edition, | ||
62 | dependencies: Vec<Dependency>, | 78 | dependencies: Vec<Dependency>, |
63 | } | 79 | } |
64 | 80 | ||
65 | impl CrateData { | 81 | impl 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 | ||
87 | impl CrateGraph { | 103 | impl 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)] |
161 | mod tests { | 181 | mod 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; | |||
14 | pub use crate::{ | 14 | pub 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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use relative_path::RelativePathBuf; | 3 | use relative_path::RelativePathBuf; |
4 | use ra_db::{CrateId, FileId, SourceRootId}; | 4 | use ra_db::{CrateId, FileId, SourceRootId, Edition}; |
5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; | 5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; |
6 | 6 | ||
7 | use crate::{ | 7 | use 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)] |
62 | pub struct HirFileId(HirFileIdRepr); | 62 | pub struct HirFileId(HirFileIdRepr); |
63 | 63 | ||
64 | impl HirFileId { | 64 | impl 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)] |
71 | pub struct MacroInput { | 71 | pub 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}; | |||
3 | use parking_lot::Mutex; | 3 | use parking_lot::Mutex; |
4 | use ra_db::{ | 4 | use ra_db::{ |
5 | FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa, | 5 | FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa, |
6 | Edition, | ||
6 | }; | 7 | }; |
7 | use relative_path::RelativePathBuf; | 8 | use relative_path::RelativePathBuf; |
8 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; | 9 | use 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)] |
235 | pub struct CrateGraphFixture(pub FxHashMap<String, (String, Vec<String>)>); | 236 | pub struct CrateGraphFixture(pub FxHashMap<String, (String, Edition, Vec<String>)>); |
236 | 237 | ||
237 | #[macro_export] | 238 | #[macro_export] |
238 | macro_rules! crate_graph { | 239 | macro_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 | ||
19 | use std::{time, sync::Arc}; | 19 | use std::{time, sync::Arc}; |
20 | 20 | ||
21 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
22 | |||
21 | use ra_arena::map::ArenaMap; | 23 | use ra_arena::map::ArenaMap; |
24 | use ra_db::Edition; | ||
22 | use test_utils::tested_by; | 25 | use test_utils::tested_by; |
23 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
24 | 26 | ||
25 | use crate::{ | 27 | use 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)] |
36 | pub struct ItemMap { | 38 | pub 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)] |
439 | enum ResolveMode { | ||
440 | Import, | ||
441 | Other, | ||
442 | } | ||
443 | |||
444 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
407 | enum ReachedFixedPoint { | 445 | enum 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 | ||
3 | use ra_syntax::{ | 3 | use 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 | }; |
7 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 7 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
8 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHashMap; |
9 | 9 | ||
10 | use crate::{ | 10 | use 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] |
269 | fn 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] | ||
269 | fn module_resolution_works_for_non_standard_filenames() { | 308 | fn 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] |
339 | fn 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] | ||
300 | fn name_res_works_for_broken_modules() { | 376 | fn 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] |
546 | fn 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] | ||
470 | fn import_across_source_roots() { | 582 | fn 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 | ||
58 | impl Resolver { | 58 | impl 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 | ||
145 | impl Scope { | 145 | impl 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 | --- | ||
2 | created: "2019-02-11T21:59:04.302375838Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&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] | ||
723 | fn infer_nested_generics_crash() { | ||
724 | // another crash found typechecking rustc | ||
725 | check_inference( | ||
726 | "infer_nested_generics_crash", | ||
727 | r#" | ||
728 | struct Canonical<V> { | ||
729 | value: V, | ||
730 | } | ||
731 | struct QueryResponse<V> { | ||
732 | value: V, | ||
733 | } | ||
734 | fn test<R>(query_response: Canonical<QueryResponse<R>>) { | ||
735 | &query_response.value; | ||
736 | } | ||
737 | "#, | ||
738 | ); | ||
739 | } | ||
740 | |||
722 | fn infer(content: &str) -> String { | 741 | fn 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 | ||
8 | use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem}; | 8 | use 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 | --- | ||
2 | created: "2019-02-13T19:52:43.734834624Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | ||
5 | expression: 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 | --- | ||
2 | created: "2019-02-12T18:32:09.428929418Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | ||
5 | expression: 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`. |
76 | fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> { | 76 | fn 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( | |||
78 | mod tests { | 78 | mod 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 | }; |
64 | pub use ra_db::{ | 64 | pub use ra_db::{ |
65 | Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId | 65 | Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId, |
66 | Edition | ||
66 | }; | 67 | }; |
67 | pub use hir::Documentation; | 68 | pub 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] |
73 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; | 74 | static 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; | |||
3 | use relative_path::RelativePathBuf; | 3 | use relative_path::RelativePathBuf; |
4 | use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; | 4 | use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; |
5 | 5 | ||
6 | use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId}; | 6 | use 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 | ||
24 | impl NavigationTarget { | 25 | impl 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. |
22 | use std::{ | 22 | use 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 | }; |
36 | use ra_db::{ | 37 | use ra_db::{ |
37 | SourceRootId, SourceDatabase, | 38 | SourceRootId, SourceDatabase, |
@@ -62,17 +63,14 @@ pub(crate) trait SymbolsDatabase: hir::db::HirDatabase { | |||
62 | fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { | 63 | fn 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 | |||
213 | fn 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 | ||
220 | fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> { | 239 | fn 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 | |||
258 | fn 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 @@ | |||
1 | use insta::assert_debug_snapshot_matches; | 1 | use insta::assert_debug_snapshot_matches; |
2 | use ra_ide_api::{ | 2 | use 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 | }; |
6 | use ra_syntax::TextRange; | 6 | use ra_syntax::{TextRange, SmolStr}; |
7 | 7 | ||
8 | #[test] | 8 | #[test] |
9 | fn test_unresolved_module_diagnostic() { | 9 | fn 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 | ||
52 | fn 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] |
53 | fn test_find_all_refs_for_local() { | 58 | fn 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] |
99 | fn 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] | ||
113 | fn test_world_symbols_include_container_name() { | ||
114 | let code = r#" | ||
115 | fn 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#" | ||
128 | mod 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] |
95 | fn world_symbols_include_stuff_from_macros() { | 143 | fn 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] |
9 | itertools = "0.8.0" | 9 | itertools = "0.8.0" |
10 | superslice = "0.1.0" | 10 | superslice = "1.0.0" |
11 | join_to_string = "0.1.1" | 11 | join_to_string = "0.1.1" |
12 | rustc-hash = "1.0" | 12 | rustc-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}; | |||
4 | use ra_arena::{Arena, RawId, impl_arena_id}; | 4 | use ra_arena::{Arena, RawId, impl_arena_id}; |
5 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
6 | use failure::format_err; | 6 | use failure::format_err; |
7 | use ra_db::Edition; | ||
7 | 8 | ||
8 | use crate::Result; | 9 | use 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)] |
18 | pub struct CargoWorkspace { | 19 | pub 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}; | |||
6 | use failure::bail; | 6 | use failure::bail; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | 8 | ||
9 | use ra_db::{CrateGraph, FileId}; | 9 | use ra_db::{CrateGraph, FileId, Edition}; |
10 | 10 | ||
11 | pub use crate::{ | 11 | pub 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 | ||
7 | pub use self::generated::*; | 7 | pub use self::generated::*; |
8 | use crate::{ | 8 | use 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 | ||
14 | use crate::{ | 14 | use 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 | ||
4213 | impl ast::AttrsOwner for UseItem {} | ||
4213 | impl UseItem { | 4214 | impl 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 | ||
16 | use crate::{ | 16 | use 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. |
31 | pub mod utils; | 31 | pub mod utils; |
32 | mod validation; | 32 | mod validation; |
33 | mod yellow; | 33 | mod syntax_node; |
34 | mod ptr; | 34 | mod ptr; |
35 | 35 | ||
36 | pub use rowan::{SmolStr, TextRange, TextUnit}; | 36 | pub 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 | ||
45 | use ra_text_edit::AtomTextEdit; | 45 | use ra_text_edit::AtomTextEdit; |
46 | use crate::yellow::GreenNode; | 46 | use 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. |
49 | pub use crate::ast::SourceFile; | 49 | pub 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; | |||
3 | use crate::lexer::{tokenize, Token}; | 3 | use crate::lexer::{tokenize, Token}; |
4 | use crate::parser_api::Parser; | 4 | use crate::parser_api::Parser; |
5 | use crate::parser_impl; | 5 | use crate::parser_impl; |
6 | use crate::yellow::{self, GreenNode, SyntaxError, SyntaxNode}; | 6 | use crate::syntax_node::{self, GreenNode, SyntaxError, SyntaxNode}; |
7 | use crate::{SyntaxKind::*, TextRange, TextUnit}; | 7 | use crate::{SyntaxKind::*, TextRange, TextUnit}; |
8 | use ra_text_edit::AtomTextEdit; | 8 | use 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 @@ | |||
1 | use crate::{ | 1 | use 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 | }; |
6 | use rowan::GreenNodeBuilder; | 6 | use 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; | |||
5 | mod block; | 5 | mod block; |
6 | 6 | ||
7 | use crate::{ | 7 | use 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 @@ | |||
1 | use crate::{SyntaxKind::*, | 1 | use 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 @@ | |||
1 | use crate::{ | 1 | use 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 @@ | |||
1 | use crate::{ | 1 | use 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)] |
37 | pub enum TokenTree { | 37 | pub enum TokenTree { |
38 | Leaf(Leaf), | 38 | Leaf(Leaf), |
39 | Subtree(Subtree), | 39 | Subtree(Subtree), |
40 | } | 40 | } |
41 | impl_froms!(TokenTree: Leaf, Subtree); | 41 | impl_froms!(TokenTree: Leaf, Subtree); |
42 | 42 | ||
43 | #[derive(Debug, Clone)] | 43 | #[derive(Debug, Clone, PartialEq, Eq)] |
44 | pub enum Leaf { | 44 | pub enum Leaf { |
45 | Literal(Literal), | 45 | Literal(Literal), |
46 | Punct(Punct), | 46 | Punct(Punct), |
@@ -48,7 +48,7 @@ pub enum Leaf { | |||
48 | } | 48 | } |
49 | impl_froms!(Leaf: Literal, Punct, Ident); | 49 | impl_froms!(Leaf: Literal, Punct, Ident); |
50 | 50 | ||
51 | #[derive(Debug, Clone)] | 51 | #[derive(Debug, Clone, PartialEq, Eq)] |
52 | pub struct Subtree { | 52 | pub 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)] |
66 | pub struct Literal { | 66 | pub 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)] |
83 | pub struct Ident { | 83 | pub 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. |
71 | fn worker_chan<I, O>(buf: usize) -> (Worker<I, O>, Receiver<I>, Sender<O>) { | 71 | fn 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 | |||
5 | a minimum version of 10 installed. Please refer to | 5 | a 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 | ||
8 | You will also need the most recent version of VS Code: we don't try to | ||
9 | maintain compatibility with older versions yet. | ||
10 | |||
8 | The experimental VS Code plugin can then be built and installed by executing the | 11 | The experimental VS Code plugin can then be built and installed by executing the |
9 | following commands: | 12 | following 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", |