aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db/src/imports_locator.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_db/src/imports_locator.rs')
-rw-r--r--crates/ide_db/src/imports_locator.rs64
1 files changed, 64 insertions, 0 deletions
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs
new file mode 100644
index 000000000..ed67e3553
--- /dev/null
+++ b/crates/ide_db/src/imports_locator.rs
@@ -0,0 +1,64 @@
1//! This module contains an import search funcionality that is provided to the assists module.
2//! Later, this should be moved away to a separate crate that is accessible from the assists module.
3
4use hir::{Crate, MacroDef, ModuleDef, Semantics};
5use syntax::{ast, AstNode, SyntaxKind::NAME};
6
7use crate::{
8 defs::{classify_name, Definition},
9 symbol_index::{self, FileSymbol, Query},
10 RootDatabase,
11};
12use either::Either;
13use rustc_hash::FxHashSet;
14
15pub fn find_imports<'a>(
16 sema: &Semantics<'a, RootDatabase>,
17 krate: Crate,
18 name_to_import: &str,
19) -> Vec<Either<ModuleDef, MacroDef>> {
20 let _p = profile::span("search_for_imports");
21 let db = sema.db;
22
23 // Query dependencies first.
24 let mut candidates: FxHashSet<_> =
25 krate.query_external_importables(db, name_to_import).collect();
26
27 // Query the local crate using the symbol index.
28 let local_results = {
29 let mut query = Query::new(name_to_import.to_string());
30 query.exact();
31 query.limit(40);
32 symbol_index::crate_symbols(db, krate.into(), query)
33 };
34
35 candidates.extend(
36 local_results
37 .into_iter()
38 .filter_map(|import_candidate| get_name_definition(sema, &import_candidate))
39 .filter_map(|name_definition_to_import| match name_definition_to_import {
40 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)),
41 Definition::Macro(macro_def) => Some(Either::Right(macro_def)),
42 _ => None,
43 }),
44 );
45
46 candidates.into_iter().collect()
47}
48
49fn get_name_definition<'a>(
50 sema: &Semantics<'a, RootDatabase>,
51 import_candidate: &FileSymbol,
52) -> Option<Definition> {
53 let _p = profile::span("get_name_definition");
54 let file_id = import_candidate.file_id;
55
56 let candidate_node = import_candidate.ptr.to_node(sema.parse(file_id).syntax());
57 let candidate_name_node = if candidate_node.kind() != NAME {
58 candidate_node.children().find(|it| it.kind() == NAME)?
59 } else {
60 candidate_node
61 };
62 let name = ast::Name::cast(candidate_name_node)?;
63 classify_name(sema, &name)?.into_definition(sema.db)
64}