diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/assists.rs | 7 | ||||
-rw-r--r-- | crates/ra_ide/src/imports_locator.rs | 97 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 1 |
3 files changed, 102 insertions, 3 deletions
diff --git a/crates/ra_ide/src/assists.rs b/crates/ra_ide/src/assists.rs index a936900da..c43c45c65 100644 --- a/crates/ra_ide/src/assists.rs +++ b/crates/ra_ide/src/assists.rs | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | use ra_db::{FilePosition, FileRange}; | 3 | use ra_db::{FilePosition, FileRange}; |
4 | 4 | ||
5 | use crate::{db::RootDatabase, FileId, SourceChange, SourceFileEdit}; | 5 | use crate::{ |
6 | 6 | db::RootDatabase, imports_locator::ImportsLocatorIde, FileId, SourceChange, SourceFileEdit, | |
7 | }; | ||
7 | use either::Either; | 8 | use either::Either; |
8 | pub use ra_assists::AssistId; | 9 | pub use ra_assists::AssistId; |
9 | use ra_assists::{AssistAction, AssistLabel}; | 10 | use ra_assists::{AssistAction, AssistLabel}; |
@@ -16,7 +17,7 @@ pub struct Assist { | |||
16 | } | 17 | } |
17 | 18 | ||
18 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { | 19 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { |
19 | ra_assists::assists(db, frange) | 20 | ra_assists::assists_with_imports_locator(db, frange, ImportsLocatorIde::new(db)) |
20 | .into_iter() | 21 | .into_iter() |
21 | .map(|assist| { | 22 | .map(|assist| { |
22 | let file_id = frange.file_id; | 23 | let file_id = frange.file_id; |
diff --git a/crates/ra_ide/src/imports_locator.rs b/crates/ra_ide/src/imports_locator.rs new file mode 100644 index 000000000..23391ac3b --- /dev/null +++ b/crates/ra_ide/src/imports_locator.rs | |||
@@ -0,0 +1,97 @@ | |||
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. | ||
3 | |||
4 | use crate::{ | ||
5 | db::RootDatabase, | ||
6 | references::{classify_name, classify_name_ref, NameDefinition, NameKind}, | ||
7 | symbol_index::{self, FileSymbol}, | ||
8 | Query, | ||
9 | }; | ||
10 | use ast::NameRef; | ||
11 | use hir::{db::HirDatabase, InFile, ModPath, Module, SourceBinder}; | ||
12 | use itertools::Itertools; | ||
13 | use ra_assists::ImportsLocator; | ||
14 | use ra_prof::profile; | ||
15 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; | ||
16 | |||
17 | pub(crate) struct ImportsLocatorIde<'a> { | ||
18 | source_binder: SourceBinder<'a, RootDatabase>, | ||
19 | } | ||
20 | |||
21 | impl<'a> ImportsLocatorIde<'a> { | ||
22 | pub(crate) fn new(db: &'a RootDatabase) -> Self { | ||
23 | Self { source_binder: SourceBinder::new(db) } | ||
24 | } | ||
25 | |||
26 | fn search_for_imports( | ||
27 | &mut self, | ||
28 | name_to_import: &ast::NameRef, | ||
29 | module_with_name_to_import: Module, | ||
30 | ) -> Vec<ModPath> { | ||
31 | let _p = profile("search_for_imports"); | ||
32 | let db = self.source_binder.db; | ||
33 | let name_to_import = name_to_import.text(); | ||
34 | |||
35 | let project_results = { | ||
36 | let mut query = Query::new(name_to_import.to_string()); | ||
37 | query.exact(); | ||
38 | query.limit(10); | ||
39 | symbol_index::world_symbols(db, query) | ||
40 | }; | ||
41 | let lib_results = { | ||
42 | let mut query = Query::new(name_to_import.to_string()); | ||
43 | query.libs(); | ||
44 | query.exact(); | ||
45 | query.limit(10); | ||
46 | symbol_index::world_symbols(db, query) | ||
47 | }; | ||
48 | |||
49 | project_results | ||
50 | .into_iter() | ||
51 | .chain(lib_results.into_iter()) | ||
52 | .filter_map(|import_candidate| self.get_name_definition(db, &import_candidate)) | ||
53 | .filter_map(|name_definition_to_import| { | ||
54 | if let NameKind::Def(module_def) = name_definition_to_import.kind { | ||
55 | module_with_name_to_import.find_use_path(db, module_def) | ||
56 | } else { | ||
57 | None | ||
58 | } | ||
59 | }) | ||
60 | .filter(|use_path| !use_path.segments.is_empty()) | ||
61 | .unique() | ||
62 | .collect() | ||
63 | } | ||
64 | |||
65 | fn get_name_definition( | ||
66 | &mut self, | ||
67 | db: &impl HirDatabase, | ||
68 | import_candidate: &FileSymbol, | ||
69 | ) -> Option<NameDefinition> { | ||
70 | let _p = profile("get_name_definition"); | ||
71 | let file_id = import_candidate.file_id.into(); | ||
72 | let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?); | ||
73 | let candidate_name_node = if candidate_node.kind() != NAME { | ||
74 | candidate_node.children().find(|it| it.kind() == NAME)? | ||
75 | } else { | ||
76 | candidate_node | ||
77 | }; | ||
78 | classify_name( | ||
79 | &mut self.source_binder, | ||
80 | hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? }, | ||
81 | ) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl<'a> ImportsLocator<'a> for ImportsLocatorIde<'a> { | ||
86 | fn find_imports( | ||
87 | &mut self, | ||
88 | name_to_import: InFile<&NameRef>, | ||
89 | module_with_name_to_import: Module, | ||
90 | ) -> Option<Vec<ModPath>> { | ||
91 | if classify_name_ref(&mut self.source_binder, name_to_import).is_none() { | ||
92 | Some(self.search_for_imports(name_to_import.value, module_with_name_to_import)) | ||
93 | } else { | ||
94 | None | ||
95 | } | ||
96 | } | ||
97 | } | ||
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 62fe6d2a9..03ad6b2c1 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -30,6 +30,7 @@ mod syntax_highlighting; | |||
30 | mod parent_module; | 30 | mod parent_module; |
31 | mod references; | 31 | mod references; |
32 | mod impls; | 32 | mod impls; |
33 | mod imports_locator; | ||
33 | mod assists; | 34 | mod assists; |
34 | mod diagnostics; | 35 | mod diagnostics; |
35 | mod syntax_tree; | 36 | mod syntax_tree; |