diff options
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r-- | crates/ra_hir_def/Cargo.toml | 3 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/import_map.rs | 355 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 39 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir_def/src/test_db.rs | 3 |
8 files changed, 392 insertions, 43 deletions
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 | } |