diff options
39 files changed, 842 insertions, 306 deletions
diff --git a/Cargo.lock b/Cargo.lock index df79334c9..308e36836 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -247,12 +247,13 @@ dependencies = [ | |||
247 | 247 | ||
248 | [[package]] | 248 | [[package]] |
249 | name = "crossbeam-queue" | 249 | name = "crossbeam-queue" |
250 | version = "0.2.2" | 250 | version = "0.2.3" |
251 | source = "registry+https://github.com/rust-lang/crates.io-index" | 251 | source = "registry+https://github.com/rust-lang/crates.io-index" |
252 | checksum = "ab6bffe714b6bb07e42f201352c34f51fefd355ace793f9e638ebd52d23f98d2" | 252 | checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" |
253 | dependencies = [ | 253 | dependencies = [ |
254 | "cfg-if", | 254 | "cfg-if", |
255 | "crossbeam-utils", | 255 | "crossbeam-utils", |
256 | "maybe-uninit", | ||
256 | ] | 257 | ] |
257 | 258 | ||
258 | [[package]] | 259 | [[package]] |
@@ -565,9 +566,9 @@ dependencies = [ | |||
565 | 566 | ||
566 | [[package]] | 567 | [[package]] |
567 | name = "jod-thread" | 568 | name = "jod-thread" |
568 | version = "0.1.1" | 569 | version = "0.1.2" |
569 | source = "registry+https://github.com/rust-lang/crates.io-index" | 570 | source = "registry+https://github.com/rust-lang/crates.io-index" |
570 | checksum = "4022656272c3e564a7cdebcaaba6518d844b0d0c1836597196efb5bfeb98bb49" | 571 | checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" |
571 | 572 | ||
572 | [[package]] | 573 | [[package]] |
573 | name = "kernel32-sys" | 574 | name = "kernel32-sys" |
@@ -981,7 +982,10 @@ dependencies = [ | |||
981 | "anymap", | 982 | "anymap", |
982 | "drop_bomb", | 983 | "drop_bomb", |
983 | "either", | 984 | "either", |
985 | "fst", | ||
986 | "indexmap", | ||
984 | "insta", | 987 | "insta", |
988 | "itertools", | ||
985 | "log", | 989 | "log", |
986 | "once_cell", | 990 | "once_cell", |
987 | "ra_arena", | 991 | "ra_arena", |
@@ -1010,6 +1014,7 @@ dependencies = [ | |||
1010 | "ra_prof", | 1014 | "ra_prof", |
1011 | "ra_syntax", | 1015 | "ra_syntax", |
1012 | "ra_tt", | 1016 | "ra_tt", |
1017 | "rustc-hash", | ||
1013 | "test_utils", | 1018 | "test_utils", |
1014 | ] | 1019 | ] |
1015 | 1020 | ||
@@ -1516,9 +1521,9 @@ dependencies = [ | |||
1516 | 1521 | ||
1517 | [[package]] | 1522 | [[package]] |
1518 | name = "serde_json" | 1523 | name = "serde_json" |
1519 | version = "1.0.53" | 1524 | version = "1.0.55" |
1520 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1521 | checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" | 1526 | checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" |
1522 | dependencies = [ | 1527 | dependencies = [ |
1523 | "itoa", | 1528 | "itoa", |
1524 | "ryu", | 1529 | "ryu", |
@@ -1538,9 +1543,9 @@ dependencies = [ | |||
1538 | 1543 | ||
1539 | [[package]] | 1544 | [[package]] |
1540 | name = "serde_yaml" | 1545 | name = "serde_yaml" |
1541 | version = "0.8.12" | 1546 | version = "0.8.13" |
1542 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1543 | checksum = "16c7a592a1ec97c9c1c68d75b6e537dcbf60c7618e038e7841e00af1d9ccf0c4" | 1548 | checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5" |
1544 | dependencies = [ | 1549 | dependencies = [ |
1545 | "dtoa", | 1550 | "dtoa", |
1546 | "linked-hash-map", | 1551 | "linked-hash-map", |
@@ -1581,9 +1586,9 @@ checksum = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" | |||
1581 | 1586 | ||
1582 | [[package]] | 1587 | [[package]] |
1583 | name = "syn" | 1588 | name = "syn" |
1584 | version = "1.0.30" | 1589 | version = "1.0.31" |
1585 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1586 | checksum = "93a56fabc59dce20fe48b6c832cc249c713e7ed88fa28b0ee0a3bfcaae5fe4e2" | 1591 | checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" |
1587 | dependencies = [ | 1592 | dependencies = [ |
1588 | "proc-macro2", | 1593 | "proc-macro2", |
1589 | "quote", | 1594 | "quote", |
@@ -1592,9 +1597,9 @@ dependencies = [ | |||
1592 | 1597 | ||
1593 | [[package]] | 1598 | [[package]] |
1594 | name = "synstructure" | 1599 | name = "synstructure" |
1595 | version = "0.12.3" | 1600 | version = "0.12.4" |
1596 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1601 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1597 | checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" | 1602 | checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" |
1598 | dependencies = [ | 1603 | dependencies = [ |
1599 | "proc-macro2", | 1604 | "proc-macro2", |
1600 | "quote", | 1605 | "quote", |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index edf96d50e..5092bf336 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -130,7 +130,7 @@ impl AutoImportAssets { | |||
130 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { | 130 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { |
131 | let _p = profile("auto_import::search_for_imports"); | 131 | let _p = profile("auto_import::search_for_imports"); |
132 | let current_crate = self.module_with_name_to_import.krate(); | 132 | let current_crate = self.module_with_name_to_import.krate(); |
133 | ImportsLocator::new(db) | 133 | ImportsLocator::new(db, current_crate) |
134 | .find_imports(&self.get_search_query()) | 134 | .find_imports(&self.get_search_query()) |
135 | .into_iter() | 135 | .into_iter() |
136 | .filter_map(|candidate| match &self.import_candidate { | 136 | .filter_map(|candidate| match &self.import_candidate { |
@@ -841,4 +841,105 @@ fn main() { | |||
841 | ", | 841 | ", |
842 | ) | 842 | ) |
843 | } | 843 | } |
844 | |||
845 | #[test] | ||
846 | fn dep_import() { | ||
847 | check_assist( | ||
848 | auto_import, | ||
849 | r" | ||
850 | //- /lib.rs crate:dep | ||
851 | pub struct Struct; | ||
852 | |||
853 | //- /main.rs crate:main deps:dep | ||
854 | fn main() { | ||
855 | Struct<|> | ||
856 | }", | ||
857 | r"use dep::Struct; | ||
858 | |||
859 | fn main() { | ||
860 | Struct | ||
861 | } | ||
862 | ", | ||
863 | ); | ||
864 | } | ||
865 | |||
866 | #[test] | ||
867 | fn whole_segment() { | ||
868 | // Tests that only imports whose last segment matches the identifier get suggested. | ||
869 | check_assist( | ||
870 | auto_import, | ||
871 | r" | ||
872 | //- /lib.rs crate:dep | ||
873 | pub mod fmt { | ||
874 | pub trait Display {} | ||
875 | } | ||
876 | |||
877 | pub fn panic_fmt() {} | ||
878 | |||
879 | //- /main.rs crate:main deps:dep | ||
880 | struct S; | ||
881 | |||
882 | impl f<|>mt::Display for S {}", | ||
883 | r"use dep::fmt; | ||
884 | |||
885 | struct S; | ||
886 | impl fmt::Display for S {} | ||
887 | ", | ||
888 | ); | ||
889 | } | ||
890 | |||
891 | #[test] | ||
892 | fn macro_generated() { | ||
893 | // Tests that macro-generated items are suggested from external crates. | ||
894 | check_assist( | ||
895 | auto_import, | ||
896 | r" | ||
897 | //- /lib.rs crate:dep | ||
898 | |||
899 | macro_rules! mac { | ||
900 | () => { | ||
901 | pub struct Cheese; | ||
902 | }; | ||
903 | } | ||
904 | |||
905 | mac!(); | ||
906 | |||
907 | //- /main.rs crate:main deps:dep | ||
908 | |||
909 | fn main() { | ||
910 | Cheese<|>; | ||
911 | }", | ||
912 | r"use dep::Cheese; | ||
913 | |||
914 | fn main() { | ||
915 | Cheese; | ||
916 | } | ||
917 | ", | ||
918 | ); | ||
919 | } | ||
920 | |||
921 | #[test] | ||
922 | fn casing() { | ||
923 | // Tests that differently cased names don't interfere and we only suggest the matching one. | ||
924 | check_assist( | ||
925 | auto_import, | ||
926 | r" | ||
927 | //- /lib.rs crate:dep | ||
928 | |||
929 | pub struct FMT; | ||
930 | pub struct fmt; | ||
931 | |||
932 | //- /main.rs crate:main deps:dep | ||
933 | |||
934 | fn main() { | ||
935 | FMT<|>; | ||
936 | }", | ||
937 | r"use dep::FMT; | ||
938 | |||
939 | fn main() { | ||
940 | FMT; | ||
941 | } | ||
942 | ", | ||
943 | ); | ||
944 | } | ||
844 | } | 945 | } |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index a8d6466ea..bf26048f2 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -15,12 +15,10 @@ use std::{ | |||
15 | 15 | ||
16 | use ra_cfg::CfgOptions; | 16 | use ra_cfg::CfgOptions; |
17 | use ra_syntax::SmolStr; | 17 | use ra_syntax::SmolStr; |
18 | use rustc_hash::FxHashMap; | 18 | use ra_tt::TokenExpander; |
19 | use rustc_hash::FxHashSet; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | 20 | ||
21 | use crate::{RelativePath, RelativePathBuf}; | 21 | use crate::{RelativePath, RelativePathBuf}; |
22 | use fmt::Display; | ||
23 | use ra_tt::TokenExpander; | ||
24 | 22 | ||
25 | /// `FileId` is an integer which uniquely identifies a file. File paths are | 23 | /// `FileId` is an integer which uniquely identifies a file. File paths are |
26 | /// messy and system-dependent, so most of the code should work directly with | 24 | /// messy and system-dependent, so most of the code should work directly with |
@@ -111,7 +109,7 @@ impl CrateName { | |||
111 | } | 109 | } |
112 | } | 110 | } |
113 | 111 | ||
114 | impl Display for CrateName { | 112 | impl fmt::Display for CrateName { |
115 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 113 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
116 | write!(f, "{}", self.0) | 114 | write!(f, "{}", self.0) |
117 | } | 115 | } |
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 2ab314884..80ddb6058 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -7,6 +7,7 @@ use std::{panic, sync::Arc}; | |||
7 | 7 | ||
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
9 | use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; | 9 | use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; |
10 | use rustc_hash::FxHashSet; | ||
10 | 11 | ||
11 | pub use crate::{ | 12 | pub use crate::{ |
12 | cancellation::Canceled, | 13 | cancellation::Canceled, |
@@ -95,7 +96,7 @@ pub trait FileLoader { | |||
95 | /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we | 96 | /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we |
96 | /// get by with a `&str` for the time being. | 97 | /// get by with a `&str` for the time being. |
97 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; | 98 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; |
98 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; | 99 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>; |
99 | } | 100 | } |
100 | 101 | ||
101 | /// Database which stores all significant input facts: source code and project | 102 | /// Database which stores all significant input facts: source code and project |
@@ -133,16 +134,21 @@ pub trait SourceDatabaseExt: SourceDatabase { | |||
133 | #[salsa::input] | 134 | #[salsa::input] |
134 | fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; | 135 | fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; |
135 | 136 | ||
136 | fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>; | 137 | fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>; |
137 | } | 138 | } |
138 | 139 | ||
139 | fn source_root_crates( | 140 | fn source_root_crates( |
140 | db: &(impl SourceDatabaseExt + SourceDatabase), | 141 | db: &(impl SourceDatabaseExt + SourceDatabase), |
141 | id: SourceRootId, | 142 | id: SourceRootId, |
142 | ) -> Arc<Vec<CrateId>> { | 143 | ) -> Arc<FxHashSet<CrateId>> { |
143 | let root = db.source_root(id); | ||
144 | let graph = db.crate_graph(); | 144 | let graph = db.crate_graph(); |
145 | let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>(); | 145 | let res = graph |
146 | .iter() | ||
147 | .filter(|&krate| { | ||
148 | let root_file = graph[krate].root_file_id; | ||
149 | db.file_source_root(root_file) == id | ||
150 | }) | ||
151 | .collect::<FxHashSet<_>>(); | ||
146 | Arc::new(res) | 152 | Arc::new(res) |
147 | } | 153 | } |
148 | 154 | ||
@@ -156,7 +162,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
156 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 162 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
157 | // FIXME: this *somehow* should be platform agnostic... | 163 | // FIXME: this *somehow* should be platform agnostic... |
158 | if std::path::Path::new(path).is_absolute() { | 164 | if std::path::Path::new(path).is_absolute() { |
159 | let krate = *self.relevant_crates(anchor).get(0)?; | 165 | let krate = *self.relevant_crates(anchor).iter().next()?; |
160 | let (extern_source_id, relative_file) = | 166 | let (extern_source_id, relative_file) = |
161 | self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; | 167 | self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; |
162 | 168 | ||
@@ -175,7 +181,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
175 | } | 181 | } |
176 | } | 182 | } |
177 | 183 | ||
178 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 184 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
179 | let source_root = self.0.file_source_root(file_id); | 185 | let source_root = self.0.file_source_root(file_id); |
180 | self.0.source_root_crates(source_root) | 186 | self.0.source_root_crates(source_root) |
181 | } | 187 | } |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 4a06f3bcd..1a9f6cc76 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -9,6 +9,7 @@ use hir_def::{ | |||
9 | builtin_type::BuiltinType, | 9 | builtin_type::BuiltinType, |
10 | docs::Documentation, | 10 | docs::Documentation, |
11 | expr::{BindingAnnotation, Pat, PatId}, | 11 | expr::{BindingAnnotation, Pat, PatId}, |
12 | import_map, | ||
12 | per_ns::PerNs, | 13 | per_ns::PerNs, |
13 | resolver::{HasResolver, Resolver}, | 14 | resolver::{HasResolver, Resolver}, |
14 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
@@ -98,6 +99,23 @@ impl Crate { | |||
98 | db.crate_graph()[self.id].display_name.as_ref().cloned() | 99 | db.crate_graph()[self.id].display_name.as_ref().cloned() |
99 | } | 100 | } |
100 | 101 | ||
102 | pub fn query_external_importables( | ||
103 | self, | ||
104 | db: &dyn DefDatabase, | ||
105 | query: &str, | ||
106 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
107 | import_map::search_dependencies( | ||
108 | db, | ||
109 | self.into(), | ||
110 | import_map::Query::new(query).anchor_end().case_sensitive().limit(40), | ||
111 | ) | ||
112 | .into_iter() | ||
113 | .map(|item| match item { | ||
114 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | ||
115 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | ||
116 | }) | ||
117 | } | ||
118 | |||
101 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { | 119 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { |
102 | db.crate_graph().iter().map(|id| Crate { id }).collect() | 120 | db.crate_graph().iter().map(|id| Crate { id }).collect() |
103 | } | 121 | } |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 7c1f79f27..a232a5856 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -122,8 +122,9 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
122 | let macro_call = | 122 | let macro_call = |
123 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); | 123 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); |
124 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | 124 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); |
125 | let krate = sa.resolver.krate()?; | ||
125 | let macro_call_id = macro_call | 126 | let macro_call_id = macro_call |
126 | .as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; | 127 | .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; |
127 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) | 128 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) |
128 | } | 129 | } |
129 | 130 | ||
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 4b509f07c..7c6bbea13 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -307,7 +307,8 @@ impl SourceAnalyzer { | |||
307 | db: &dyn HirDatabase, | 307 | db: &dyn HirDatabase, |
308 | macro_call: InFile<&ast::MacroCall>, | 308 | macro_call: InFile<&ast::MacroCall>, |
309 | ) -> Option<HirFileId> { | 309 | ) -> Option<HirFileId> { |
310 | let macro_call_id = macro_call.as_call_id(db.upcast(), |path| { | 310 | let krate = self.resolver.krate()?; |
311 | let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { | ||
311 | self.resolver.resolve_path_as_macro(db.upcast(), &path) | 312 | self.resolver.resolve_path_as_macro(db.upcast(), &path) |
312 | })?; | 313 | })?; |
313 | Some(macro_call_id.as_file()) | 314 | Some(macro_call_id.as_file()) |
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index b85358308..ef1f65ee0 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml | |||
@@ -14,6 +14,9 @@ rustc-hash = "1.1.0" | |||
14 | either = "1.5.3" | 14 | either = "1.5.3" |
15 | anymap = "0.12.1" | 15 | anymap = "0.12.1" |
16 | drop_bomb = "0.1.4" | 16 | drop_bomb = "0.1.4" |
17 | fst = { version = "0.4", default-features = false } | ||
18 | itertools = "0.9.0" | ||
19 | indexmap = "1.4.0" | ||
17 | 20 | ||
18 | stdx = { path = "../stdx" } | 21 | stdx = { path = "../stdx" } |
19 | 22 | ||
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 273036cee..4f2350915 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -97,7 +97,7 @@ impl Expander { | |||
97 | 97 | ||
98 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 98 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
99 | 99 | ||
100 | if let Some(call_id) = macro_call.as_call_id(db, |path| { | 100 | if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| { |
101 | if let Some(local_scope) = local_scope { | 101 | if let Some(local_scope) = local_scope { |
102 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { | 102 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { |
103 | return Some(def); | 103 | return Some(def); |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 807195d25..53599e74a 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -99,7 +99,7 @@ impl FunctionData { | |||
99 | } | 99 | } |
100 | 100 | ||
101 | fn desugar_future_path(orig: TypeRef) -> Path { | 101 | fn desugar_future_path(orig: TypeRef) -> Path { |
102 | let path = path![std::future::Future]; | 102 | let path = path![core::future::Future]; |
103 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | 103 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); |
104 | let mut last = GenericArgs::empty(); | 104 | let mut last = GenericArgs::empty(); |
105 | last.bindings.push(AssociatedTypeBinding { | 105 | last.bindings.push(AssociatedTypeBinding { |
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 4284a0a91..36b4fdd81 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs | |||
@@ -1,9 +1,11 @@ | |||
1 | //! A map of all publicly exported items in a crate. | 1 | //! A map of all publicly exported items in a crate. |
2 | 2 | ||
3 | use std::{collections::hash_map::Entry, fmt, sync::Arc}; | 3 | use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; |
4 | 4 | ||
5 | use fst::{self, Streamer}; | ||
6 | use indexmap::{map::Entry, IndexMap}; | ||
5 | use ra_db::CrateId; | 7 | use ra_db::CrateId; |
6 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHasher; |
7 | 9 | ||
8 | use crate::{ | 10 | use crate::{ |
9 | db::DefDatabase, | 11 | db::DefDatabase, |
@@ -13,6 +15,8 @@ use crate::{ | |||
13 | ModuleDefId, ModuleId, | 15 | ModuleDefId, ModuleId, |
14 | }; | 16 | }; |
15 | 17 | ||
18 | type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>; | ||
19 | |||
16 | /// A map from publicly exported items to the path needed to import/name them from a downstream | 20 | /// A map from publicly exported items to the path needed to import/name them from a downstream |
17 | /// crate. | 21 | /// crate. |
18 | /// | 22 | /// |
@@ -21,16 +25,24 @@ use crate::{ | |||
21 | /// | 25 | /// |
22 | /// Note that all paths are relative to the containing crate's root, so the crate name still needs | 26 | /// Note that all paths are relative to the containing crate's root, so the crate name still needs |
23 | /// to be prepended to the `ModPath` before the path is valid. | 27 | /// to be prepended to the `ModPath` before the path is valid. |
24 | #[derive(Eq, PartialEq)] | ||
25 | pub struct ImportMap { | 28 | pub struct ImportMap { |
26 | map: FxHashMap<ItemInNs, ModPath>, | 29 | map: FxIndexMap<ItemInNs, ModPath>, |
30 | |||
31 | /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the | ||
32 | /// values returned by running `fst`. | ||
33 | /// | ||
34 | /// Since a path can refer to multiple items due to namespacing, we store all items with the | ||
35 | /// same path right after each other. This allows us to find all items after the FST gives us | ||
36 | /// the index of the first one. | ||
37 | importables: Vec<ItemInNs>, | ||
38 | fst: fst::Map<Vec<u8>>, | ||
27 | } | 39 | } |
28 | 40 | ||
29 | impl ImportMap { | 41 | impl ImportMap { |
30 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { | 42 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { |
31 | let _p = ra_prof::profile("import_map_query"); | 43 | let _p = ra_prof::profile("import_map_query"); |
32 | let def_map = db.crate_def_map(krate); | 44 | let def_map = db.crate_def_map(krate); |
33 | let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default()); | 45 | let mut import_map = FxIndexMap::with_capacity_and_hasher(64, Default::default()); |
34 | 46 | ||
35 | // We look only into modules that are public(ly reexported), starting with the crate root. | 47 | // We look only into modules that are public(ly reexported), starting with the crate root. |
36 | let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; | 48 | let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; |
@@ -88,7 +100,34 @@ impl ImportMap { | |||
88 | } | 100 | } |
89 | } | 101 | } |
90 | 102 | ||
91 | Arc::new(Self { map: import_map }) | 103 | let mut importables = import_map.iter().collect::<Vec<_>>(); |
104 | |||
105 | importables.sort_by(cmp); | ||
106 | |||
107 | // Build the FST, taking care not to insert duplicate values. | ||
108 | |||
109 | let mut builder = fst::MapBuilder::memory(); | ||
110 | let mut last_batch_start = 0; | ||
111 | |||
112 | for idx in 0..importables.len() { | ||
113 | if let Some(next_item) = importables.get(idx + 1) { | ||
114 | if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { | ||
115 | continue; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | let start = last_batch_start; | ||
120 | last_batch_start = idx + 1; | ||
121 | |||
122 | let key = fst_path(&importables[start].1); | ||
123 | |||
124 | builder.insert(key, start as u64).unwrap(); | ||
125 | } | ||
126 | |||
127 | let fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); | ||
128 | let importables = importables.iter().map(|(item, _)| **item).collect(); | ||
129 | |||
130 | Arc::new(Self { map: import_map, fst, importables }) | ||
92 | } | 131 | } |
93 | 132 | ||
94 | /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. | 133 | /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. |
@@ -97,6 +136,15 @@ impl ImportMap { | |||
97 | } | 136 | } |
98 | } | 137 | } |
99 | 138 | ||
139 | impl PartialEq for ImportMap { | ||
140 | fn eq(&self, other: &Self) -> bool { | ||
141 | // `fst` and `importables` are built from `map`, so we don't need to compare them. | ||
142 | self.map == other.map | ||
143 | } | ||
144 | } | ||
145 | |||
146 | impl Eq for ImportMap {} | ||
147 | |||
100 | impl fmt::Debug for ImportMap { | 148 | impl fmt::Debug for ImportMap { |
101 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 149 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
102 | let mut importable_paths: Vec<_> = self | 150 | let mut importable_paths: Vec<_> = self |
@@ -117,19 +165,135 @@ impl fmt::Debug for ImportMap { | |||
117 | } | 165 | } |
118 | } | 166 | } |
119 | 167 | ||
168 | fn fst_path(path: &ModPath) -> String { | ||
169 | let mut s = path.to_string(); | ||
170 | s.make_ascii_lowercase(); | ||
171 | s | ||
172 | } | ||
173 | |||
174 | fn cmp((_, lhs): &(&ItemInNs, &ModPath), (_, rhs): &(&ItemInNs, &ModPath)) -> Ordering { | ||
175 | let lhs_str = fst_path(lhs); | ||
176 | let rhs_str = fst_path(rhs); | ||
177 | lhs_str.cmp(&rhs_str) | ||
178 | } | ||
179 | |||
180 | #[derive(Debug)] | ||
181 | pub struct Query { | ||
182 | query: String, | ||
183 | lowercased: String, | ||
184 | anchor_end: bool, | ||
185 | case_sensitive: bool, | ||
186 | limit: usize, | ||
187 | } | ||
188 | |||
189 | impl Query { | ||
190 | pub fn new(query: &str) -> Self { | ||
191 | Self { | ||
192 | lowercased: query.to_lowercase(), | ||
193 | query: query.to_string(), | ||
194 | anchor_end: false, | ||
195 | case_sensitive: false, | ||
196 | limit: usize::max_value(), | ||
197 | } | ||
198 | } | ||
199 | |||
200 | /// Only returns items whose paths end with the (case-insensitive) query string as their last | ||
201 | /// segment. | ||
202 | pub fn anchor_end(self) -> Self { | ||
203 | Self { anchor_end: true, ..self } | ||
204 | } | ||
205 | |||
206 | /// Limits the returned number of items to `limit`. | ||
207 | pub fn limit(self, limit: usize) -> Self { | ||
208 | Self { limit, ..self } | ||
209 | } | ||
210 | |||
211 | /// Respect casing of the query string when matching. | ||
212 | pub fn case_sensitive(self) -> Self { | ||
213 | Self { case_sensitive: true, ..self } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | /// Searches dependencies of `krate` for an importable path matching `query`. | ||
218 | /// | ||
219 | /// This returns a list of items that could be imported from dependencies of `krate`. | ||
220 | pub fn search_dependencies<'a>( | ||
221 | db: &'a dyn DefDatabase, | ||
222 | krate: CrateId, | ||
223 | query: Query, | ||
224 | ) -> Vec<ItemInNs> { | ||
225 | let _p = ra_prof::profile("search_dependencies").detail(|| format!("{:?}", query)); | ||
226 | |||
227 | let graph = db.crate_graph(); | ||
228 | let import_maps: Vec<_> = | ||
229 | graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); | ||
230 | |||
231 | let automaton = fst::automaton::Subsequence::new(&query.lowercased); | ||
232 | |||
233 | let mut op = fst::map::OpBuilder::new(); | ||
234 | for map in &import_maps { | ||
235 | op = op.add(map.fst.search(&automaton)); | ||
236 | } | ||
237 | |||
238 | let mut stream = op.union(); | ||
239 | let mut res = Vec::new(); | ||
240 | while let Some((_, indexed_values)) = stream.next() { | ||
241 | for indexed_value in indexed_values { | ||
242 | let import_map = &import_maps[indexed_value.index]; | ||
243 | let importables = &import_map.importables[indexed_value.value as usize..]; | ||
244 | |||
245 | // Path shared by the importable items in this group. | ||
246 | let path = &import_map.map[&importables[0]]; | ||
247 | |||
248 | if query.anchor_end { | ||
249 | // Last segment must match query. | ||
250 | let last = path.segments.last().unwrap().to_string(); | ||
251 | if last.to_lowercase() != query.lowercased { | ||
252 | continue; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | // Add the items from this `ModPath` group. Those are all subsequent items in | ||
257 | // `importables` whose paths match `path`. | ||
258 | let iter = importables.iter().copied().take_while(|item| { | ||
259 | let item_path = &import_map.map[item]; | ||
260 | fst_path(item_path) == fst_path(path) | ||
261 | }); | ||
262 | |||
263 | if query.case_sensitive { | ||
264 | // FIXME: This does not do a subsequence match. | ||
265 | res.extend(iter.filter(|item| { | ||
266 | let item_path = &import_map.map[item]; | ||
267 | item_path.to_string().contains(&query.query) | ||
268 | })); | ||
269 | } else { | ||
270 | res.extend(iter); | ||
271 | } | ||
272 | |||
273 | if res.len() >= query.limit { | ||
274 | res.truncate(query.limit); | ||
275 | return res; | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | |||
280 | res | ||
281 | } | ||
282 | |||
120 | #[cfg(test)] | 283 | #[cfg(test)] |
121 | mod tests { | 284 | mod tests { |
122 | use super::*; | 285 | use super::*; |
123 | use crate::test_db::TestDB; | 286 | use crate::test_db::TestDB; |
124 | use insta::assert_snapshot; | 287 | use insta::assert_snapshot; |
288 | use itertools::Itertools; | ||
125 | use ra_db::fixture::WithFixture; | 289 | use ra_db::fixture::WithFixture; |
126 | use ra_db::SourceDatabase; | 290 | use ra_db::{SourceDatabase, Upcast}; |
127 | 291 | ||
128 | fn import_map(ra_fixture: &str) -> String { | 292 | fn import_map(ra_fixture: &str) -> String { |
129 | let db = TestDB::with_files(ra_fixture); | 293 | let db = TestDB::with_files(ra_fixture); |
130 | let crate_graph = db.crate_graph(); | 294 | let crate_graph = db.crate_graph(); |
131 | 295 | ||
132 | let import_maps: Vec<_> = crate_graph | 296 | let s = crate_graph |
133 | .iter() | 297 | .iter() |
134 | .filter_map(|krate| { | 298 | .filter_map(|krate| { |
135 | let cdata = &crate_graph[krate]; | 299 | let cdata = &crate_graph[krate]; |
@@ -139,9 +303,41 @@ mod tests { | |||
139 | 303 | ||
140 | Some(format!("{}:\n{:?}", name, map)) | 304 | Some(format!("{}:\n{:?}", name, map)) |
141 | }) | 305 | }) |
142 | .collect(); | 306 | .join("\n"); |
307 | s | ||
308 | } | ||
143 | 309 | ||
144 | import_maps.join("\n") | 310 | fn search_dependencies_of(ra_fixture: &str, krate_name: &str, query: Query) -> String { |
311 | let db = TestDB::with_files(ra_fixture); | ||
312 | let crate_graph = db.crate_graph(); | ||
313 | let krate = crate_graph | ||
314 | .iter() | ||
315 | .find(|krate| { | ||
316 | crate_graph[*krate].display_name.as_ref().map(|n| n.to_string()) | ||
317 | == Some(krate_name.to_string()) | ||
318 | }) | ||
319 | .unwrap(); | ||
320 | |||
321 | search_dependencies(db.upcast(), krate, query) | ||
322 | .into_iter() | ||
323 | .filter_map(|item| { | ||
324 | let mark = match item { | ||
325 | ItemInNs::Types(_) => "t", | ||
326 | ItemInNs::Values(_) => "v", | ||
327 | ItemInNs::Macros(_) => "m", | ||
328 | }; | ||
329 | item.krate(db.upcast()).map(|krate| { | ||
330 | let map = db.import_map(krate); | ||
331 | let path = map.path_of(item).unwrap(); | ||
332 | format!( | ||
333 | "{}::{} ({})", | ||
334 | crate_graph[krate].display_name.as_ref().unwrap(), | ||
335 | path, | ||
336 | mark | ||
337 | ) | ||
338 | }) | ||
339 | }) | ||
340 | .join("\n") | ||
145 | } | 341 | } |
146 | 342 | ||
147 | #[test] | 343 | #[test] |
@@ -328,4 +524,143 @@ mod tests { | |||
328 | lib: | 524 | lib: |
329 | "###); | 525 | "###); |
330 | } | 526 | } |
527 | |||
528 | #[test] | ||
529 | fn namespacing() { | ||
530 | let map = import_map( | ||
531 | r" | ||
532 | //- /lib.rs crate:lib | ||
533 | pub struct Thing; // t + v | ||
534 | #[macro_export] | ||
535 | macro_rules! Thing { // m | ||
536 | () => {}; | ||
537 | } | ||
538 | ", | ||
539 | ); | ||
540 | |||
541 | assert_snapshot!(map, @r###" | ||
542 | lib: | ||
543 | - Thing (m) | ||
544 | - Thing (t) | ||
545 | - Thing (v) | ||
546 | "###); | ||
547 | |||
548 | let map = import_map( | ||
549 | r" | ||
550 | //- /lib.rs crate:lib | ||
551 | pub mod Thing {} // t | ||
552 | #[macro_export] | ||
553 | macro_rules! Thing { // m | ||
554 | () => {}; | ||
555 | } | ||
556 | ", | ||
557 | ); | ||
558 | |||
559 | assert_snapshot!(map, @r###" | ||
560 | lib: | ||
561 | - Thing (m) | ||
562 | - Thing (t) | ||
563 | "###); | ||
564 | } | ||
565 | |||
566 | #[test] | ||
567 | fn search() { | ||
568 | let ra_fixture = r#" | ||
569 | //- /main.rs crate:main deps:dep | ||
570 | //- /dep.rs crate:dep deps:tdep | ||
571 | use tdep::fmt as fmt_dep; | ||
572 | pub mod fmt { | ||
573 | pub trait Display { | ||
574 | fn fmt(); | ||
575 | } | ||
576 | } | ||
577 | #[macro_export] | ||
578 | macro_rules! Fmt { | ||
579 | () => {}; | ||
580 | } | ||
581 | pub struct Fmt; | ||
582 | |||
583 | pub fn format() {} | ||
584 | pub fn no() {} | ||
585 | |||
586 | //- /tdep.rs crate:tdep | ||
587 | pub mod fmt { | ||
588 | pub struct NotImportableFromMain; | ||
589 | } | ||
590 | "#; | ||
591 | |||
592 | let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt")); | ||
593 | assert_snapshot!(res, @r###" | ||
594 | dep::fmt (t) | ||
595 | dep::Fmt (t) | ||
596 | dep::Fmt (v) | ||
597 | dep::Fmt (m) | ||
598 | dep::fmt::Display (t) | ||
599 | dep::format (v) | ||
600 | "###); | ||
601 | |||
602 | let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt").anchor_end()); | ||
603 | assert_snapshot!(res, @r###" | ||
604 | dep::fmt (t) | ||
605 | dep::Fmt (t) | ||
606 | dep::Fmt (v) | ||
607 | dep::Fmt (m) | ||
608 | "###); | ||
609 | } | ||
610 | |||
611 | #[test] | ||
612 | fn search_casing() { | ||
613 | let ra_fixture = r#" | ||
614 | //- /main.rs crate:main deps:dep | ||
615 | //- /dep.rs crate:dep | ||
616 | |||
617 | pub struct fmt; | ||
618 | pub struct FMT; | ||
619 | "#; | ||
620 | |||
621 | let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT")); | ||
622 | |||
623 | assert_snapshot!(res, @r###" | ||
624 | dep::fmt (t) | ||
625 | dep::fmt (v) | ||
626 | dep::FMT (t) | ||
627 | dep::FMT (v) | ||
628 | "###); | ||
629 | |||
630 | let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive()); | ||
631 | |||
632 | assert_snapshot!(res, @r###" | ||
633 | dep::FMT (t) | ||
634 | dep::FMT (v) | ||
635 | "###); | ||
636 | } | ||
637 | |||
638 | #[test] | ||
639 | fn search_limit() { | ||
640 | let res = search_dependencies_of( | ||
641 | r#" | ||
642 | //- /main.rs crate:main deps:dep | ||
643 | //- /dep.rs crate:dep | ||
644 | pub mod fmt { | ||
645 | pub trait Display { | ||
646 | fn fmt(); | ||
647 | } | ||
648 | } | ||
649 | #[macro_export] | ||
650 | macro_rules! Fmt { | ||
651 | () => {}; | ||
652 | } | ||
653 | pub struct Fmt; | ||
654 | |||
655 | pub fn format() {} | ||
656 | pub fn no() {} | ||
657 | "#, | ||
658 | "main", | ||
659 | Query::new("").limit(2), | ||
660 | ); | ||
661 | assert_snapshot!(res, @r###" | ||
662 | dep::fmt (t) | ||
663 | dep::Fmt (t) | ||
664 | "###); | ||
665 | } | ||
331 | } | 666 | } |
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index de490fcc5..edc59e5a8 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -417,6 +417,7 @@ pub trait AsMacroCall { | |||
417 | fn as_call_id( | 417 | fn as_call_id( |
418 | &self, | 418 | &self, |
419 | db: &dyn db::DefDatabase, | 419 | db: &dyn db::DefDatabase, |
420 | krate: CrateId, | ||
420 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 421 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
421 | ) -> Option<MacroCallId>; | 422 | ) -> Option<MacroCallId>; |
422 | } | 423 | } |
@@ -425,13 +426,14 @@ impl AsMacroCall for InFile<&ast::MacroCall> { | |||
425 | fn as_call_id( | 426 | fn as_call_id( |
426 | &self, | 427 | &self, |
427 | db: &dyn db::DefDatabase, | 428 | db: &dyn db::DefDatabase, |
429 | krate: CrateId, | ||
428 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 430 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
429 | ) -> Option<MacroCallId> { | 431 | ) -> Option<MacroCallId> { |
430 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); | 432 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); |
431 | let h = Hygiene::new(db.upcast(), self.file_id); | 433 | let h = Hygiene::new(db.upcast(), self.file_id); |
432 | let path = path::ModPath::from_src(self.value.path()?, &h)?; | 434 | let path = path::ModPath::from_src(self.value.path()?, &h)?; |
433 | 435 | ||
434 | AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, resolver) | 436 | AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver) |
435 | } | 437 | } |
436 | } | 438 | } |
437 | 439 | ||
@@ -452,6 +454,7 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> { | |||
452 | fn as_call_id( | 454 | fn as_call_id( |
453 | &self, | 455 | &self, |
454 | db: &dyn db::DefDatabase, | 456 | db: &dyn db::DefDatabase, |
457 | krate: CrateId, | ||
455 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 458 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
456 | ) -> Option<MacroCallId> { | 459 | ) -> Option<MacroCallId> { |
457 | let def: MacroDefId = resolver(self.path.clone())?; | 460 | let def: MacroDefId = resolver(self.path.clone())?; |
@@ -461,13 +464,13 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> { | |||
461 | let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); | 464 | let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); |
462 | 465 | ||
463 | Some( | 466 | Some( |
464 | expand_eager_macro(db.upcast(), macro_call, def, &|path: ast::Path| { | 467 | expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| { |
465 | resolver(path::ModPath::from_src(path, &hygiene)?) | 468 | resolver(path::ModPath::from_src(path, &hygiene)?) |
466 | })? | 469 | })? |
467 | .into(), | 470 | .into(), |
468 | ) | 471 | ) |
469 | } else { | 472 | } else { |
470 | Some(def.as_lazy_macro(db.upcast(), MacroCallKind::FnLike(self.ast_id)).into()) | 473 | Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into()) |
471 | } | 474 | } |
472 | } | 475 | } |
473 | } | 476 | } |
@@ -476,12 +479,14 @@ impl AsMacroCall for AstIdWithPath<ast::ModuleItem> { | |||
476 | fn as_call_id( | 479 | fn as_call_id( |
477 | &self, | 480 | &self, |
478 | db: &dyn db::DefDatabase, | 481 | db: &dyn db::DefDatabase, |
482 | krate: CrateId, | ||
479 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 483 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
480 | ) -> Option<MacroCallId> { | 484 | ) -> Option<MacroCallId> { |
481 | let def = resolver(self.path.clone())?; | 485 | let def = resolver(self.path.clone())?; |
482 | Some( | 486 | Some( |
483 | def.as_lazy_macro( | 487 | def.as_lazy_macro( |
484 | db.upcast(), | 488 | db.upcast(), |
489 | krate, | ||
485 | MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), | 490 | MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), |
486 | ) | 491 | ) |
487 | .into(), | 492 | .into(), |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 353a31ad4..976e5e585 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -571,16 +571,18 @@ impl DefCollector<'_> { | |||
571 | return false; | 571 | return false; |
572 | } | 572 | } |
573 | 573 | ||
574 | if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| { | 574 | if let Some(call_id) = |
575 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | 575 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { |
576 | self.db, | 576 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
577 | ResolveMode::Other, | 577 | self.db, |
578 | directive.module_id, | 578 | ResolveMode::Other, |
579 | &path, | 579 | directive.module_id, |
580 | BuiltinShadowMode::Module, | 580 | &path, |
581 | ); | 581 | BuiltinShadowMode::Module, |
582 | resolved_res.resolved_def.take_macros() | 582 | ); |
583 | }) { | 583 | resolved_res.resolved_def.take_macros() |
584 | }) | ||
585 | { | ||
584 | resolved.push((directive.module_id, call_id, directive.depth)); | 586 | resolved.push((directive.module_id, call_id, directive.depth)); |
585 | res = ReachedFixedPoint::No; | 587 | res = ReachedFixedPoint::No; |
586 | return false; | 588 | return false; |
@@ -589,9 +591,10 @@ impl DefCollector<'_> { | |||
589 | true | 591 | true |
590 | }); | 592 | }); |
591 | attribute_macros.retain(|directive| { | 593 | attribute_macros.retain(|directive| { |
592 | if let Some(call_id) = directive | 594 | if let Some(call_id) = |
593 | .ast_id | 595 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { |
594 | .as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path)) | 596 | self.resolve_attribute_macro(&directive, &path) |
597 | }) | ||
595 | { | 598 | { |
596 | resolved.push((directive.module_id, call_id, 0)); | 599 | resolved.push((directive.module_id, call_id, 0)); |
597 | res = ReachedFixedPoint::No; | 600 | res = ReachedFixedPoint::No; |
@@ -957,11 +960,13 @@ impl ModCollector<'_, '_> { | |||
957 | } | 960 | } |
958 | 961 | ||
959 | // Case 2: try to resolve in legacy scope and expand macro_rules | 962 | // Case 2: try to resolve in legacy scope and expand macro_rules |
960 | if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| { | 963 | if let Some(macro_call_id) = |
961 | path.as_ident().and_then(|name| { | 964 | ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| { |
962 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | 965 | path.as_ident().and_then(|name| { |
966 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | ||
967 | }) | ||
963 | }) | 968 | }) |
964 | }) { | 969 | { |
965 | self.def_collector.unexpanded_macros.push(MacroDirective { | 970 | self.def_collector.unexpanded_macros.push(MacroDirective { |
966 | module_id: self.module_id, | 971 | module_id: self.module_id, |
967 | ast_id, | 972 | ast_id, |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index bfa921de2..ba16442bd 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -323,16 +323,16 @@ pub use hir_expand::name as __name; | |||
323 | 323 | ||
324 | #[macro_export] | 324 | #[macro_export] |
325 | macro_rules! __known_path { | 325 | macro_rules! __known_path { |
326 | (std::iter::IntoIterator) => {}; | 326 | (core::iter::IntoIterator) => {}; |
327 | (std::result::Result) => {}; | 327 | (core::result::Result) => {}; |
328 | (std::ops::Range) => {}; | 328 | (core::ops::Range) => {}; |
329 | (std::ops::RangeFrom) => {}; | 329 | (core::ops::RangeFrom) => {}; |
330 | (std::ops::RangeFull) => {}; | 330 | (core::ops::RangeFull) => {}; |
331 | (std::ops::RangeTo) => {}; | 331 | (core::ops::RangeTo) => {}; |
332 | (std::ops::RangeToInclusive) => {}; | 332 | (core::ops::RangeToInclusive) => {}; |
333 | (std::ops::RangeInclusive) => {}; | 333 | (core::ops::RangeInclusive) => {}; |
334 | (std::future::Future) => {}; | 334 | (core::future::Future) => {}; |
335 | (std::ops::Try) => {}; | 335 | (core::ops::Try) => {}; |
336 | ($path:path) => { | 336 | ($path:path) => { |
337 | compile_error!("Please register your known path in the path module") | 337 | compile_error!("Please register your known path in the path module") |
338 | }; | 338 | }; |
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index bcfa66ac9..4581d8745 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs | |||
@@ -7,6 +7,7 @@ use std::{ | |||
7 | 7 | ||
8 | use hir_expand::db::AstDatabase; | 8 | use hir_expand::db::AstDatabase; |
9 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; | 9 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; |
10 | use rustc_hash::FxHashSet; | ||
10 | 11 | ||
11 | use crate::db::DefDatabase; | 12 | use crate::db::DefDatabase; |
12 | 13 | ||
@@ -59,7 +60,7 @@ impl FileLoader for TestDB { | |||
59 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 60 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
60 | FileLoaderDelegate(self).resolve_path(anchor, path) | 61 | FileLoaderDelegate(self).resolve_path(anchor, path) |
61 | } | 62 | } |
62 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 63 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
63 | FileLoaderDelegate(self).relevant_crates(file_id) | 64 | FileLoaderDelegate(self).relevant_crates(file_id) |
64 | } | 65 | } |
65 | } | 66 | } |
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml index 2cd522766..e5c9f3e99 100644 --- a/crates/ra_hir_expand/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml | |||
@@ -10,6 +10,7 @@ doctest = false | |||
10 | [dependencies] | 10 | [dependencies] |
11 | log = "0.4.8" | 11 | log = "0.4.8" |
12 | either = "1.5.3" | 12 | either = "1.5.3" |
13 | rustc-hash = "1.0.0" | ||
13 | 14 | ||
14 | ra_arena = { path = "../ra_arena" } | 15 | ra_arena = { path = "../ra_arena" } |
15 | ra_db = { path = "../ra_db" } | 16 | ra_db = { path = "../ra_db" } |
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index 1dc9cac66..26b667b55 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs | |||
@@ -8,8 +8,7 @@ use ra_syntax::{ | |||
8 | match_ast, | 8 | match_ast, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::db::AstDatabase; | 11 | use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind}; |
12 | use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; | ||
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_rules! register_builtin { |
15 | ( $($trait:ident => $expand:ident),* ) => { | 14 | ( $($trait:ident => $expand:ident),* ) => { |
@@ -156,23 +155,13 @@ fn expand_simple_derive( | |||
156 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { | 155 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { |
157 | // FIXME: make hygiene works for builtin derive macro | 156 | // FIXME: make hygiene works for builtin derive macro |
158 | // such that $crate can be used here. | 157 | // such that $crate can be used here. |
159 | |||
160 | let m: MacroCallId = id.into(); | ||
161 | let file_id = m.as_file().original_file(db); | ||
162 | let cg = db.crate_graph(); | 158 | let cg = db.crate_graph(); |
163 | let krates = db.relevant_crates(file_id); | 159 | let krate = db.lookup_intern_macro(id).krate; |
164 | let krate = match krates.get(0) { | ||
165 | Some(krate) => krate, | ||
166 | None => { | ||
167 | let tt = quote! { core }; | ||
168 | return tt.token_trees[0].clone(); | ||
169 | } | ||
170 | }; | ||
171 | 160 | ||
172 | // XXX | 161 | // XXX |
173 | // All crates except core itself should have a dependency on core, | 162 | // All crates except core itself should have a dependency on core, |
174 | // We detect `core` by seeing whether it doesn't have such a dependency. | 163 | // We detect `core` by seeing whether it doesn't have such a dependency. |
175 | let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") { | 164 | let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") { |
176 | quote! { core } | 165 | quote! { core } |
177 | } else { | 166 | } else { |
178 | quote! { crate } | 167 | quote! { crate } |
@@ -264,10 +253,12 @@ fn partial_ord_expand( | |||
264 | 253 | ||
265 | #[cfg(test)] | 254 | #[cfg(test)] |
266 | mod tests { | 255 | mod tests { |
267 | use super::*; | ||
268 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; | ||
269 | use name::{known, Name}; | 256 | use name::{known, Name}; |
270 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 257 | use ra_db::{fixture::WithFixture, CrateId, SourceDatabase}; |
258 | |||
259 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; | ||
260 | |||
261 | use super::*; | ||
271 | 262 | ||
272 | fn expand_builtin_derive(s: &str, name: Name) -> String { | 263 | fn expand_builtin_derive(s: &str, name: Name) -> String { |
273 | let def = find_builtin_derive(&name).unwrap(); | 264 | let def = find_builtin_derive(&name).unwrap(); |
@@ -291,7 +282,11 @@ mod tests { | |||
291 | 282 | ||
292 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); | 283 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); |
293 | 284 | ||
294 | let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) }; | 285 | let loc = MacroCallLoc { |
286 | def, | ||
287 | krate: CrateId(0), | ||
288 | kind: MacroCallKind::Attr(attr_id, name.to_string()), | ||
289 | }; | ||
295 | 290 | ||
296 | let id: MacroCallId = db.intern_macro(loc).into(); | 291 | let id: MacroCallId = db.intern_macro(loc).into(); |
297 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); | 292 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); |
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 7579546d2..b50eb347c 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -1,15 +1,14 @@ | |||
1 | //! Builtin macro | 1 | //! Builtin macro |
2 | use crate::db::AstDatabase; | ||
3 | use crate::{ | 2 | use crate::{ |
4 | ast::{self, AstToken, HasStringValue}, | 3 | db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId, |
5 | name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize, | 4 | MacroDefId, MacroDefKind, TextSize, |
6 | }; | 5 | }; |
7 | 6 | ||
8 | use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId}; | ||
9 | use either::Either; | 7 | use either::Either; |
10 | use mbe::parse_to_token_tree; | 8 | use mbe::parse_to_token_tree; |
11 | use ra_db::FileId; | 9 | use ra_db::FileId; |
12 | use ra_parser::FragmentKind; | 10 | use ra_parser::FragmentKind; |
11 | use ra_syntax::ast::{self, AstToken, HasStringValue}; | ||
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_rules! register_builtin { |
15 | ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { | 14 | ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { |
@@ -333,10 +332,7 @@ fn include_expand( | |||
333 | } | 332 | } |
334 | 333 | ||
335 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | 334 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { |
336 | let call_id: MacroCallId = arg_id.into(); | 335 | let krate = db.lookup_intern_eager_expansion(arg_id).krate; |
337 | let original_file = call_id.as_file().original_file(db); | ||
338 | |||
339 | let krate = *db.relevant_crates(original_file).get(0)?; | ||
340 | db.crate_graph()[krate].env.get(key) | 336 | db.crate_graph()[krate].env.get(key) |
341 | } | 337 | } |
342 | 338 | ||
@@ -395,6 +391,7 @@ mod tests { | |||
395 | 391 | ||
396 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); | 392 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); |
397 | 393 | ||
394 | let krate = CrateId(0); | ||
398 | let file_id = match expander { | 395 | let file_id = match expander { |
399 | Either::Left(expander) => { | 396 | Either::Left(expander) => { |
400 | // the first one should be a macro_rules | 397 | // the first one should be a macro_rules |
@@ -407,6 +404,7 @@ mod tests { | |||
407 | 404 | ||
408 | let loc = MacroCallLoc { | 405 | let loc = MacroCallLoc { |
409 | def, | 406 | def, |
407 | krate, | ||
410 | kind: MacroCallKind::FnLike(AstId::new( | 408 | kind: MacroCallKind::FnLike(AstId::new( |
411 | file_id.into(), | 409 | file_id.into(), |
412 | ast_id_map.ast_id(¯o_calls[1]), | 410 | ast_id_map.ast_id(¯o_calls[1]), |
@@ -419,7 +417,7 @@ mod tests { | |||
419 | Either::Right(expander) => { | 417 | Either::Right(expander) => { |
420 | // the first one should be a macro_rules | 418 | // the first one should be a macro_rules |
421 | let def = MacroDefId { | 419 | let def = MacroDefId { |
422 | krate: Some(CrateId(0)), | 420 | krate: Some(krate), |
423 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), | 421 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), |
424 | kind: MacroDefKind::BuiltInEager(expander), | 422 | kind: MacroDefKind::BuiltInEager(expander), |
425 | local_inner: false, | 423 | local_inner: false, |
@@ -433,6 +431,7 @@ mod tests { | |||
433 | def, | 431 | def, |
434 | fragment: FragmentKind::Expr, | 432 | fragment: FragmentKind::Expr, |
435 | subtree: Arc::new(parsed_args.clone()), | 433 | subtree: Arc::new(parsed_args.clone()), |
434 | krate, | ||
436 | file_id: file_id.into(), | 435 | file_id: file_id.into(), |
437 | } | 436 | } |
438 | }); | 437 | }); |
@@ -442,6 +441,7 @@ mod tests { | |||
442 | def, | 441 | def, |
443 | fragment, | 442 | fragment, |
444 | subtree: Arc::new(subtree), | 443 | subtree: Arc::new(subtree), |
444 | krate, | ||
445 | file_id: file_id.into(), | 445 | file_id: file_id.into(), |
446 | }; | 446 | }; |
447 | 447 | ||
diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs index 932f47c30..302d2b3e0 100644 --- a/crates/ra_hir_expand/src/eager.rs +++ b/crates/ra_hir_expand/src/eager.rs | |||
@@ -25,12 +25,14 @@ use crate::{ | |||
25 | EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | 25 | EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | use ra_db::CrateId; | ||
28 | use ra_parser::FragmentKind; | 29 | use ra_parser::FragmentKind; |
29 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; | 30 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; |
30 | use std::sync::Arc; | 31 | use std::sync::Arc; |
31 | 32 | ||
32 | pub fn expand_eager_macro( | 33 | pub fn expand_eager_macro( |
33 | db: &dyn AstDatabase, | 34 | db: &dyn AstDatabase, |
35 | krate: CrateId, | ||
34 | macro_call: InFile<ast::MacroCall>, | 36 | macro_call: InFile<ast::MacroCall>, |
35 | def: MacroDefId, | 37 | def: MacroDefId, |
36 | resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, | 38 | resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, |
@@ -47,6 +49,7 @@ pub fn expand_eager_macro( | |||
47 | def, | 49 | def, |
48 | fragment: FragmentKind::Expr, | 50 | fragment: FragmentKind::Expr, |
49 | subtree: Arc::new(parsed_args.clone()), | 51 | subtree: Arc::new(parsed_args.clone()), |
52 | krate, | ||
50 | file_id: macro_call.file_id, | 53 | file_id: macro_call.file_id, |
51 | } | 54 | } |
52 | }); | 55 | }); |
@@ -56,14 +59,20 @@ pub fn expand_eager_macro( | |||
56 | let result = eager_macro_recur( | 59 | let result = eager_macro_recur( |
57 | db, | 60 | db, |
58 | InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), | 61 | InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), |
62 | krate, | ||
59 | resolver, | 63 | resolver, |
60 | )?; | 64 | )?; |
61 | let subtree = to_subtree(&result)?; | 65 | let subtree = to_subtree(&result)?; |
62 | 66 | ||
63 | if let MacroDefKind::BuiltInEager(eager) = def.kind { | 67 | if let MacroDefKind::BuiltInEager(eager) = def.kind { |
64 | let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; | 68 | let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; |
65 | let eager = | 69 | let eager = EagerCallLoc { |
66 | EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id }; | 70 | def, |
71 | fragment, | ||
72 | subtree: Arc::new(subtree), | ||
73 | krate, | ||
74 | file_id: macro_call.file_id, | ||
75 | }; | ||
67 | 76 | ||
68 | Some(db.intern_eager_expansion(eager)) | 77 | Some(db.intern_eager_expansion(eager)) |
69 | } else { | 78 | } else { |
@@ -81,11 +90,12 @@ fn lazy_expand( | |||
81 | db: &dyn AstDatabase, | 90 | db: &dyn AstDatabase, |
82 | def: &MacroDefId, | 91 | def: &MacroDefId, |
83 | macro_call: InFile<ast::MacroCall>, | 92 | macro_call: InFile<ast::MacroCall>, |
93 | krate: CrateId, | ||
84 | ) -> Option<InFile<SyntaxNode>> { | 94 | ) -> Option<InFile<SyntaxNode>> { |
85 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); | 95 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); |
86 | 96 | ||
87 | let id: MacroCallId = | 97 | let id: MacroCallId = |
88 | def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); | 98 | def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); |
89 | 99 | ||
90 | db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) | 100 | db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) |
91 | } | 101 | } |
@@ -93,6 +103,7 @@ fn lazy_expand( | |||
93 | fn eager_macro_recur( | 103 | fn eager_macro_recur( |
94 | db: &dyn AstDatabase, | 104 | db: &dyn AstDatabase, |
95 | curr: InFile<SyntaxNode>, | 105 | curr: InFile<SyntaxNode>, |
106 | krate: CrateId, | ||
96 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, | 107 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, |
97 | ) -> Option<SyntaxNode> { | 108 | ) -> Option<SyntaxNode> { |
98 | let original = curr.value.clone(); | 109 | let original = curr.value.clone(); |
@@ -105,18 +116,23 @@ fn eager_macro_recur( | |||
105 | let def: MacroDefId = macro_resolver(child.path()?)?; | 116 | let def: MacroDefId = macro_resolver(child.path()?)?; |
106 | let insert = match def.kind { | 117 | let insert = match def.kind { |
107 | MacroDefKind::BuiltInEager(_) => { | 118 | MacroDefKind::BuiltInEager(_) => { |
108 | let id: MacroCallId = | 119 | let id: MacroCallId = expand_eager_macro( |
109 | expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)? | 120 | db, |
110 | .into(); | 121 | krate, |
122 | curr.with_value(child.clone()), | ||
123 | def, | ||
124 | macro_resolver, | ||
125 | )? | ||
126 | .into(); | ||
111 | db.parse_or_expand(id.as_file())? | 127 | db.parse_or_expand(id.as_file())? |
112 | } | 128 | } |
113 | MacroDefKind::Declarative | 129 | MacroDefKind::Declarative |
114 | | MacroDefKind::BuiltIn(_) | 130 | | MacroDefKind::BuiltIn(_) |
115 | | MacroDefKind::BuiltInDerive(_) | 131 | | MacroDefKind::BuiltInDerive(_) |
116 | | MacroDefKind::CustomDerive(_) => { | 132 | | MacroDefKind::CustomDerive(_) => { |
117 | let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; | 133 | let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?; |
118 | // replace macro inside | 134 | // replace macro inside |
119 | eager_macro_recur(db, expanded, macro_resolver)? | 135 | eager_macro_recur(db, expanded, krate, macro_resolver)? |
120 | } | 136 | } |
121 | }; | 137 | }; |
122 | 138 | ||
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index f440c073b..5eac2605b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -209,8 +209,13 @@ pub struct MacroDefId { | |||
209 | } | 209 | } |
210 | 210 | ||
211 | impl MacroDefId { | 211 | impl MacroDefId { |
212 | pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId { | 212 | pub fn as_lazy_macro( |
213 | db.intern_macro(MacroCallLoc { def: self, kind }) | 213 | self, |
214 | db: &dyn db::AstDatabase, | ||
215 | krate: CrateId, | ||
216 | kind: MacroCallKind, | ||
217 | ) -> LazyMacroId { | ||
218 | db.intern_macro(MacroCallLoc { def: self, krate, kind }) | ||
214 | } | 219 | } |
215 | } | 220 | } |
216 | 221 | ||
@@ -227,6 +232,7 @@ pub enum MacroDefKind { | |||
227 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 232 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
228 | pub struct MacroCallLoc { | 233 | pub struct MacroCallLoc { |
229 | pub(crate) def: MacroDefId, | 234 | pub(crate) def: MacroDefId, |
235 | pub(crate) krate: CrateId, | ||
230 | pub(crate) kind: MacroCallKind, | 236 | pub(crate) kind: MacroCallKind, |
231 | } | 237 | } |
232 | 238 | ||
@@ -274,6 +280,7 @@ pub struct EagerCallLoc { | |||
274 | pub(crate) def: MacroDefId, | 280 | pub(crate) def: MacroDefId, |
275 | pub(crate) fragment: FragmentKind, | 281 | pub(crate) fragment: FragmentKind, |
276 | pub(crate) subtree: Arc<tt::Subtree>, | 282 | pub(crate) subtree: Arc<tt::Subtree>, |
283 | pub(crate) krate: CrateId, | ||
277 | pub(crate) file_id: HirFileId, | 284 | pub(crate) file_id: HirFileId, |
278 | } | 285 | } |
279 | 286 | ||
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index fdf225f55..09fc18c36 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs | |||
@@ -6,6 +6,7 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; | 8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; |
9 | use rustc_hash::FxHashSet; | ||
9 | 10 | ||
10 | #[salsa::database( | 11 | #[salsa::database( |
11 | ra_db::SourceDatabaseExtStorage, | 12 | ra_db::SourceDatabaseExtStorage, |
@@ -44,7 +45,7 @@ impl FileLoader for TestDB { | |||
44 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 45 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
45 | FileLoaderDelegate(self).resolve_path(anchor, path) | 46 | FileLoaderDelegate(self).resolve_path(anchor, path) |
46 | } | 47 | } |
47 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 48 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
48 | FileLoaderDelegate(self).relevant_crates(file_id) | 49 | FileLoaderDelegate(self).relevant_crates(file_id) |
49 | } | 50 | } |
50 | } | 51 | } |
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index f04968e14..7db928dde 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs | |||
@@ -226,17 +226,19 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
226 | None => return, | 226 | None => return, |
227 | }; | 227 | }; |
228 | 228 | ||
229 | let std_result_path = path![std::result::Result]; | 229 | let core_result_path = path![core::result::Result]; |
230 | 230 | ||
231 | let resolver = self.func.resolver(db.upcast()); | 231 | let resolver = self.func.resolver(db.upcast()); |
232 | let std_result_enum = match resolver.resolve_known_enum(db.upcast(), &std_result_path) { | 232 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { |
233 | Some(it) => it, | 233 | Some(it) => it, |
234 | _ => return, | 234 | _ => return, |
235 | }; | 235 | }; |
236 | 236 | ||
237 | let std_result_ctor = TypeCtor::Adt(AdtId::EnumId(std_result_enum)); | 237 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); |
238 | let params = match &mismatch.expected { | 238 | let params = match &mismatch.expected { |
239 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, | 239 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { |
240 | parameters | ||
241 | } | ||
240 | _ => return, | 242 | _ => return, |
241 | }; | 243 | }; |
242 | 244 | ||
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index f965eb2b5..3719f76a6 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -555,13 +555,13 @@ impl<'a> InferenceContext<'a> { | |||
555 | } | 555 | } |
556 | 556 | ||
557 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { | 557 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { |
558 | let path = path![std::iter::IntoIterator]; | 558 | let path = path![core::iter::IntoIterator]; |
559 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 559 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
560 | self.db.trait_data(trait_).associated_type_by_name(&name![Item]) | 560 | self.db.trait_data(trait_).associated_type_by_name(&name![Item]) |
561 | } | 561 | } |
562 | 562 | ||
563 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { | 563 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { |
564 | let path = path![std::ops::Try]; | 564 | let path = path![core::ops::Try]; |
565 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 565 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
566 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) | 566 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) |
567 | } | 567 | } |
@@ -587,37 +587,37 @@ impl<'a> InferenceContext<'a> { | |||
587 | } | 587 | } |
588 | 588 | ||
589 | fn resolve_range_full(&self) -> Option<AdtId> { | 589 | fn resolve_range_full(&self) -> Option<AdtId> { |
590 | let path = path![std::ops::RangeFull]; | 590 | let path = path![core::ops::RangeFull]; |
591 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 591 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
592 | Some(struct_.into()) | 592 | Some(struct_.into()) |
593 | } | 593 | } |
594 | 594 | ||
595 | fn resolve_range(&self) -> Option<AdtId> { | 595 | fn resolve_range(&self) -> Option<AdtId> { |
596 | let path = path![std::ops::Range]; | 596 | let path = path![core::ops::Range]; |
597 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 597 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
598 | Some(struct_.into()) | 598 | Some(struct_.into()) |
599 | } | 599 | } |
600 | 600 | ||
601 | fn resolve_range_inclusive(&self) -> Option<AdtId> { | 601 | fn resolve_range_inclusive(&self) -> Option<AdtId> { |
602 | let path = path![std::ops::RangeInclusive]; | 602 | let path = path![core::ops::RangeInclusive]; |
603 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 603 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
604 | Some(struct_.into()) | 604 | Some(struct_.into()) |
605 | } | 605 | } |
606 | 606 | ||
607 | fn resolve_range_from(&self) -> Option<AdtId> { | 607 | fn resolve_range_from(&self) -> Option<AdtId> { |
608 | let path = path![std::ops::RangeFrom]; | 608 | let path = path![core::ops::RangeFrom]; |
609 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 609 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
610 | Some(struct_.into()) | 610 | Some(struct_.into()) |
611 | } | 611 | } |
612 | 612 | ||
613 | fn resolve_range_to(&self) -> Option<AdtId> { | 613 | fn resolve_range_to(&self) -> Option<AdtId> { |
614 | let path = path![std::ops::RangeTo]; | 614 | let path = path![core::ops::RangeTo]; |
615 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 615 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
616 | Some(struct_.into()) | 616 | Some(struct_.into()) |
617 | } | 617 | } |
618 | 618 | ||
619 | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { | 619 | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { |
620 | let path = path![std::ops::RangeToInclusive]; | 620 | let path = path![core::ops::RangeToInclusive]; |
621 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 621 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
622 | Some(struct_.into()) | 622 | Some(struct_.into()) |
623 | } | 623 | } |
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index e484968a0..ad04e3e0f 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs | |||
@@ -8,6 +8,7 @@ use std::{ | |||
8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; | 8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; |
9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; | 9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; |
10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; | 10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; |
11 | use rustc_hash::FxHashSet; | ||
11 | use stdx::format_to; | 12 | use stdx::format_to; |
12 | 13 | ||
13 | use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; | 14 | use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; |
@@ -73,7 +74,7 @@ impl FileLoader for TestDB { | |||
73 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 74 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
74 | FileLoaderDelegate(self).resolve_path(anchor, path) | 75 | FileLoaderDelegate(self).resolve_path(anchor, path) |
75 | } | 76 | } |
76 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 77 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
77 | FileLoaderDelegate(self).relevant_crates(file_id) | 78 | FileLoaderDelegate(self).relevant_crates(file_id) |
78 | } | 79 | } |
79 | } | 80 | } |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 8a5031756..37659cd02 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -95,7 +95,7 @@ fn foo() { | |||
95 | fn infer_ranges() { | 95 | fn infer_ranges() { |
96 | let (db, pos) = TestDB::with_position( | 96 | let (db, pos) = TestDB::with_position( |
97 | r#" | 97 | r#" |
98 | //- /main.rs crate:main deps:std | 98 | //- /main.rs crate:main deps:core |
99 | fn test() { | 99 | fn test() { |
100 | let a = ..; | 100 | let a = ..; |
101 | let b = 1..; | 101 | let b = 1..; |
@@ -108,7 +108,7 @@ fn test() { | |||
108 | t<|>; | 108 | t<|>; |
109 | } | 109 | } |
110 | 110 | ||
111 | //- /std.rs crate:std | 111 | //- /core.rs crate:core |
112 | #[prelude_import] use prelude::*; | 112 | #[prelude_import] use prelude::*; |
113 | mod prelude {} | 113 | mod prelude {} |
114 | 114 | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 133fb5f39..e81193a3c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -10,7 +10,7 @@ use super::{infer, infer_with_mismatches, type_at, type_at_pos}; | |||
10 | fn infer_await() { | 10 | fn infer_await() { |
11 | let (db, pos) = TestDB::with_position( | 11 | let (db, pos) = TestDB::with_position( |
12 | r#" | 12 | r#" |
13 | //- /main.rs crate:main deps:std | 13 | //- /main.rs crate:main deps:core |
14 | 14 | ||
15 | struct IntFuture; | 15 | struct IntFuture; |
16 | 16 | ||
@@ -24,7 +24,7 @@ fn test() { | |||
24 | v<|>; | 24 | v<|>; |
25 | } | 25 | } |
26 | 26 | ||
27 | //- /std.rs crate:std | 27 | //- /core.rs crate:core |
28 | #[prelude_import] use future::*; | 28 | #[prelude_import] use future::*; |
29 | mod future { | 29 | mod future { |
30 | #[lang = "future_trait"] | 30 | #[lang = "future_trait"] |
@@ -42,7 +42,7 @@ mod future { | |||
42 | fn infer_async() { | 42 | fn infer_async() { |
43 | let (db, pos) = TestDB::with_position( | 43 | let (db, pos) = TestDB::with_position( |
44 | r#" | 44 | r#" |
45 | //- /main.rs crate:main deps:std | 45 | //- /main.rs crate:main deps:core |
46 | 46 | ||
47 | async fn foo() -> u64 { | 47 | async fn foo() -> u64 { |
48 | 128 | 48 | 128 |
@@ -54,7 +54,7 @@ fn test() { | |||
54 | v<|>; | 54 | v<|>; |
55 | } | 55 | } |
56 | 56 | ||
57 | //- /std.rs crate:std | 57 | //- /core.rs crate:core |
58 | #[prelude_import] use future::*; | 58 | #[prelude_import] use future::*; |
59 | mod future { | 59 | mod future { |
60 | #[lang = "future_trait"] | 60 | #[lang = "future_trait"] |
@@ -72,7 +72,7 @@ mod future { | |||
72 | fn infer_desugar_async() { | 72 | fn infer_desugar_async() { |
73 | let (db, pos) = TestDB::with_position( | 73 | let (db, pos) = TestDB::with_position( |
74 | r#" | 74 | r#" |
75 | //- /main.rs crate:main deps:std | 75 | //- /main.rs crate:main deps:core |
76 | 76 | ||
77 | async fn foo() -> u64 { | 77 | async fn foo() -> u64 { |
78 | 128 | 78 | 128 |
@@ -83,7 +83,7 @@ fn test() { | |||
83 | r<|>; | 83 | r<|>; |
84 | } | 84 | } |
85 | 85 | ||
86 | //- /std.rs crate:std | 86 | //- /core.rs crate:core |
87 | #[prelude_import] use future::*; | 87 | #[prelude_import] use future::*; |
88 | mod future { | 88 | mod future { |
89 | trait Future { | 89 | trait Future { |
@@ -100,7 +100,7 @@ mod future { | |||
100 | fn infer_try() { | 100 | fn infer_try() { |
101 | let (db, pos) = TestDB::with_position( | 101 | let (db, pos) = TestDB::with_position( |
102 | r#" | 102 | r#" |
103 | //- /main.rs crate:main deps:std | 103 | //- /main.rs crate:main deps:core |
104 | 104 | ||
105 | fn test() { | 105 | fn test() { |
106 | let r: Result<i32, u64> = Result::Ok(1); | 106 | let r: Result<i32, u64> = Result::Ok(1); |
@@ -108,7 +108,7 @@ fn test() { | |||
108 | v<|>; | 108 | v<|>; |
109 | } | 109 | } |
110 | 110 | ||
111 | //- /std.rs crate:std | 111 | //- /core.rs crate:core |
112 | 112 | ||
113 | #[prelude_import] use ops::*; | 113 | #[prelude_import] use ops::*; |
114 | mod ops { | 114 | mod ops { |
@@ -140,9 +140,9 @@ mod result { | |||
140 | fn infer_for_loop() { | 140 | fn infer_for_loop() { |
141 | let (db, pos) = TestDB::with_position( | 141 | let (db, pos) = TestDB::with_position( |
142 | r#" | 142 | r#" |
143 | //- /main.rs crate:main deps:std | 143 | //- /main.rs crate:main deps:core,alloc |
144 | 144 | ||
145 | use std::collections::Vec; | 145 | use alloc::collections::Vec; |
146 | 146 | ||
147 | fn test() { | 147 | fn test() { |
148 | let v = Vec::new(); | 148 | let v = Vec::new(); |
@@ -152,7 +152,7 @@ fn test() { | |||
152 | } | 152 | } |
153 | } | 153 | } |
154 | 154 | ||
155 | //- /std.rs crate:std | 155 | //- /core.rs crate:core |
156 | 156 | ||
157 | #[prelude_import] use iter::*; | 157 | #[prelude_import] use iter::*; |
158 | mod iter { | 158 | mod iter { |
@@ -161,6 +161,8 @@ mod iter { | |||
161 | } | 161 | } |
162 | } | 162 | } |
163 | 163 | ||
164 | //- /alloc.rs crate:alloc deps:core | ||
165 | |||
164 | mod collections { | 166 | mod collections { |
165 | struct Vec<T> {} | 167 | struct Vec<T> {} |
166 | impl<T> Vec<T> { | 168 | impl<T> Vec<T> { |
@@ -168,7 +170,7 @@ mod collections { | |||
168 | fn push(&mut self, t: T) { } | 170 | fn push(&mut self, t: T) { } |
169 | } | 171 | } |
170 | 172 | ||
171 | impl<T> crate::iter::IntoIterator for Vec<T> { | 173 | impl<T> IntoIterator for Vec<T> { |
172 | type Item=T; | 174 | type Item=T; |
173 | } | 175 | } |
174 | } | 176 | } |
@@ -2846,12 +2848,12 @@ fn test() { | |||
2846 | fn integer_range_iterate() { | 2848 | fn integer_range_iterate() { |
2847 | let t = type_at( | 2849 | let t = type_at( |
2848 | r#" | 2850 | r#" |
2849 | //- /main.rs crate:main deps:std | 2851 | //- /main.rs crate:main deps:core |
2850 | fn test() { | 2852 | fn test() { |
2851 | for x in 0..100 { x<|>; } | 2853 | for x in 0..100 { x<|>; } |
2852 | } | 2854 | } |
2853 | 2855 | ||
2854 | //- /std.rs crate:std | 2856 | //- /core.rs crate:core |
2855 | pub mod ops { | 2857 | pub mod ops { |
2856 | pub struct Range<Idx> { | 2858 | pub struct Range<Idx> { |
2857 | pub start: Idx, | 2859 | pub start: Idx, |
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index bf14a467f..f44feaf69 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -321,29 +321,26 @@ mod tests { | |||
321 | fn test_wrap_return_type() { | 321 | fn test_wrap_return_type() { |
322 | let before = r#" | 322 | let before = r#" |
323 | //- /main.rs | 323 | //- /main.rs |
324 | use std::{string::String, result::Result::{self, Ok, Err}}; | 324 | use core::result::Result::{self, Ok, Err}; |
325 | 325 | ||
326 | fn div(x: i32, y: i32) -> Result<i32, String> { | 326 | fn div(x: i32, y: i32) -> Result<i32, ()> { |
327 | if y == 0 { | 327 | if y == 0 { |
328 | return Err("div by zero".into()); | 328 | return Err(()); |
329 | } | 329 | } |
330 | x / y<|> | 330 | x / y<|> |
331 | } | 331 | } |
332 | 332 | ||
333 | //- /std/lib.rs | 333 | //- /core/lib.rs |
334 | pub mod string { | ||
335 | pub struct String { } | ||
336 | } | ||
337 | pub mod result { | 334 | pub mod result { |
338 | pub enum Result<T, E> { Ok(T), Err(E) } | 335 | pub enum Result<T, E> { Ok(T), Err(E) } |
339 | } | 336 | } |
340 | "#; | 337 | "#; |
341 | let after = r#" | 338 | let after = r#" |
342 | use std::{string::String, result::Result::{self, Ok, Err}}; | 339 | use core::result::Result::{self, Ok, Err}; |
343 | 340 | ||
344 | fn div(x: i32, y: i32) -> Result<i32, String> { | 341 | fn div(x: i32, y: i32) -> Result<i32, ()> { |
345 | if y == 0 { | 342 | if y == 0 { |
346 | return Err("div by zero".into()); | 343 | return Err(()); |
347 | } | 344 | } |
348 | Ok(x / y) | 345 | Ok(x / y) |
349 | } | 346 | } |
@@ -355,7 +352,7 @@ mod tests { | |||
355 | fn test_wrap_return_type_handles_generic_functions() { | 352 | fn test_wrap_return_type_handles_generic_functions() { |
356 | let before = r#" | 353 | let before = r#" |
357 | //- /main.rs | 354 | //- /main.rs |
358 | use std::result::Result::{self, Ok, Err}; | 355 | use core::result::Result::{self, Ok, Err}; |
359 | 356 | ||
360 | fn div<T>(x: T) -> Result<T, i32> { | 357 | fn div<T>(x: T) -> Result<T, i32> { |
361 | if x == 0 { | 358 | if x == 0 { |
@@ -364,13 +361,13 @@ mod tests { | |||
364 | <|>x | 361 | <|>x |
365 | } | 362 | } |
366 | 363 | ||
367 | //- /std/lib.rs | 364 | //- /core/lib.rs |
368 | pub mod result { | 365 | pub mod result { |
369 | pub enum Result<T, E> { Ok(T), Err(E) } | 366 | pub enum Result<T, E> { Ok(T), Err(E) } |
370 | } | 367 | } |
371 | "#; | 368 | "#; |
372 | let after = r#" | 369 | let after = r#" |
373 | use std::result::Result::{self, Ok, Err}; | 370 | use core::result::Result::{self, Ok, Err}; |
374 | 371 | ||
375 | fn div<T>(x: T) -> Result<T, i32> { | 372 | fn div<T>(x: T) -> Result<T, i32> { |
376 | if x == 0 { | 373 | if x == 0 { |
@@ -386,32 +383,29 @@ mod tests { | |||
386 | fn test_wrap_return_type_handles_type_aliases() { | 383 | fn test_wrap_return_type_handles_type_aliases() { |
387 | let before = r#" | 384 | let before = r#" |
388 | //- /main.rs | 385 | //- /main.rs |
389 | use std::{string::String, result::Result::{self, Ok, Err}}; | 386 | use core::result::Result::{self, Ok, Err}; |
390 | 387 | ||
391 | type MyResult<T> = Result<T, String>; | 388 | type MyResult<T> = Result<T, ()>; |
392 | 389 | ||
393 | fn div(x: i32, y: i32) -> MyResult<i32> { | 390 | fn div(x: i32, y: i32) -> MyResult<i32> { |
394 | if y == 0 { | 391 | if y == 0 { |
395 | return Err("div by zero".into()); | 392 | return Err(()); |
396 | } | 393 | } |
397 | x <|>/ y | 394 | x <|>/ y |
398 | } | 395 | } |
399 | 396 | ||
400 | //- /std/lib.rs | 397 | //- /core/lib.rs |
401 | pub mod string { | ||
402 | pub struct String { } | ||
403 | } | ||
404 | pub mod result { | 398 | pub mod result { |
405 | pub enum Result<T, E> { Ok(T), Err(E) } | 399 | pub enum Result<T, E> { Ok(T), Err(E) } |
406 | } | 400 | } |
407 | "#; | 401 | "#; |
408 | let after = r#" | 402 | let after = r#" |
409 | use std::{string::String, result::Result::{self, Ok, Err}}; | 403 | use core::result::Result::{self, Ok, Err}; |
410 | 404 | ||
411 | type MyResult<T> = Result<T, String>; | 405 | type MyResult<T> = Result<T, ()>; |
412 | fn div(x: i32, y: i32) -> MyResult<i32> { | 406 | fn div(x: i32, y: i32) -> MyResult<i32> { |
413 | if y == 0 { | 407 | if y == 0 { |
414 | return Err("div by zero".into()); | 408 | return Err(()); |
415 | } | 409 | } |
416 | Ok(x / y) | 410 | Ok(x / y) |
417 | } | 411 | } |
@@ -423,16 +417,13 @@ mod tests { | |||
423 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { | 417 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { |
424 | let content = r#" | 418 | let content = r#" |
425 | //- /main.rs | 419 | //- /main.rs |
426 | use std::{string::String, result::Result::{self, Ok, Err}}; | 420 | use core::result::Result::{self, Ok, Err}; |
427 | 421 | ||
428 | fn foo() -> Result<String, i32> { | 422 | fn foo() -> Result<(), i32> { |
429 | 0<|> | 423 | 0<|> |
430 | } | 424 | } |
431 | 425 | ||
432 | //- /std/lib.rs | 426 | //- /core/lib.rs |
433 | pub mod string { | ||
434 | pub struct String { } | ||
435 | } | ||
436 | pub mod result { | 427 | pub mod result { |
437 | pub enum Result<T, E> { Ok(T), Err(E) } | 428 | pub enum Result<T, E> { Ok(T), Err(E) } |
438 | } | 429 | } |
@@ -444,7 +435,7 @@ mod tests { | |||
444 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { | 435 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { |
445 | let content = r#" | 436 | let content = r#" |
446 | //- /main.rs | 437 | //- /main.rs |
447 | use std::{string::String, result::Result::{self, Ok, Err}}; | 438 | use core::result::Result::{self, Ok, Err}; |
448 | 439 | ||
449 | enum SomeOtherEnum { | 440 | enum SomeOtherEnum { |
450 | Ok(i32), | 441 | Ok(i32), |
@@ -455,10 +446,7 @@ mod tests { | |||
455 | 0<|> | 446 | 0<|> |
456 | } | 447 | } |
457 | 448 | ||
458 | //- /std/lib.rs | 449 | //- /core/lib.rs |
459 | pub mod string { | ||
460 | pub struct String { } | ||
461 | } | ||
462 | pub mod result { | 450 | pub mod result { |
463 | pub enum Result<T, E> { Ok(T), Err(E) } | 451 | pub enum Result<T, E> { Ok(T), Err(E) } |
464 | } | 452 | } |
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index e34ff5a7d..33548d43c 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html | |||
@@ -84,7 +84,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
84 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>; | 84 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>; |
85 | <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>; | 85 | <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>; |
86 | 86 | ||
87 | <span class="variable mutable">y</span>; | 87 | <span class="keyword">let</span> <span class="struct">Foo</span> { <span class="field">x</span>: <span class="variable declaration">z</span>, <span class="field">y</span> } = <span class="struct">Foo</span> { <span class="field">x</span>: <span class="variable">z</span>, <span class="field">y</span> }; |
88 | |||
89 | <span class="variable">y</span>; | ||
88 | } | 90 | } |
89 | 91 | ||
90 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><<span class="type_param declaration">T</span>> { | 92 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><<span class="type_param declaration">T</span>> { |
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 021f8e7e2..949bf59a0 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs | |||
@@ -7,18 +7,6 @@ use crate::{ | |||
7 | FileRange, TextRange, | 7 | FileRange, TextRange, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// Highlights the code given by the `ra_fixture` argument, renders the | ||
11 | /// result as HTML, and compares it with the HTML file given as `snapshot`. | ||
12 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | ||
13 | fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { | ||
14 | let (analysis, file_id) = single_file(ra_fixture); | ||
15 | let dst_file = project_dir().join(snapshot); | ||
16 | let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); | ||
17 | let expected_html = &read_text(&dst_file); | ||
18 | fs::write(dst_file, &actual_html).unwrap(); | ||
19 | assert_eq_text!(expected_html, actual_html); | ||
20 | } | ||
21 | |||
22 | #[test] | 10 | #[test] |
23 | fn test_highlighting() { | 11 | fn test_highlighting() { |
24 | check_highlighting( | 12 | check_highlighting( |
@@ -77,6 +65,8 @@ fn main() { | |||
77 | let y = &mut x; | 65 | let y = &mut x; |
78 | let z = &y; | 66 | let z = &y; |
79 | 67 | ||
68 | let Foo { x: z, y } = Foo { x: z, y }; | ||
69 | |||
80 | y; | 70 | y; |
81 | } | 71 | } |
82 | 72 | ||
@@ -334,3 +324,15 @@ impl Foo { | |||
334 | false, | 324 | false, |
335 | ) | 325 | ) |
336 | } | 326 | } |
327 | |||
328 | /// Highlights the code given by the `ra_fixture` argument, renders the | ||
329 | /// result as HTML, and compares it with the HTML file given as `snapshot`. | ||
330 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | ||
331 | fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { | ||
332 | let (analysis, file_id) = single_file(ra_fixture); | ||
333 | let dst_file = project_dir().join(snapshot); | ||
334 | let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); | ||
335 | let expected_html = &read_text(&dst_file); | ||
336 | fs::write(dst_file, &actual_html).unwrap(); | ||
337 | assert_eq_text!(expected_html, actual_html); | ||
338 | } | ||
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 533306e2e..83776d2b6 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs | |||
@@ -21,7 +21,9 @@ use ra_ide_db::{source_change::SourceFileEdit, RootDatabase}; | |||
21 | use ra_syntax::{ | 21 | use ra_syntax::{ |
22 | algo::find_node_at_offset, | 22 | algo::find_node_at_offset, |
23 | ast::{self, AstToken}, | 23 | ast::{self, AstToken}, |
24 | AstNode, SourceFile, TextRange, TextSize, | 24 | AstNode, SourceFile, |
25 | SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, | ||
26 | TextRange, TextSize, | ||
25 | }; | 27 | }; |
26 | 28 | ||
27 | use ra_text_edit::TextEdit; | 29 | use ra_text_edit::TextEdit; |
@@ -98,9 +100,12 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { | |||
98 | }; | 100 | }; |
99 | let current_indent_len = TextSize::of(current_indent); | 101 | let current_indent_len = TextSize::of(current_indent); |
100 | 102 | ||
103 | let parent = whitespace.syntax().parent(); | ||
101 | // Make sure dot is a part of call chain | 104 | // Make sure dot is a part of call chain |
102 | let field_expr = ast::FieldExpr::cast(whitespace.syntax().parent())?; | 105 | if !matches!(parent.kind(), FIELD_EXPR | METHOD_CALL_EXPR) { |
103 | let prev_indent = leading_indent(field_expr.syntax())?; | 106 | return None; |
107 | } | ||
108 | let prev_indent = leading_indent(&parent)?; | ||
104 | let target_indent = format!(" {}", prev_indent); | 109 | let target_indent = format!(" {}", prev_indent); |
105 | let target_indent_len = TextSize::of(&target_indent); | 110 | let target_indent_len = TextSize::of(&target_indent); |
106 | if current_indent_len == target_indent_len { | 111 | if current_indent_len == target_indent_len { |
@@ -143,11 +148,11 @@ mod tests { | |||
143 | }) | 148 | }) |
144 | } | 149 | } |
145 | 150 | ||
146 | fn type_char(char_typed: char, before: &str, after: &str) { | 151 | fn type_char(char_typed: char, ra_fixture_before: &str, ra_fixture_after: &str) { |
147 | let actual = do_type_char(char_typed, before) | 152 | let actual = do_type_char(char_typed, ra_fixture_before) |
148 | .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); | 153 | .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); |
149 | 154 | ||
150 | assert_eq_text!(after, &actual); | 155 | assert_eq_text!(ra_fixture_after, &actual); |
151 | } | 156 | } |
152 | 157 | ||
153 | fn type_char_noop(char_typed: char, before: &str) { | 158 | fn type_char_noop(char_typed: char, before: &str) { |
@@ -249,6 +254,27 @@ fn foo() { | |||
249 | } | 254 | } |
250 | 255 | ||
251 | #[test] | 256 | #[test] |
257 | fn indents_new_chain_call_with_let() { | ||
258 | type_char( | ||
259 | '.', | ||
260 | r#" | ||
261 | fn main() { | ||
262 | let _ = foo | ||
263 | <|> | ||
264 | bar() | ||
265 | } | ||
266 | "#, | ||
267 | r#" | ||
268 | fn main() { | ||
269 | let _ = foo | ||
270 | . | ||
271 | bar() | ||
272 | } | ||
273 | "#, | ||
274 | ); | ||
275 | } | ||
276 | |||
277 | #[test] | ||
252 | fn indents_continued_chain_call() { | 278 | fn indents_continued_chain_call() { |
253 | type_char( | 279 | type_char( |
254 | '.', | 280 | '.', |
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index 5dbe1c1b7..2fc796a85 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs | |||
@@ -16,7 +16,7 @@ use rustc_hash::FxHashMap; | |||
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{ |
18 | symbol_index::{SymbolIndex, SymbolsDatabase}, | 18 | symbol_index::{SymbolIndex, SymbolsDatabase}, |
19 | DebugData, RootDatabase, | 19 | RootDatabase, |
20 | }; | 20 | }; |
21 | 21 | ||
22 | #[derive(Default)] | 22 | #[derive(Default)] |
@@ -26,7 +26,6 @@ pub struct AnalysisChange { | |||
26 | files_changed: Vec<(FileId, Arc<String>)>, | 26 | files_changed: Vec<(FileId, Arc<String>)>, |
27 | libraries_added: Vec<LibraryData>, | 27 | libraries_added: Vec<LibraryData>, |
28 | crate_graph: Option<CrateGraph>, | 28 | crate_graph: Option<CrateGraph>, |
29 | debug_data: DebugData, | ||
30 | } | 29 | } |
31 | 30 | ||
32 | impl fmt::Debug for AnalysisChange { | 31 | impl fmt::Debug for AnalysisChange { |
@@ -87,10 +86,6 @@ impl AnalysisChange { | |||
87 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 86 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { |
88 | self.crate_graph = Some(graph); | 87 | self.crate_graph = Some(graph); |
89 | } | 88 | } |
90 | |||
91 | pub fn set_debug_root_path(&mut self, source_root_id: SourceRootId, path: String) { | ||
92 | self.debug_data.root_paths.insert(source_root_id, path); | ||
93 | } | ||
94 | } | 89 | } |
95 | 90 | ||
96 | #[derive(Debug)] | 91 | #[derive(Debug)] |
@@ -218,8 +213,6 @@ impl RootDatabase { | |||
218 | if let Some(crate_graph) = change.crate_graph { | 213 | if let Some(crate_graph) = change.crate_graph { |
219 | self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) | 214 | self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) |
220 | } | 215 | } |
221 | |||
222 | Arc::make_mut(&mut self.debug_data).merge(change.debug_data) | ||
223 | } | 216 | } |
224 | 217 | ||
225 | fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { | 218 | fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { |
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 1826f3ac6..3ef5e74b6 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -78,6 +78,7 @@ impl Definition { | |||
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | #[derive(Debug)] | ||
81 | pub enum NameClass { | 82 | pub enum NameClass { |
82 | Definition(Definition), | 83 | Definition(Definition), |
83 | /// `None` in `if let None = Some(82) {}` | 84 | /// `None` in `if let None = Some(82) {}` |
@@ -131,9 +132,11 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option | |||
131 | let local = sema.to_def(&it)?; | 132 | let local = sema.to_def(&it)?; |
132 | 133 | ||
133 | if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) { | 134 | if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) { |
134 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { | 135 | if record_field_pat.name_ref().is_none() { |
135 | let field = Definition::Field(field); | 136 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { |
136 | return Some(NameClass::FieldShorthand { local, field }); | 137 | let field = Definition::Field(field); |
138 | return Some(NameClass::FieldShorthand { local, field }); | ||
139 | } | ||
137 | } | 140 | } |
138 | } | 141 | } |
139 | 142 | ||
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs index bf0d8db60..fff112e66 100644 --- a/crates/ra_ide_db/src/imports_locator.rs +++ b/crates/ra_ide_db/src/imports_locator.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the ra_assists module. | 1 | //! This module contains an import search funcionality that is provided to the ra_assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. |
3 | 3 | ||
4 | use hir::{MacroDef, ModuleDef, Semantics}; | 4 | use hir::{Crate, MacroDef, ModuleDef, Semantics}; |
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; | 6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; |
7 | 7 | ||
@@ -11,44 +11,46 @@ use crate::{ | |||
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use either::Either; | 13 | use either::Either; |
14 | use rustc_hash::FxHashSet; | ||
14 | 15 | ||
15 | pub struct ImportsLocator<'a> { | 16 | pub struct ImportsLocator<'a> { |
16 | sema: Semantics<'a, RootDatabase>, | 17 | sema: Semantics<'a, RootDatabase>, |
18 | krate: Crate, | ||
17 | } | 19 | } |
18 | 20 | ||
19 | impl<'a> ImportsLocator<'a> { | 21 | impl<'a> ImportsLocator<'a> { |
20 | pub fn new(db: &'a RootDatabase) -> Self { | 22 | pub fn new(db: &'a RootDatabase, krate: Crate) -> Self { |
21 | Self { sema: Semantics::new(db) } | 23 | Self { sema: Semantics::new(db), krate } |
22 | } | 24 | } |
23 | 25 | ||
24 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { | 26 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { |
25 | let _p = profile("search_for_imports"); | 27 | let _p = profile("search_for_imports"); |
26 | let db = self.sema.db; | 28 | let db = self.sema.db; |
27 | 29 | ||
28 | let project_results = { | 30 | // Query dependencies first. |
29 | let mut query = Query::new(name_to_import.to_string()); | 31 | let mut candidates: FxHashSet<_> = |
30 | query.exact(); | 32 | self.krate.query_external_importables(db, name_to_import).collect(); |
31 | query.limit(40); | 33 | |
32 | symbol_index::world_symbols(db, query) | 34 | // Query the local crate using the symbol index. |
33 | }; | 35 | let local_results = { |
34 | let lib_results = { | ||
35 | let mut query = Query::new(name_to_import.to_string()); | 36 | let mut query = Query::new(name_to_import.to_string()); |
36 | query.libs(); | ||
37 | query.exact(); | 37 | query.exact(); |
38 | query.limit(40); | 38 | query.limit(40); |
39 | symbol_index::world_symbols(db, query) | 39 | symbol_index::crate_symbols(db, self.krate.into(), query) |
40 | }; | 40 | }; |
41 | 41 | ||
42 | project_results | 42 | candidates.extend( |
43 | .into_iter() | 43 | local_results |
44 | .chain(lib_results.into_iter()) | 44 | .into_iter() |
45 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) | 45 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) |
46 | .filter_map(|name_definition_to_import| match name_definition_to_import { | 46 | .filter_map(|name_definition_to_import| match name_definition_to_import { |
47 | Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), | 47 | Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), |
48 | Definition::Macro(macro_def) => Some(Either::Right(macro_def)), | 48 | Definition::Macro(macro_def) => Some(Either::Right(macro_def)), |
49 | _ => None, | 49 | _ => None, |
50 | }) | 50 | }), |
51 | .collect() | 51 | ); |
52 | |||
53 | candidates.into_iter().collect() | ||
52 | } | 54 | } |
53 | 55 | ||
54 | fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> { | 56 | fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> { |
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 727d743b5..a808de4f1 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs | |||
@@ -17,9 +17,9 @@ use hir::db::{AstDatabase, DefDatabase}; | |||
17 | use ra_db::{ | 17 | use ra_db::{ |
18 | salsa::{self, Database, Durability}, | 18 | salsa::{self, Database, Durability}, |
19 | Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, | 19 | Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, |
20 | SourceRootId, Upcast, | 20 | Upcast, |
21 | }; | 21 | }; |
22 | use rustc_hash::FxHashMap; | 22 | use rustc_hash::FxHashSet; |
23 | 23 | ||
24 | use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; | 24 | use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; |
25 | 25 | ||
@@ -36,7 +36,6 @@ use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; | |||
36 | #[derive(Debug)] | 36 | #[derive(Debug)] |
37 | pub struct RootDatabase { | 37 | pub struct RootDatabase { |
38 | runtime: salsa::Runtime<RootDatabase>, | 38 | runtime: salsa::Runtime<RootDatabase>, |
39 | pub(crate) debug_data: Arc<DebugData>, | ||
40 | pub last_gc: crate::wasm_shims::Instant, | 39 | pub last_gc: crate::wasm_shims::Instant, |
41 | pub last_gc_check: crate::wasm_shims::Instant, | 40 | pub last_gc_check: crate::wasm_shims::Instant, |
42 | } | 41 | } |
@@ -60,7 +59,7 @@ impl FileLoader for RootDatabase { | |||
60 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 59 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
61 | FileLoaderDelegate(self).resolve_path(anchor, path) | 60 | FileLoaderDelegate(self).resolve_path(anchor, path) |
62 | } | 61 | } |
63 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 62 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
64 | FileLoaderDelegate(self).relevant_crates(file_id) | 63 | FileLoaderDelegate(self).relevant_crates(file_id) |
65 | } | 64 | } |
66 | } | 65 | } |
@@ -98,7 +97,6 @@ impl RootDatabase { | |||
98 | runtime: salsa::Runtime::default(), | 97 | runtime: salsa::Runtime::default(), |
99 | last_gc: crate::wasm_shims::Instant::now(), | 98 | last_gc: crate::wasm_shims::Instant::now(), |
100 | last_gc_check: crate::wasm_shims::Instant::now(), | 99 | last_gc_check: crate::wasm_shims::Instant::now(), |
101 | debug_data: Default::default(), | ||
102 | }; | 100 | }; |
103 | db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); | 101 | db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); |
104 | db.set_local_roots_with_durability(Default::default(), Durability::HIGH); | 102 | db.set_local_roots_with_durability(Default::default(), Durability::HIGH); |
@@ -121,7 +119,6 @@ impl salsa::ParallelDatabase for RootDatabase { | |||
121 | runtime: self.runtime.snapshot(self), | 119 | runtime: self.runtime.snapshot(self), |
122 | last_gc: self.last_gc, | 120 | last_gc: self.last_gc, |
123 | last_gc_check: self.last_gc_check, | 121 | last_gc_check: self.last_gc_check, |
124 | debug_data: Arc::clone(&self.debug_data), | ||
125 | }) | 122 | }) |
126 | } | 123 | } |
127 | } | 124 | } |
@@ -135,14 +132,3 @@ fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> { | |||
135 | let text = db.file_text(file_id); | 132 | let text = db.file_text(file_id); |
136 | Arc::new(LineIndex::new(&*text)) | 133 | Arc::new(LineIndex::new(&*text)) |
137 | } | 134 | } |
138 | |||
139 | #[derive(Debug, Default, Clone)] | ||
140 | pub(crate) struct DebugData { | ||
141 | pub(crate) root_paths: FxHashMap<SourceRootId, String>, | ||
142 | } | ||
143 | |||
144 | impl DebugData { | ||
145 | pub(crate) fn merge(&mut self, other: DebugData) { | ||
146 | self.root_paths.extend(other.root_paths.into_iter()); | ||
147 | } | ||
148 | } | ||
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index acc31fe3b..aab918973 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs | |||
@@ -29,9 +29,10 @@ use std::{ | |||
29 | }; | 29 | }; |
30 | 30 | ||
31 | use fst::{self, Streamer}; | 31 | use fst::{self, Streamer}; |
32 | use hir::db::DefDatabase; | ||
32 | use ra_db::{ | 33 | use ra_db::{ |
33 | salsa::{self, ParallelDatabase}, | 34 | salsa::{self, ParallelDatabase}, |
34 | FileId, SourceDatabaseExt, SourceRootId, | 35 | CrateId, FileId, SourceDatabaseExt, SourceRootId, |
35 | }; | 36 | }; |
36 | use ra_syntax::{ | 37 | use ra_syntax::{ |
37 | ast::{self, NameOwner}, | 38 | ast::{self, NameOwner}, |
@@ -110,6 +111,14 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> | |||
110 | Arc::new(SymbolIndex::new(symbols)) | 111 | Arc::new(SymbolIndex::new(symbols)) |
111 | } | 112 | } |
112 | 113 | ||
114 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | ||
115 | struct Snap(salsa::Snapshot<RootDatabase>); | ||
116 | impl Clone for Snap { | ||
117 | fn clone(&self) -> Snap { | ||
118 | Snap(self.0.snapshot()) | ||
119 | } | ||
120 | } | ||
121 | |||
113 | // Feature: Workspace Symbol | 122 | // Feature: Workspace Symbol |
114 | // | 123 | // |
115 | // Uses fuzzy-search to find types, modules and functions by name across your | 124 | // Uses fuzzy-search to find types, modules and functions by name across your |
@@ -132,13 +141,7 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> | |||
132 | // | VS Code | kbd:[Ctrl+T] | 141 | // | VS Code | kbd:[Ctrl+T] |
133 | // |=== | 142 | // |=== |
134 | pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { | 143 | pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { |
135 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | 144 | let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone()); |
136 | struct Snap(salsa::Snapshot<RootDatabase>); | ||
137 | impl Clone for Snap { | ||
138 | fn clone(&self) -> Snap { | ||
139 | Snap(self.0.snapshot()) | ||
140 | } | ||
141 | } | ||
142 | 145 | ||
143 | let buf: Vec<Arc<SymbolIndex>> = if query.libs { | 146 | let buf: Vec<Arc<SymbolIndex>> = if query.libs { |
144 | let snap = Snap(db.snapshot()); | 147 | let snap = Snap(db.snapshot()); |
@@ -173,6 +176,33 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { | |||
173 | query.search(&buf) | 176 | query.search(&buf) |
174 | } | 177 | } |
175 | 178 | ||
179 | pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<FileSymbol> { | ||
180 | // FIXME(#4842): This now depends on CrateDefMap, why not build the entire symbol index from | ||
181 | // that instead? | ||
182 | |||
183 | let def_map = db.crate_def_map(krate); | ||
184 | let mut files = Vec::new(); | ||
185 | let mut modules = vec![def_map.root]; | ||
186 | while let Some(module) = modules.pop() { | ||
187 | let data = &def_map[module]; | ||
188 | files.extend(data.origin.file_id()); | ||
189 | modules.extend(data.children.values()); | ||
190 | } | ||
191 | |||
192 | let snap = Snap(db.snapshot()); | ||
193 | |||
194 | #[cfg(not(feature = "wasm"))] | ||
195 | let buf = files | ||
196 | .par_iter() | ||
197 | .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) | ||
198 | .collect::<Vec<_>>(); | ||
199 | |||
200 | #[cfg(feature = "wasm")] | ||
201 | let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect::<Vec<_>>(); | ||
202 | |||
203 | query.search(&buf) | ||
204 | } | ||
205 | |||
176 | pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymbol> { | 206 | pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymbol> { |
177 | let name = name_ref.text(); | 207 | let name = name_ref.text(); |
178 | let mut query = Query::new(name.to_string()); | 208 | let mut query = Query::new(name.to_string()); |
@@ -298,9 +328,6 @@ impl Query { | |||
298 | let mut stream = op.union(); | 328 | let mut stream = op.union(); |
299 | let mut res = Vec::new(); | 329 | let mut res = Vec::new(); |
300 | while let Some((_, indexed_values)) = stream.next() { | 330 | while let Some((_, indexed_values)) = stream.next() { |
301 | if res.len() >= self.limit { | ||
302 | break; | ||
303 | } | ||
304 | for indexed_value in indexed_values { | 331 | for indexed_value in indexed_values { |
305 | let symbol_index = &indices[indexed_value.index]; | 332 | let symbol_index = &indices[indexed_value.index]; |
306 | let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); | 333 | let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); |
@@ -312,7 +339,11 @@ impl Query { | |||
312 | if self.exact && symbol.name != self.query { | 339 | if self.exact && symbol.name != self.query { |
313 | continue; | 340 | continue; |
314 | } | 341 | } |
342 | |||
315 | res.push(symbol.clone()); | 343 | res.push(symbol.clone()); |
344 | if res.len() >= self.limit { | ||
345 | return res; | ||
346 | } | ||
316 | } | 347 | } |
317 | } | 348 | } |
318 | } | 349 | } |
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index c1f7e3ac5..cb0e27dce 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -47,17 +47,21 @@ pub struct PackageRoot { | |||
47 | path: PathBuf, | 47 | path: PathBuf, |
48 | /// Is a member of the current workspace | 48 | /// Is a member of the current workspace |
49 | is_member: bool, | 49 | is_member: bool, |
50 | out_dir: Option<PathBuf>, | ||
50 | } | 51 | } |
51 | impl PackageRoot { | 52 | impl PackageRoot { |
52 | pub fn new_member(path: PathBuf) -> PackageRoot { | 53 | pub fn new_member(path: PathBuf) -> PackageRoot { |
53 | Self { path, is_member: true } | 54 | Self { path, is_member: true, out_dir: None } |
54 | } | 55 | } |
55 | pub fn new_non_member(path: PathBuf) -> PackageRoot { | 56 | pub fn new_non_member(path: PathBuf) -> PackageRoot { |
56 | Self { path, is_member: false } | 57 | Self { path, is_member: false, out_dir: None } |
57 | } | 58 | } |
58 | pub fn path(&self) -> &Path { | 59 | pub fn path(&self) -> &Path { |
59 | &self.path | 60 | &self.path |
60 | } | 61 | } |
62 | pub fn out_dir(&self) -> Option<&Path> { | ||
63 | self.out_dir.as_deref() | ||
64 | } | ||
61 | pub fn is_member(&self) -> bool { | 65 | pub fn is_member(&self) -> bool { |
62 | self.is_member | 66 | self.is_member |
63 | } | 67 | } |
@@ -204,6 +208,7 @@ impl ProjectWorkspace { | |||
204 | .map(|pkg| PackageRoot { | 208 | .map(|pkg| PackageRoot { |
205 | path: cargo[pkg].root().to_path_buf(), | 209 | path: cargo[pkg].root().to_path_buf(), |
206 | is_member: cargo[pkg].is_member, | 210 | is_member: cargo[pkg].is_member, |
211 | out_dir: cargo[pkg].out_dir.clone(), | ||
207 | }) | 212 | }) |
208 | .chain(sysroot.crates().map(|krate| { | 213 | .chain(sysroot.crates().map(|krate| { |
209 | PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf()) | 214 | PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf()) |
@@ -212,17 +217,6 @@ impl ProjectWorkspace { | |||
212 | } | 217 | } |
213 | } | 218 | } |
214 | 219 | ||
215 | pub fn out_dirs(&self) -> Vec<PathBuf> { | ||
216 | match self { | ||
217 | ProjectWorkspace::Json { project } => { | ||
218 | project.crates.iter().filter_map(|krate| krate.out_dir.as_ref()).cloned().collect() | ||
219 | } | ||
220 | ProjectWorkspace::Cargo { cargo, sysroot: _ } => { | ||
221 | cargo.packages().filter_map(|pkg| cargo[pkg].out_dir.as_ref()).cloned().collect() | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | |||
226 | pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> { | 220 | pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> { |
227 | match self { | 221 | match self { |
228 | ProjectWorkspace::Json { project } => project | 222 | ProjectWorkspace::Json { project } => project |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 8f2aeac77..97367d7c6 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -36,28 +36,28 @@ pub fn load_cargo( | |||
36 | )?; | 36 | )?; |
37 | 37 | ||
38 | let mut extern_dirs = FxHashSet::default(); | 38 | let mut extern_dirs = FxHashSet::default(); |
39 | extern_dirs.extend(ws.out_dirs()); | ||
40 | |||
41 | let mut project_roots = ws.to_roots(); | ||
42 | project_roots.extend(extern_dirs.iter().cloned().map(PackageRoot::new_non_member)); | ||
43 | 39 | ||
44 | let (sender, receiver) = unbounded(); | 40 | let (sender, receiver) = unbounded(); |
45 | let sender = Box::new(move |t| sender.send(t).unwrap()); | 41 | let sender = Box::new(move |t| sender.send(t).unwrap()); |
46 | let (mut vfs, roots) = Vfs::new( | 42 | |
47 | project_roots | 43 | let mut roots = Vec::new(); |
48 | .iter() | 44 | let project_roots = ws.to_roots(); |
49 | .map(|pkg_root| { | 45 | for root in &project_roots { |
50 | RootEntry::new( | 46 | roots.push(RootEntry::new( |
51 | pkg_root.path().to_owned(), | 47 | root.path().to_owned(), |
52 | RustPackageFilterBuilder::default() | 48 | RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(), |
53 | .set_member(pkg_root.is_member()) | 49 | )); |
54 | .into_vfs_filter(), | 50 | |
55 | ) | 51 | if let Some(out_dir) = root.out_dir() { |
56 | }) | 52 | extern_dirs.insert(out_dir.to_path_buf()); |
57 | .collect(), | 53 | roots.push(RootEntry::new( |
58 | sender, | 54 | out_dir.to_owned(), |
59 | Watch(false), | 55 | RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(), |
60 | ); | 56 | )) |
57 | } | ||
58 | } | ||
59 | |||
60 | let (mut vfs, roots) = Vfs::new(roots, sender, Watch(false)); | ||
61 | 61 | ||
62 | let source_roots = roots | 62 | let source_roots = roots |
63 | .into_iter() | 63 | .into_iter() |
@@ -111,10 +111,6 @@ pub(crate) fn load( | |||
111 | vfs.root2path(root) | 111 | vfs.root2path(root) |
112 | ); | 112 | ); |
113 | analysis_change.add_root(source_root_id, is_local); | 113 | analysis_change.add_root(source_root_id, is_local); |
114 | analysis_change.set_debug_root_path( | ||
115 | source_root_id, | ||
116 | source_roots[&source_root_id].path().display().to_string(), | ||
117 | ); | ||
118 | 114 | ||
119 | let vfs_root_path = vfs.root2path(root); | 115 | let vfs_root_path = vfs.root2path(root); |
120 | if extern_dirs.contains(&vfs_root_path) { | 116 | if extern_dirs.contains(&vfs_root_path) { |
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 73b0f881d..21116e165 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -89,8 +89,7 @@ impl GlobalState { | |||
89 | ) -> GlobalState { | 89 | ) -> GlobalState { |
90 | let mut change = AnalysisChange::new(); | 90 | let mut change = AnalysisChange::new(); |
91 | 91 | ||
92 | let extern_dirs: FxHashSet<_> = | 92 | let mut extern_dirs: FxHashSet<PathBuf> = FxHashSet::default(); |
93 | workspaces.iter().flat_map(ProjectWorkspace::out_dirs).collect(); | ||
94 | 93 | ||
95 | let mut local_roots = Vec::new(); | 94 | let mut local_roots = Vec::new(); |
96 | let roots: Vec<_> = { | 95 | let roots: Vec<_> = { |
@@ -100,22 +99,22 @@ impl GlobalState { | |||
100 | .exclude(exclude_globs.iter().cloned()) | 99 | .exclude(exclude_globs.iter().cloned()) |
101 | .into_vfs_filter() | 100 | .into_vfs_filter() |
102 | }; | 101 | }; |
103 | workspaces | 102 | let mut roots = Vec::new(); |
104 | .iter() | 103 | for root in workspaces.iter().flat_map(ProjectWorkspace::to_roots) { |
105 | .flat_map(ProjectWorkspace::to_roots) | 104 | let path = root.path().to_owned(); |
106 | .map(|pkg_root| { | 105 | if root.is_member() { |
107 | let path = pkg_root.path().to_owned(); | 106 | local_roots.push(path.clone()); |
108 | if pkg_root.is_member() { | 107 | } |
109 | local_roots.push(path.clone()); | 108 | roots.push(RootEntry::new(path, create_filter(root.is_member()))); |
110 | } | 109 | if let Some(out_dir) = root.out_dir() { |
111 | RootEntry::new(path, create_filter(pkg_root.is_member())) | 110 | extern_dirs.insert(out_dir.to_path_buf()); |
112 | }) | 111 | roots.push(RootEntry::new( |
113 | .chain( | 112 | out_dir.to_path_buf(), |
114 | extern_dirs | 113 | create_filter(root.is_member()), |
115 | .iter() | 114 | )) |
116 | .map(|path| RootEntry::new(path.to_owned(), create_filter(false))), | 115 | } |
117 | ) | 116 | } |
118 | .collect() | 117 | roots |
119 | }; | 118 | }; |
120 | 119 | ||
121 | let (task_sender, task_receiver) = unbounded(); | 120 | let (task_sender, task_receiver) = unbounded(); |
@@ -127,7 +126,6 @@ impl GlobalState { | |||
127 | let vfs_root_path = vfs.root2path(r); | 126 | let vfs_root_path = vfs.root2path(r); |
128 | let is_local = local_roots.iter().any(|it| vfs_root_path.starts_with(it)); | 127 | let is_local = local_roots.iter().any(|it| vfs_root_path.starts_with(it)); |
129 | change.add_root(SourceRootId(r.0), is_local); | 128 | change.add_root(SourceRootId(r.0), is_local); |
130 | change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string()); | ||
131 | 129 | ||
132 | // FIXME: add path2root in vfs to simpily this logic | 130 | // FIXME: add path2root in vfs to simpily this logic |
133 | if extern_dirs.contains(&vfs_root_path) { | 131 | if extern_dirs.contains(&vfs_root_path) { |
diff --git a/docs/dev/README.md b/docs/dev/README.md index 0330939b6..ef5ffbf59 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -303,6 +303,17 @@ Rather than talking in definitions and references, it talks in Strings and textu | |||
303 | In general, API is centered around UI concerns -- the result of the call is what the user sees in the editor, and not what the compiler sees underneath. | 303 | In general, API is centered around UI concerns -- the result of the call is what the user sees in the editor, and not what the compiler sees underneath. |
304 | The results are 100% Rust specific though. | 304 | The results are 100% Rust specific though. |
305 | 305 | ||
306 | ## Parser Tests | ||
307 | |||
308 | Test for parser (`ra_parser`) live in `ra_syntax` crate (see `test_data` direcotory). | ||
309 | There are two kinds of tests: | ||
310 | |||
311 | * Manually written test cases in `parser/ok` and `parser/err` | ||
312 | * "Inline" tests in `parser/inline` (these are generated) from comments in `ra_parser` crate. | ||
313 | |||
314 | The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for. | ||
315 | If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test. | ||
316 | |||
306 | # Logging | 317 | # Logging |
307 | 318 | ||
308 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to | 319 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to |