aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/Cargo.toml3
-rw-r--r--crates/ra_hir_def/src/body.rs2
-rw-r--r--crates/ra_hir_def/src/data.rs2
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs3
-rw-r--r--crates/ra_hir_def/src/find_path.rs59
-rw-r--r--crates/ra_hir_def/src/import_map.rs378
-rw-r--r--crates/ra_hir_def/src/lib.rs11
-rw-r--r--crates/ra_hir_def/src/nameres.rs3
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs39
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs8
-rw-r--r--crates/ra_hir_def/src/path.rs22
-rw-r--r--crates/ra_hir_def/src/test_db.rs3
12 files changed, 468 insertions, 65 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"
14either = "1.5.3" 14either = "1.5.3"
15anymap = "0.12.1" 15anymap = "0.12.1"
16drop_bomb = "0.1.4" 16drop_bomb = "0.1.4"
17fst = { version = "0.4", default-features = false }
18itertools = "0.9.0"
19indexmap = "1.4.0"
17 20
18stdx = { path = "../stdx" } 21stdx = { 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, &macro_call); 98 let macro_call = InFile::new(self.current_file_id, &macro_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
101fn desugar_future_path(orig: TypeRef) -> Path { 101fn 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/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs
index 510c5e064..30db48f86 100644
--- a/crates/ra_hir_def/src/diagnostics.rs
+++ b/crates/ra_hir_def/src/diagnostics.rs
@@ -3,7 +3,6 @@
3use std::any::Any; 3use std::any::Any;
4 4
5use hir_expand::diagnostics::Diagnostic; 5use hir_expand::diagnostics::Diagnostic;
6use ra_db::RelativePathBuf;
7use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; 6use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
8 7
9use hir_expand::{HirFileId, InFile}; 8use hir_expand::{HirFileId, InFile};
@@ -12,7 +11,7 @@ use hir_expand::{HirFileId, InFile};
12pub struct UnresolvedModule { 11pub struct UnresolvedModule {
13 pub file: HirFileId, 12 pub file: HirFileId,
14 pub decl: AstPtr<ast::Module>, 13 pub decl: AstPtr<ast::Module>,
15 pub candidate: RelativePathBuf, 14 pub candidate: String,
16} 15}
17 16
18impl Diagnostic for UnresolvedModule { 17impl Diagnostic for UnresolvedModule {
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs
index a7f59e028..06701a830 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -159,10 +159,16 @@ fn find_path_inner(
159 let crate_graph = db.crate_graph(); 159 let crate_graph = db.crate_graph();
160 let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { 160 let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
161 let import_map = db.import_map(dep.crate_id); 161 let import_map = db.import_map(dep.crate_id);
162 import_map.path_of(item).map(|modpath| { 162 import_map.import_info_for(item).and_then(|info| {
163 let mut modpath = modpath.clone(); 163 // Determine best path for containing module and append last segment from `info`.
164 modpath.segments.insert(0, dep.as_name()); 164 let mut path = find_path_inner(
165 modpath 165 db,
166 ItemInNs::Types(ModuleDefId::ModuleId(info.container)),
167 from,
168 best_path_len - 1,
169 )?;
170 path.segments.push(info.path.segments.last().unwrap().clone());
171 Some(path)
166 }) 172 })
167 }); 173 });
168 174
@@ -299,8 +305,8 @@ mod tests {
299 /// `code` needs to contain a cursor marker; checks that `find_path` for the 305 /// `code` needs to contain a cursor marker; checks that `find_path` for the
300 /// item the `path` refers to returns that same path when called from the 306 /// item the `path` refers to returns that same path when called from the
301 /// module the cursor is in. 307 /// module the cursor is in.
302 fn check_found_path(code: &str, path: &str) { 308 fn check_found_path(ra_fixture: &str, path: &str) {
303 let (db, pos) = TestDB::with_position(code); 309 let (db, pos) = TestDB::with_position(ra_fixture);
304 let module = db.module_for_file(pos.file_id); 310 let module = db.module_for_file(pos.file_id);
305 let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); 311 let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path));
306 let ast_path = parsed_path_file 312 let ast_path = parsed_path_file
@@ -420,7 +426,6 @@ mod tests {
420 426
421 #[test] 427 #[test]
422 fn different_crate_renamed() { 428 fn different_crate_renamed() {
423 // Even if a local path exists, if the item is defined externally, prefer an external path.
424 let code = r#" 429 let code = r#"
425 //- /main.rs crate:main deps:std 430 //- /main.rs crate:main deps:std
426 extern crate std as std_renamed; 431 extern crate std as std_renamed;
@@ -428,7 +433,45 @@ mod tests {
428 //- /std.rs crate:std 433 //- /std.rs crate:std
429 pub struct S; 434 pub struct S;
430 "#; 435 "#;
431 check_found_path(code, "std::S"); 436 check_found_path(code, "std_renamed::S");
437 }
438
439 #[test]
440 fn partially_imported() {
441 // Tests that short paths are used even for external items, when parts of the path are
442 // already in scope.
443 check_found_path(
444 r#"
445 //- /main.rs crate:main deps:ra_syntax
446
447 use ra_syntax::ast;
448 <|>
449
450 //- /lib.rs crate:ra_syntax
451 pub mod ast {
452 pub enum ModuleItem {
453 A, B, C,
454 }
455 }
456 "#,
457 "ast::ModuleItem",
458 );
459
460 check_found_path(
461 r#"
462 //- /main.rs crate:main deps:ra_syntax
463
464 <|>
465
466 //- /lib.rs crate:ra_syntax
467 pub mod ast {
468 pub enum ModuleItem {
469 A, B, C,
470 }
471 }
472 "#,
473 "ra_syntax::ast::ModuleItem",
474 );
432 } 475 }
433 476
434 #[test] 477 #[test]
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs
index 4284a0a91..68e20d06b 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
3use std::{collections::hash_map::Entry, fmt, sync::Arc}; 3use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc};
4 4
5use fst::{self, Streamer};
6use indexmap::{map::Entry, IndexMap};
5use ra_db::CrateId; 7use ra_db::CrateId;
6use rustc_hash::FxHashMap; 8use rustc_hash::FxHasher;
7 9
8use crate::{ 10use crate::{
9 db::DefDatabase, 11 db::DefDatabase,
@@ -13,6 +15,17 @@ use crate::{
13 ModuleDefId, ModuleId, 15 ModuleDefId, ModuleId,
14}; 16};
15 17
18type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
19
20/// Item import details stored in the `ImportMap`.
21#[derive(Debug, Clone, Eq, PartialEq)]
22pub struct ImportInfo {
23 /// A path that can be used to import the item, relative to the crate's root.
24 pub path: ModPath,
25 /// The module containing this item.
26 pub container: ModuleId,
27}
28
16/// A map from publicly exported items to the path needed to import/name them from a downstream 29/// A map from publicly exported items to the path needed to import/name them from a downstream
17/// crate. 30/// crate.
18/// 31///
@@ -21,16 +34,24 @@ use crate::{
21/// 34///
22/// Note that all paths are relative to the containing crate's root, so the crate name still needs 35/// 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. 36/// to be prepended to the `ModPath` before the path is valid.
24#[derive(Eq, PartialEq)]
25pub struct ImportMap { 37pub struct ImportMap {
26 map: FxHashMap<ItemInNs, ModPath>, 38 map: FxIndexMap<ItemInNs, ImportInfo>,
39
40 /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the
41 /// values returned by running `fst`.
42 ///
43 /// Since a path can refer to multiple items due to namespacing, we store all items with the
44 /// same path right after each other. This allows us to find all items after the FST gives us
45 /// the index of the first one.
46 importables: Vec<ItemInNs>,
47 fst: fst::Map<Vec<u8>>,
27} 48}
28 49
29impl ImportMap { 50impl ImportMap {
30 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { 51 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
31 let _p = ra_prof::profile("import_map_query"); 52 let _p = ra_prof::profile("import_map_query");
32 let def_map = db.crate_def_map(krate); 53 let def_map = db.crate_def_map(krate);
33 let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default()); 54 let mut import_map = FxIndexMap::with_capacity_and_hasher(64, Default::default());
34 55
35 // We look only into modules that are public(ly reexported), starting with the crate root. 56 // We look only into modules that are public(ly reexported), starting with the crate root.
36 let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; 57 let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
@@ -66,12 +87,12 @@ impl ImportMap {
66 let path = mk_path(); 87 let path = mk_path();
67 match import_map.entry(item) { 88 match import_map.entry(item) {
68 Entry::Vacant(entry) => { 89 Entry::Vacant(entry) => {
69 entry.insert(path); 90 entry.insert(ImportInfo { path, container: module });
70 } 91 }
71 Entry::Occupied(mut entry) => { 92 Entry::Occupied(mut entry) => {
72 // If the new path is shorter, prefer that one. 93 // If the new path is shorter, prefer that one.
73 if path.len() < entry.get().len() { 94 if path.len() < entry.get().path.len() {
74 *entry.get_mut() = path; 95 *entry.get_mut() = ImportInfo { path, container: module };
75 } else { 96 } else {
76 continue; 97 continue;
77 } 98 }
@@ -88,27 +109,67 @@ impl ImportMap {
88 } 109 }
89 } 110 }
90 111
91 Arc::new(Self { map: import_map }) 112 let mut importables = import_map.iter().collect::<Vec<_>>();
113
114 importables.sort_by(cmp);
115
116 // Build the FST, taking care not to insert duplicate values.
117
118 let mut builder = fst::MapBuilder::memory();
119 let mut last_batch_start = 0;
120
121 for idx in 0..importables.len() {
122 if let Some(next_item) = importables.get(idx + 1) {
123 if cmp(&importables[last_batch_start], next_item) == Ordering::Equal {
124 continue;
125 }
126 }
127
128 let start = last_batch_start;
129 last_batch_start = idx + 1;
130
131 let key = fst_path(&importables[start].1.path);
132
133 builder.insert(key, start as u64).unwrap();
134 }
135
136 let fst = fst::Map::new(builder.into_inner().unwrap()).unwrap();
137 let importables = importables.iter().map(|(item, _)| **item).collect();
138
139 Arc::new(Self { map: import_map, fst, importables })
92 } 140 }
93 141
94 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. 142 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
95 pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> { 143 pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> {
144 Some(&self.map.get(&item)?.path)
145 }
146
147 pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> {
96 self.map.get(&item) 148 self.map.get(&item)
97 } 149 }
98} 150}
99 151
152impl PartialEq for ImportMap {
153 fn eq(&self, other: &Self) -> bool {
154 // `fst` and `importables` are built from `map`, so we don't need to compare them.
155 self.map == other.map
156 }
157}
158
159impl Eq for ImportMap {}
160
100impl fmt::Debug for ImportMap { 161impl fmt::Debug for ImportMap {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 let mut importable_paths: Vec<_> = self 163 let mut importable_paths: Vec<_> = self
103 .map 164 .map
104 .iter() 165 .iter()
105 .map(|(item, modpath)| { 166 .map(|(item, info)| {
106 let ns = match item { 167 let ns = match item {
107 ItemInNs::Types(_) => "t", 168 ItemInNs::Types(_) => "t",
108 ItemInNs::Values(_) => "v", 169 ItemInNs::Values(_) => "v",
109 ItemInNs::Macros(_) => "m", 170 ItemInNs::Macros(_) => "m",
110 }; 171 };
111 format!("- {} ({})", modpath, ns) 172 format!("- {} ({})", info.path, ns)
112 }) 173 })
113 .collect(); 174 .collect();
114 175
@@ -117,19 +178,135 @@ impl fmt::Debug for ImportMap {
117 } 178 }
118} 179}
119 180
181fn fst_path(path: &ModPath) -> String {
182 let mut s = path.to_string();
183 s.make_ascii_lowercase();
184 s
185}
186
187fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering {
188 let lhs_str = fst_path(&lhs.path);
189 let rhs_str = fst_path(&rhs.path);
190 lhs_str.cmp(&rhs_str)
191}
192
193#[derive(Debug)]
194pub struct Query {
195 query: String,
196 lowercased: String,
197 anchor_end: bool,
198 case_sensitive: bool,
199 limit: usize,
200}
201
202impl Query {
203 pub fn new(query: &str) -> Self {
204 Self {
205 lowercased: query.to_lowercase(),
206 query: query.to_string(),
207 anchor_end: false,
208 case_sensitive: false,
209 limit: usize::max_value(),
210 }
211 }
212
213 /// Only returns items whose paths end with the (case-insensitive) query string as their last
214 /// segment.
215 pub fn anchor_end(self) -> Self {
216 Self { anchor_end: true, ..self }
217 }
218
219 /// Limits the returned number of items to `limit`.
220 pub fn limit(self, limit: usize) -> Self {
221 Self { limit, ..self }
222 }
223
224 /// Respect casing of the query string when matching.
225 pub fn case_sensitive(self) -> Self {
226 Self { case_sensitive: true, ..self }
227 }
228}
229
230/// Searches dependencies of `krate` for an importable path matching `query`.
231///
232/// This returns a list of items that could be imported from dependencies of `krate`.
233pub fn search_dependencies<'a>(
234 db: &'a dyn DefDatabase,
235 krate: CrateId,
236 query: Query,
237) -> Vec<ItemInNs> {
238 let _p = ra_prof::profile("search_dependencies").detail(|| format!("{:?}", query));
239
240 let graph = db.crate_graph();
241 let import_maps: Vec<_> =
242 graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect();
243
244 let automaton = fst::automaton::Subsequence::new(&query.lowercased);
245
246 let mut op = fst::map::OpBuilder::new();
247 for map in &import_maps {
248 op = op.add(map.fst.search(&automaton));
249 }
250
251 let mut stream = op.union();
252 let mut res = Vec::new();
253 while let Some((_, indexed_values)) = stream.next() {
254 for indexed_value in indexed_values {
255 let import_map = &import_maps[indexed_value.index];
256 let importables = &import_map.importables[indexed_value.value as usize..];
257
258 // Path shared by the importable items in this group.
259 let path = &import_map.map[&importables[0]].path;
260
261 if query.anchor_end {
262 // Last segment must match query.
263 let last = path.segments.last().unwrap().to_string();
264 if last.to_lowercase() != query.lowercased {
265 continue;
266 }
267 }
268
269 // Add the items from this `ModPath` group. Those are all subsequent items in
270 // `importables` whose paths match `path`.
271 let iter = importables.iter().copied().take_while(|item| {
272 let item_path = &import_map.map[item].path;
273 fst_path(item_path) == fst_path(path)
274 });
275
276 if query.case_sensitive {
277 // FIXME: This does not do a subsequence match.
278 res.extend(iter.filter(|item| {
279 let item_path = &import_map.map[item].path;
280 item_path.to_string().contains(&query.query)
281 }));
282 } else {
283 res.extend(iter);
284 }
285
286 if res.len() >= query.limit {
287 res.truncate(query.limit);
288 return res;
289 }
290 }
291 }
292
293 res
294}
295
120#[cfg(test)] 296#[cfg(test)]
121mod tests { 297mod tests {
122 use super::*; 298 use super::*;
123 use crate::test_db::TestDB; 299 use crate::test_db::TestDB;
124 use insta::assert_snapshot; 300 use insta::assert_snapshot;
301 use itertools::Itertools;
125 use ra_db::fixture::WithFixture; 302 use ra_db::fixture::WithFixture;
126 use ra_db::SourceDatabase; 303 use ra_db::{SourceDatabase, Upcast};
127 304
128 fn import_map(ra_fixture: &str) -> String { 305 fn import_map(ra_fixture: &str) -> String {
129 let db = TestDB::with_files(ra_fixture); 306 let db = TestDB::with_files(ra_fixture);
130 let crate_graph = db.crate_graph(); 307 let crate_graph = db.crate_graph();
131 308
132 let import_maps: Vec<_> = crate_graph 309 let s = crate_graph
133 .iter() 310 .iter()
134 .filter_map(|krate| { 311 .filter_map(|krate| {
135 let cdata = &crate_graph[krate]; 312 let cdata = &crate_graph[krate];
@@ -139,9 +316,41 @@ mod tests {
139 316
140 Some(format!("{}:\n{:?}", name, map)) 317 Some(format!("{}:\n{:?}", name, map))
141 }) 318 })
142 .collect(); 319 .join("\n");
320 s
321 }
143 322
144 import_maps.join("\n") 323 fn search_dependencies_of(ra_fixture: &str, krate_name: &str, query: Query) -> String {
324 let db = TestDB::with_files(ra_fixture);
325 let crate_graph = db.crate_graph();
326 let krate = crate_graph
327 .iter()
328 .find(|krate| {
329 crate_graph[*krate].display_name.as_ref().map(|n| n.to_string())
330 == Some(krate_name.to_string())
331 })
332 .unwrap();
333
334 search_dependencies(db.upcast(), krate, query)
335 .into_iter()
336 .filter_map(|item| {
337 let mark = match item {
338 ItemInNs::Types(_) => "t",
339 ItemInNs::Values(_) => "v",
340 ItemInNs::Macros(_) => "m",
341 };
342 item.krate(db.upcast()).map(|krate| {
343 let map = db.import_map(krate);
344 let path = map.path_of(item).unwrap();
345 format!(
346 "{}::{} ({})",
347 crate_graph[krate].display_name.as_ref().unwrap(),
348 path,
349 mark
350 )
351 })
352 })
353 .join("\n")
145 } 354 }
146 355
147 #[test] 356 #[test]
@@ -328,4 +537,143 @@ mod tests {
328 lib: 537 lib:
329 "###); 538 "###);
330 } 539 }
540
541 #[test]
542 fn namespacing() {
543 let map = import_map(
544 r"
545 //- /lib.rs crate:lib
546 pub struct Thing; // t + v
547 #[macro_export]
548 macro_rules! Thing { // m
549 () => {};
550 }
551 ",
552 );
553
554 assert_snapshot!(map, @r###"
555 lib:
556 - Thing (m)
557 - Thing (t)
558 - Thing (v)
559 "###);
560
561 let map = import_map(
562 r"
563 //- /lib.rs crate:lib
564 pub mod Thing {} // t
565 #[macro_export]
566 macro_rules! Thing { // m
567 () => {};
568 }
569 ",
570 );
571
572 assert_snapshot!(map, @r###"
573 lib:
574 - Thing (m)
575 - Thing (t)
576 "###);
577 }
578
579 #[test]
580 fn search() {
581 let ra_fixture = r#"
582 //- /main.rs crate:main deps:dep
583 //- /dep.rs crate:dep deps:tdep
584 use tdep::fmt as fmt_dep;
585 pub mod fmt {
586 pub trait Display {
587 fn fmt();
588 }
589 }
590 #[macro_export]
591 macro_rules! Fmt {
592 () => {};
593 }
594 pub struct Fmt;
595
596 pub fn format() {}
597 pub fn no() {}
598
599 //- /tdep.rs crate:tdep
600 pub mod fmt {
601 pub struct NotImportableFromMain;
602 }
603 "#;
604
605 let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt"));
606 assert_snapshot!(res, @r###"
607 dep::fmt (t)
608 dep::Fmt (t)
609 dep::Fmt (v)
610 dep::Fmt (m)
611 dep::fmt::Display (t)
612 dep::format (v)
613 "###);
614
615 let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt").anchor_end());
616 assert_snapshot!(res, @r###"
617 dep::fmt (t)
618 dep::Fmt (t)
619 dep::Fmt (v)
620 dep::Fmt (m)
621 "###);
622 }
623
624 #[test]
625 fn search_casing() {
626 let ra_fixture = r#"
627 //- /main.rs crate:main deps:dep
628 //- /dep.rs crate:dep
629
630 pub struct fmt;
631 pub struct FMT;
632 "#;
633
634 let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT"));
635
636 assert_snapshot!(res, @r###"
637 dep::fmt (t)
638 dep::fmt (v)
639 dep::FMT (t)
640 dep::FMT (v)
641 "###);
642
643 let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive());
644
645 assert_snapshot!(res, @r###"
646 dep::FMT (t)
647 dep::FMT (v)
648 "###);
649 }
650
651 #[test]
652 fn search_limit() {
653 let res = search_dependencies_of(
654 r#"
655 //- /main.rs crate:main deps:dep
656 //- /dep.rs crate:dep
657 pub mod fmt {
658 pub trait Display {
659 fn fmt();
660 }
661 }
662 #[macro_export]
663 macro_rules! Fmt {
664 () => {};
665 }
666 pub struct Fmt;
667
668 pub fn format() {}
669 pub fn no() {}
670 "#,
671 "main",
672 Query::new("").limit(2),
673 );
674 assert_snapshot!(res, @r###"
675 dep::fmt (t)
676 dep::Fmt (t)
677 "###);
678 }
331} 679}
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.rs b/crates/ra_hir_def/src/nameres.rs
index f279c2ad4..b3e5f491a 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -296,7 +296,6 @@ pub enum ModuleSource {
296 296
297mod diagnostics { 297mod diagnostics {
298 use hir_expand::diagnostics::DiagnosticSink; 298 use hir_expand::diagnostics::DiagnosticSink;
299 use ra_db::RelativePathBuf;
300 use ra_syntax::{ast, AstPtr}; 299 use ra_syntax::{ast, AstPtr};
301 300
302 use crate::{db::DefDatabase, diagnostics::UnresolvedModule, nameres::LocalModuleId, AstId}; 301 use crate::{db::DefDatabase, diagnostics::UnresolvedModule, nameres::LocalModuleId, AstId};
@@ -306,7 +305,7 @@ mod diagnostics {
306 UnresolvedModule { 305 UnresolvedModule {
307 module: LocalModuleId, 306 module: LocalModuleId,
308 declaration: AstId<ast::Module>, 307 declaration: AstId<ast::Module>,
309 candidate: RelativePathBuf, 308 candidate: String,
310 }, 309 },
311 } 310 }
312 311
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/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs
index cede4a6fc..19fe0615a 100644
--- a/crates/ra_hir_def/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs
@@ -44,7 +44,7 @@ impl ModDir {
44 file_id: HirFileId, 44 file_id: HirFileId,
45 name: &Name, 45 name: &Name,
46 attr_path: Option<&SmolStr>, 46 attr_path: Option<&SmolStr>,
47 ) -> Result<(FileId, ModDir), RelativePathBuf> { 47 ) -> Result<(FileId, ModDir), String> {
48 let file_id = file_id.original_file(db.upcast()); 48 let file_id = file_id.original_file(db.upcast());
49 49
50 let mut candidate_files = Vec::new(); 50 let mut candidate_files = Vec::new();
@@ -52,11 +52,11 @@ impl ModDir {
52 Some(attr_path) => { 52 Some(attr_path) => {
53 let base = 53 let base =
54 if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path }; 54 if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path };
55 candidate_files.push(base.join(attr_path)) 55 candidate_files.push(base.join(attr_path).to_string())
56 } 56 }
57 None => { 57 None => {
58 candidate_files.push(self.path.join(&format!("{}.rs", name))); 58 candidate_files.push(self.path.join(&format!("{}.rs", name)).to_string());
59 candidate_files.push(self.path.join(&format!("{}/mod.rs", name))); 59 candidate_files.push(self.path.join(&format!("{}/mod.rs", name)).to_string());
60 } 60 }
61 }; 61 };
62 62
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index bfa921de2..190d6d98d 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -154,7 +154,7 @@ pub enum GenericArg {
154 154
155impl Path { 155impl Path {
156 /// Converts an `ast::Path` to `Path`. Works with use trees. 156 /// Converts an `ast::Path` to `Path`. Works with use trees.
157 /// DEPRECATED: It does not handle `$crate` from macro call. 157 #[deprecated = "Doesn't handle hygiene, don't add new calls, remove old ones"]
158 pub fn from_ast(path: ast::Path) -> Option<Path> { 158 pub fn from_ast(path: ast::Path) -> Option<Path> {
159 lower::lower_path(path, &Hygiene::new_unhygienic()) 159 lower::lower_path(path, &Hygiene::new_unhygienic())
160 } 160 }
@@ -323,16 +323,16 @@ pub use hir_expand::name as __name;
323 323
324#[macro_export] 324#[macro_export]
325macro_rules! __known_path { 325macro_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
8use hir_expand::db::AstDatabase; 8use hir_expand::db::AstDatabase;
9use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; 9use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
10use rustc_hash::FxHashSet;
10 11
11use crate::db::DefDatabase; 12use 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}