diff options
30 files changed, 1249 insertions, 1060 deletions
diff --git a/Cargo.lock b/Cargo.lock index b4d466fb6..bacea8dc3 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -604,10 +604,11 @@ name = "ra_analysis" | |||
604 | version = "0.1.0" | 604 | version = "0.1.0" |
605 | dependencies = [ | 605 | dependencies = [ |
606 | "fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", | 606 | "fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", |
607 | "id-arena 1.0.2 (git+https://github.com/fitzgen/id-arena/?rev=43ecd67)", | ||
608 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | 607 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", |
609 | "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", | 608 | "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", |
609 | "ra_db 0.1.0", | ||
610 | "ra_editor 0.1.0", | 610 | "ra_editor 0.1.0", |
611 | "ra_hir 0.1.0", | ||
611 | "ra_syntax 0.1.0", | 612 | "ra_syntax 0.1.0", |
612 | "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | 613 | "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", |
613 | "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | 614 | "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
@@ -629,6 +630,21 @@ dependencies = [ | |||
629 | ] | 630 | ] |
630 | 631 | ||
631 | [[package]] | 632 | [[package]] |
633 | name = "ra_db" | ||
634 | version = "0.1.0" | ||
635 | dependencies = [ | ||
636 | "id-arena 1.0.2 (git+https://github.com/fitzgen/id-arena/?rev=43ecd67)", | ||
637 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||
638 | "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||
639 | "ra_editor 0.1.0", | ||
640 | "ra_syntax 0.1.0", | ||
641 | "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||
642 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||
643 | "salsa 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||
644 | "test_utils 0.1.0", | ||
645 | ] | ||
646 | |||
647 | [[package]] | ||
632 | name = "ra_editor" | 648 | name = "ra_editor" |
633 | version = "0.1.0" | 649 | version = "0.1.0" |
634 | dependencies = [ | 650 | dependencies = [ |
@@ -641,6 +657,22 @@ dependencies = [ | |||
641 | ] | 657 | ] |
642 | 658 | ||
643 | [[package]] | 659 | [[package]] |
660 | name = "ra_hir" | ||
661 | version = "0.1.0" | ||
662 | dependencies = [ | ||
663 | "id-arena 1.0.2 (git+https://github.com/fitzgen/id-arena/?rev=43ecd67)", | ||
664 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||
665 | "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||
666 | "ra_db 0.1.0", | ||
667 | "ra_editor 0.1.0", | ||
668 | "ra_syntax 0.1.0", | ||
669 | "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||
670 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||
671 | "salsa 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||
672 | "test_utils 0.1.0", | ||
673 | ] | ||
674 | |||
675 | [[package]] | ||
644 | name = "ra_lsp_server" | 676 | name = "ra_lsp_server" |
645 | version = "0.1.0" | 677 | version = "0.1.0" |
646 | dependencies = [ | 678 | dependencies = [ |
diff --git a/crates/ra_analysis/Cargo.toml b/crates/ra_analysis/Cargo.toml index 5dae45857..fe9765a66 100644 --- a/crates/ra_analysis/Cargo.toml +++ b/crates/ra_analysis/Cargo.toml | |||
@@ -12,7 +12,8 @@ fst = "0.3.1" | |||
12 | salsa = "0.8.0" | 12 | salsa = "0.8.0" |
13 | rustc-hash = "1.0" | 13 | rustc-hash = "1.0" |
14 | parking_lot = "0.6.4" | 14 | parking_lot = "0.6.4" |
15 | id-arena = { git = "https://github.com/fitzgen/id-arena/", rev = "43ecd67" } | ||
16 | ra_syntax = { path = "../ra_syntax" } | 15 | ra_syntax = { path = "../ra_syntax" } |
17 | ra_editor = { path = "../ra_editor" } | 16 | ra_editor = { path = "../ra_editor" } |
17 | ra_db = { path = "../ra_db" } | ||
18 | hir = { path = "../ra_hir", package = "ra_hir" } | ||
18 | test_utils = { path = "../test_utils" } | 19 | test_utils = { path = "../test_utils" } |
diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs index 5ef278127..e5ba92acd 100644 --- a/crates/ra_analysis/src/completion/mod.rs +++ b/crates/ra_analysis/src/completion/mod.rs | |||
@@ -7,13 +7,11 @@ use ra_syntax::{ | |||
7 | AstNode, AtomEdit, | 7 | AstNode, AtomEdit, |
8 | SyntaxNodeRef, | 8 | SyntaxNodeRef, |
9 | }; | 9 | }; |
10 | use ra_db::SyntaxDatabase; | ||
10 | use rustc_hash::{FxHashMap}; | 11 | use rustc_hash::{FxHashMap}; |
11 | 12 | ||
12 | use crate::{ | 13 | use crate::{ |
13 | db::{self, SyntaxDatabase}, | 14 | db, |
14 | descriptors::{ | ||
15 | module::{ModuleDescriptor} | ||
16 | }, | ||
17 | Cancelable, FilePosition | 15 | Cancelable, FilePosition |
18 | }; | 16 | }; |
19 | 17 | ||
@@ -31,14 +29,14 @@ pub(crate) fn completions( | |||
31 | db: &db::RootDatabase, | 29 | db: &db::RootDatabase, |
32 | position: FilePosition, | 30 | position: FilePosition, |
33 | ) -> Cancelable<Option<Vec<CompletionItem>>> { | 31 | ) -> Cancelable<Option<Vec<CompletionItem>>> { |
34 | let original_file = db.file_syntax(position.file_id); | 32 | let original_file = db.source_file(position.file_id); |
35 | // Insert a fake ident to get a valid parse tree | 33 | // Insert a fake ident to get a valid parse tree |
36 | let file = { | 34 | let file = { |
37 | let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string()); | 35 | let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string()); |
38 | original_file.reparse(&edit) | 36 | original_file.reparse(&edit) |
39 | }; | 37 | }; |
40 | 38 | ||
41 | let module = ctry!(ModuleDescriptor::guess_from_position(db, position)?); | 39 | let module = ctry!(hir::Module::guess_from_position(db, position)?); |
42 | 40 | ||
43 | let mut res = Vec::new(); | 41 | let mut res = Vec::new(); |
44 | let mut has_completions = false; | 42 | let mut has_completions = false; |
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index 858b52e76..e1a2d5241 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs | |||
@@ -6,23 +6,23 @@ use ra_syntax::{ | |||
6 | ast::{self, LoopBodyOwner}, | 6 | ast::{self, LoopBodyOwner}, |
7 | SyntaxKind::*, | 7 | SyntaxKind::*, |
8 | }; | 8 | }; |
9 | use hir::{ | ||
10 | self, | ||
11 | FnScopes, | ||
12 | Def, | ||
13 | Path, | ||
14 | }; | ||
9 | 15 | ||
10 | use crate::{ | 16 | use crate::{ |
11 | db::RootDatabase, | 17 | db::RootDatabase, |
12 | completion::CompletionItem, | 18 | completion::CompletionItem, |
13 | descriptors::{ | ||
14 | module::{ModuleDescriptor}, | ||
15 | function::FnScopes, | ||
16 | Def, | ||
17 | Path, | ||
18 | }, | ||
19 | Cancelable | 19 | Cancelable |
20 | }; | 20 | }; |
21 | 21 | ||
22 | pub(super) fn completions( | 22 | pub(super) fn completions( |
23 | acc: &mut Vec<CompletionItem>, | 23 | acc: &mut Vec<CompletionItem>, |
24 | db: &RootDatabase, | 24 | db: &RootDatabase, |
25 | module: &ModuleDescriptor, | 25 | module: &hir::Module, |
26 | file: &SourceFileNode, | 26 | file: &SourceFileNode, |
27 | name_ref: ast::NameRef, | 27 | name_ref: ast::NameRef, |
28 | ) -> Cancelable<()> { | 28 | ) -> Cancelable<()> { |
@@ -150,7 +150,7 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<Completi | |||
150 | fn complete_path( | 150 | fn complete_path( |
151 | acc: &mut Vec<CompletionItem>, | 151 | acc: &mut Vec<CompletionItem>, |
152 | db: &RootDatabase, | 152 | db: &RootDatabase, |
153 | module: &ModuleDescriptor, | 153 | module: &hir::Module, |
154 | mut path: Path, | 154 | mut path: Path, |
155 | ) -> Cancelable<()> { | 155 | ) -> Cancelable<()> { |
156 | if path.segments.is_empty() { | 156 | if path.segments.is_empty() { |
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index 4e34265fb..7fc3fe31b 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -1,17 +1,12 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | #[cfg(test)] | 2 | #[cfg(test)] |
3 | use parking_lot::Mutex; | 3 | use parking_lot::Mutex; |
4 | use ra_editor::LineIndex; | ||
5 | use ra_syntax::{SourceFileNode, SyntaxNode}; | ||
6 | use salsa::{self, Database}; | 4 | use salsa::{self, Database}; |
5 | use ra_db::{LocationIntener, BaseDatabase}; | ||
6 | use hir::{self, DefId, DefLoc, FnId, SourceItemId}; | ||
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | db, | 9 | symbol_index, |
10 | descriptors, | ||
11 | symbol_index::SymbolIndex, | ||
12 | syntax_ptr::SyntaxPtr, | ||
13 | loc2id::{IdMaps, IdDatabase}, | ||
14 | Cancelable, Canceled, FileId, | ||
15 | }; | 10 | }; |
16 | 11 | ||
17 | #[derive(Debug)] | 12 | #[derive(Debug)] |
@@ -22,7 +17,13 @@ pub(crate) struct RootDatabase { | |||
22 | events: (), | 17 | events: (), |
23 | 18 | ||
24 | runtime: salsa::Runtime<RootDatabase>, | 19 | runtime: salsa::Runtime<RootDatabase>, |
25 | id_maps: IdMaps, | 20 | id_maps: Arc<IdMaps>, |
21 | } | ||
22 | |||
23 | #[derive(Debug, Default)] | ||
24 | struct IdMaps { | ||
25 | fns: LocationIntener<SourceItemId, FnId>, | ||
26 | defs: LocationIntener<DefLoc, DefId>, | ||
26 | } | 27 | } |
27 | 28 | ||
28 | impl salsa::Database for RootDatabase { | 29 | impl salsa::Database for RootDatabase { |
@@ -47,26 +48,18 @@ impl Default for RootDatabase { | |||
47 | let mut db = RootDatabase { | 48 | let mut db = RootDatabase { |
48 | events: Default::default(), | 49 | events: Default::default(), |
49 | runtime: salsa::Runtime::default(), | 50 | runtime: salsa::Runtime::default(), |
50 | id_maps: IdMaps::default(), | 51 | id_maps: Default::default(), |
51 | }; | 52 | }; |
52 | db.query_mut(crate::input::SourceRootQuery) | 53 | db.query_mut(ra_db::SourceRootQuery) |
53 | .set(crate::input::WORKSPACE, Default::default()); | 54 | .set(ra_db::WORKSPACE, Default::default()); |
54 | db.query_mut(crate::input::CrateGraphQuery) | 55 | db.query_mut(ra_db::CrateGraphQuery) |
55 | .set((), Default::default()); | 56 | .set((), Default::default()); |
56 | db.query_mut(crate::input::LibrariesQuery) | 57 | db.query_mut(ra_db::LibrariesQuery) |
57 | .set((), Default::default()); | 58 | .set((), Default::default()); |
58 | db | 59 | db |
59 | } | 60 | } |
60 | } | 61 | } |
61 | 62 | ||
62 | pub(crate) fn check_canceled(db: &impl salsa::Database) -> Cancelable<()> { | ||
63 | if db.salsa_runtime().is_current_revision_canceled() { | ||
64 | Err(Canceled) | ||
65 | } else { | ||
66 | Ok(()) | ||
67 | } | ||
68 | } | ||
69 | |||
70 | impl salsa::ParallelDatabase for RootDatabase { | 63 | impl salsa::ParallelDatabase for RootDatabase { |
71 | fn snapshot(&self) -> salsa::Snapshot<RootDatabase> { | 64 | fn snapshot(&self) -> salsa::Snapshot<RootDatabase> { |
72 | salsa::Snapshot::new(RootDatabase { | 65 | salsa::Snapshot::new(RootDatabase { |
@@ -77,9 +70,17 @@ impl salsa::ParallelDatabase for RootDatabase { | |||
77 | } | 70 | } |
78 | } | 71 | } |
79 | 72 | ||
80 | impl IdDatabase for RootDatabase { | 73 | impl BaseDatabase for RootDatabase {} |
81 | fn id_maps(&self) -> &IdMaps { | 74 | |
82 | &self.id_maps | 75 | impl AsRef<LocationIntener<DefLoc, DefId>> for RootDatabase { |
76 | fn as_ref(&self) -> &LocationIntener<DefLoc, DefId> { | ||
77 | &self.id_maps.defs | ||
78 | } | ||
79 | } | ||
80 | |||
81 | impl AsRef<LocationIntener<hir::SourceItemId, FnId>> for RootDatabase { | ||
82 | fn as_ref(&self) -> &LocationIntener<hir::SourceItemId, FnId> { | ||
83 | &self.id_maps.fns | ||
83 | } | 84 | } |
84 | } | 85 | } |
85 | 86 | ||
@@ -108,63 +109,30 @@ impl RootDatabase { | |||
108 | 109 | ||
109 | salsa::database_storage! { | 110 | salsa::database_storage! { |
110 | pub(crate) struct RootDatabaseStorage for RootDatabase { | 111 | pub(crate) struct RootDatabaseStorage for RootDatabase { |
111 | impl crate::input::FilesDatabase { | 112 | impl ra_db::FilesDatabase { |
112 | fn file_text() for crate::input::FileTextQuery; | 113 | fn file_text() for ra_db::FileTextQuery; |
113 | fn file_source_root() for crate::input::FileSourceRootQuery; | 114 | fn file_source_root() for ra_db::FileSourceRootQuery; |
114 | fn source_root() for crate::input::SourceRootQuery; | 115 | fn source_root() for ra_db::SourceRootQuery; |
115 | fn libraries() for crate::input::LibrariesQuery; | 116 | fn libraries() for ra_db::LibrariesQuery; |
116 | fn library_symbols() for crate::input::LibrarySymbolsQuery; | 117 | fn crate_graph() for ra_db::CrateGraphQuery; |
117 | fn crate_graph() for crate::input::CrateGraphQuery; | ||
118 | } | 118 | } |
119 | impl SyntaxDatabase { | 119 | impl ra_db::SyntaxDatabase { |
120 | fn file_syntax() for FileSyntaxQuery; | 120 | fn source_file() for ra_db::SourceFileQuery; |
121 | fn file_lines() for FileLinesQuery; | 121 | fn file_lines() for ra_db::FileLinesQuery; |
122 | fn file_symbols() for FileSymbolsQuery; | ||
123 | fn resolve_syntax_ptr() for ResolveSyntaxPtrQuery; | ||
124 | } | 122 | } |
125 | impl descriptors::DescriptorDatabase { | 123 | impl symbol_index::SymbolsDatabase { |
126 | fn module_tree() for descriptors::ModuleTreeQuery; | 124 | fn file_symbols() for symbol_index::FileSymbolsQuery; |
127 | fn fn_scopes() for descriptors::FnScopesQuery; | 125 | fn library_symbols() for symbol_index::LibrarySymbolsQuery; |
128 | fn _file_items() for descriptors::FileItemsQuery; | ||
129 | fn _file_item() for descriptors::FileItemQuery; | ||
130 | fn _input_module_items() for descriptors::InputModuleItemsQuery; | ||
131 | fn _item_map() for descriptors::ItemMapQuery; | ||
132 | fn _fn_syntax() for descriptors::FnSyntaxQuery; | ||
133 | fn _submodules() for descriptors::SubmodulesQuery; | ||
134 | } | 126 | } |
135 | } | 127 | impl hir::db::HirDatabase { |
136 | } | 128 | fn module_tree() for hir::db::ModuleTreeQuery; |
137 | 129 | fn fn_scopes() for hir::db::FnScopesQuery; | |
138 | salsa::query_group! { | 130 | fn file_items() for hir::db::SourceFileItemsQuery; |
139 | pub(crate) trait SyntaxDatabase: crate::input::FilesDatabase { | 131 | fn file_item() for hir::db::FileItemQuery; |
140 | fn file_syntax(file_id: FileId) -> SourceFileNode { | 132 | fn input_module_items() for hir::db::InputModuleItemsQuery; |
141 | type FileSyntaxQuery; | 133 | fn item_map() for hir::db::ItemMapQuery; |
142 | } | 134 | fn fn_syntax() for hir::db::FnSyntaxQuery; |
143 | fn file_lines(file_id: FileId) -> Arc<LineIndex> { | 135 | fn submodules() for hir::db::SubmodulesQuery; |
144 | type FileLinesQuery; | ||
145 | } | ||
146 | fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { | ||
147 | type FileSymbolsQuery; | ||
148 | } | ||
149 | fn resolve_syntax_ptr(ptr: SyntaxPtr) -> SyntaxNode { | ||
150 | type ResolveSyntaxPtrQuery; | ||
151 | // Don't retain syntax trees in memory | ||
152 | storage dependencies; | ||
153 | use fn crate::syntax_ptr::resolve_syntax_ptr; | ||
154 | } | 136 | } |
155 | } | 137 | } |
156 | } | 138 | } |
157 | |||
158 | fn file_syntax(db: &impl SyntaxDatabase, file_id: FileId) -> SourceFileNode { | ||
159 | let text = db.file_text(file_id); | ||
160 | SourceFileNode::parse(&*text) | ||
161 | } | ||
162 | fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> { | ||
163 | let text = db.file_text(file_id); | ||
164 | Arc::new(LineIndex::new(&*text)) | ||
165 | } | ||
166 | fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { | ||
167 | db::check_canceled(db)?; | ||
168 | let syntax = db.file_syntax(file_id); | ||
169 | Ok(Arc::new(SymbolIndex::for_file(file_id, syntax))) | ||
170 | } | ||
diff --git a/crates/ra_analysis/src/descriptors/function/imp.rs b/crates/ra_analysis/src/descriptors/function/imp.rs deleted file mode 100644 index e09deba0f..000000000 --- a/crates/ra_analysis/src/descriptors/function/imp.rs +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_syntax::ast::{AstNode, FnDef, FnDefNode}; | ||
4 | |||
5 | use crate::descriptors::{ | ||
6 | function::{FnId, FnScopes}, | ||
7 | DescriptorDatabase, | ||
8 | }; | ||
9 | |||
10 | /// Resolve `FnId` to the corresponding `SyntaxNode` | ||
11 | pub(crate) fn fn_syntax(db: &impl DescriptorDatabase, fn_id: FnId) -> FnDefNode { | ||
12 | let ptr = db.id_maps().fn_ptr(fn_id); | ||
13 | let syntax = db.resolve_syntax_ptr(ptr); | ||
14 | FnDef::cast(syntax.borrowed()).unwrap().owned() | ||
15 | } | ||
16 | |||
17 | pub(crate) fn fn_scopes(db: &impl DescriptorDatabase, fn_id: FnId) -> Arc<FnScopes> { | ||
18 | let syntax = db._fn_syntax(fn_id); | ||
19 | let res = FnScopes::new(syntax.borrowed()); | ||
20 | Arc::new(res) | ||
21 | } | ||
diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs deleted file mode 100644 index 7a1bcf447..000000000 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ /dev/null | |||
@@ -1,137 +0,0 @@ | |||
1 | pub(crate) mod function; | ||
2 | pub(crate) mod module; | ||
3 | mod path; | ||
4 | |||
5 | use std::sync::Arc; | ||
6 | |||
7 | use ra_syntax::{ | ||
8 | ast::{self, FnDefNode, AstNode}, | ||
9 | TextRange, SyntaxNode, | ||
10 | }; | ||
11 | |||
12 | use crate::{ | ||
13 | FileId, | ||
14 | db::SyntaxDatabase, | ||
15 | descriptors::function::{resolve_local_name, FnId, FnScopes}, | ||
16 | descriptors::module::{ | ||
17 | ModuleId, ModuleTree, ModuleSource, ModuleDescriptor, | ||
18 | nameres::{ItemMap, InputModuleItems, FileItems} | ||
19 | }, | ||
20 | input::SourceRootId, | ||
21 | loc2id::{IdDatabase, DefId, DefLoc}, | ||
22 | syntax_ptr::LocalSyntaxPtr, | ||
23 | Cancelable, | ||
24 | }; | ||
25 | |||
26 | pub(crate) use self::path::{Path, PathKind}; | ||
27 | pub(crate) use self::module::nameres::FileItemId; | ||
28 | |||
29 | salsa::query_group! { | ||
30 | pub(crate) trait DescriptorDatabase: SyntaxDatabase + IdDatabase { | ||
31 | fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { | ||
32 | type FnScopesQuery; | ||
33 | use fn function::imp::fn_scopes; | ||
34 | } | ||
35 | |||
36 | fn _file_items(file_id: FileId) -> Arc<FileItems> { | ||
37 | type FileItemsQuery; | ||
38 | storage dependencies; | ||
39 | use fn module::nameres::file_items; | ||
40 | } | ||
41 | |||
42 | fn _file_item(file_id: FileId, file_item_id: FileItemId) -> SyntaxNode { | ||
43 | type FileItemQuery; | ||
44 | storage dependencies; | ||
45 | use fn module::nameres::file_item; | ||
46 | } | ||
47 | |||
48 | fn _input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<InputModuleItems>> { | ||
49 | type InputModuleItemsQuery; | ||
50 | use fn module::nameres::input_module_items; | ||
51 | } | ||
52 | fn _item_map(source_root_id: SourceRootId) -> Cancelable<Arc<ItemMap>> { | ||
53 | type ItemMapQuery; | ||
54 | use fn module::nameres::item_map; | ||
55 | } | ||
56 | fn _module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { | ||
57 | type ModuleTreeQuery; | ||
58 | use fn module::imp::module_tree; | ||
59 | } | ||
60 | fn _fn_syntax(fn_id: FnId) -> FnDefNode { | ||
61 | type FnSyntaxQuery; | ||
62 | // Don't retain syntax trees in memory | ||
63 | storage dependencies; | ||
64 | use fn function::imp::fn_syntax; | ||
65 | } | ||
66 | fn _submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> { | ||
67 | type SubmodulesQuery; | ||
68 | use fn module::imp::submodules; | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | pub(crate) enum Def { | ||
74 | Module(ModuleDescriptor), | ||
75 | Item, | ||
76 | } | ||
77 | |||
78 | impl DefId { | ||
79 | pub(crate) fn resolve(self, db: &impl DescriptorDatabase) -> Cancelable<Def> { | ||
80 | let loc = db.id_maps().def_loc(self); | ||
81 | let res = match loc { | ||
82 | DefLoc::Module { id, source_root } => { | ||
83 | let descr = ModuleDescriptor::new(db, source_root, id)?; | ||
84 | Def::Module(descr) | ||
85 | } | ||
86 | DefLoc::Item { .. } => Def::Item, | ||
87 | }; | ||
88 | Ok(res) | ||
89 | } | ||
90 | } | ||
91 | |||
92 | #[derive(Debug)] | ||
93 | pub struct ReferenceDescriptor { | ||
94 | pub range: TextRange, | ||
95 | pub name: String, | ||
96 | } | ||
97 | |||
98 | #[derive(Debug)] | ||
99 | pub struct DeclarationDescriptor<'a> { | ||
100 | pat: ast::BindPat<'a>, | ||
101 | pub range: TextRange, | ||
102 | } | ||
103 | |||
104 | impl<'a> DeclarationDescriptor<'a> { | ||
105 | pub fn new(pat: ast::BindPat) -> DeclarationDescriptor { | ||
106 | let range = pat.syntax().range(); | ||
107 | |||
108 | DeclarationDescriptor { pat, range } | ||
109 | } | ||
110 | |||
111 | pub fn find_all_refs(&self) -> Vec<ReferenceDescriptor> { | ||
112 | let name_ptr = LocalSyntaxPtr::new(self.pat.syntax()); | ||
113 | |||
114 | let fn_def = match self.pat.syntax().ancestors().find_map(ast::FnDef::cast) { | ||
115 | Some(def) => def, | ||
116 | None => return Default::default(), | ||
117 | }; | ||
118 | |||
119 | let fn_scopes = FnScopes::new(fn_def); | ||
120 | |||
121 | let refs: Vec<_> = fn_def | ||
122 | .syntax() | ||
123 | .descendants() | ||
124 | .filter_map(ast::NameRef::cast) | ||
125 | .filter(|name_ref| match resolve_local_name(*name_ref, &fn_scopes) { | ||
126 | None => false, | ||
127 | Some(entry) => entry.ptr() == name_ptr, | ||
128 | }) | ||
129 | .map(|name_ref| ReferenceDescriptor { | ||
130 | name: name_ref.syntax().text().to_string(), | ||
131 | range: name_ref.syntax().range(), | ||
132 | }) | ||
133 | .collect(); | ||
134 | |||
135 | refs | ||
136 | } | ||
137 | } | ||
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 8a41b3152..f5cb3550e 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -1,94 +1,33 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | fmt, | 2 | fmt, |
3 | hash::{Hash, Hasher}, | ||
4 | sync::Arc, | 3 | sync::Arc, |
5 | }; | 4 | }; |
6 | 5 | ||
7 | use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit}; | 6 | use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit}; |
8 | use ra_syntax::{ | 7 | use ra_syntax::{ |
9 | ast::{self, ArgListOwner, Expr, NameOwner}, | 8 | ast::{self, ArgListOwner, Expr, NameOwner}, |
10 | AstNode, SourceFileNode, SmolStr, | 9 | AstNode, SourceFileNode, |
11 | SyntaxKind::*, | 10 | SyntaxKind::*, |
12 | SyntaxNodeRef, TextRange, TextUnit, | 11 | SyntaxNodeRef, TextRange, TextUnit, |
13 | }; | 12 | }; |
13 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE, SyntaxDatabase, SourceFileQuery}; | ||
14 | use rayon::prelude::*; | 14 | use rayon::prelude::*; |
15 | use relative_path::RelativePath; | ||
16 | use rustc_hash::FxHashSet; | 15 | use rustc_hash::FxHashSet; |
17 | use salsa::{Database, ParallelDatabase}; | 16 | use salsa::{Database, ParallelDatabase}; |
17 | use hir::{ | ||
18 | self, | ||
19 | FnSignatureInfo, | ||
20 | Problem, | ||
21 | }; | ||
18 | 22 | ||
19 | use crate::{ | 23 | use crate::{ |
20 | completion::{completions, CompletionItem}, | 24 | completion::{completions, CompletionItem}, |
21 | db::{self, FileSyntaxQuery, SyntaxDatabase}, | 25 | db, |
22 | descriptors::{ | 26 | symbol_index::{SymbolIndex, SymbolsDatabase}, |
23 | function::{FnDescriptor, FnId}, | 27 | AnalysisChange, Cancelable, CrateId, Diagnostic, FileId, |
24 | module::{ModuleDescriptor, Problem}, | ||
25 | DeclarationDescriptor, DescriptorDatabase, | ||
26 | }, | ||
27 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, | ||
28 | symbol_index::SymbolIndex, | ||
29 | AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver, | ||
30 | FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, | 28 | FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, |
31 | }; | 29 | }; |
32 | 30 | ||
33 | #[derive(Clone, Debug)] | ||
34 | pub(crate) struct FileResolverImp { | ||
35 | inner: Arc<FileResolver>, | ||
36 | } | ||
37 | |||
38 | impl PartialEq for FileResolverImp { | ||
39 | fn eq(&self, other: &FileResolverImp) -> bool { | ||
40 | self.inner() == other.inner() | ||
41 | } | ||
42 | } | ||
43 | |||
44 | impl Eq for FileResolverImp {} | ||
45 | |||
46 | impl Hash for FileResolverImp { | ||
47 | fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
48 | self.inner().hash(hasher); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | impl FileResolverImp { | ||
53 | pub(crate) fn new(inner: Arc<FileResolver>) -> FileResolverImp { | ||
54 | FileResolverImp { inner } | ||
55 | } | ||
56 | pub(crate) fn file_stem(&self, file_id: FileId) -> String { | ||
57 | self.inner.file_stem(file_id) | ||
58 | } | ||
59 | pub(crate) fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> { | ||
60 | self.inner.resolve(file_id, path) | ||
61 | } | ||
62 | pub(crate) fn debug_path(&self, file_id: FileId) -> Option<std::path::PathBuf> { | ||
63 | self.inner.debug_path(file_id) | ||
64 | } | ||
65 | fn inner(&self) -> *const FileResolver { | ||
66 | &*self.inner | ||
67 | } | ||
68 | } | ||
69 | |||
70 | impl Default for FileResolverImp { | ||
71 | fn default() -> FileResolverImp { | ||
72 | #[derive(Debug)] | ||
73 | struct DummyResolver; | ||
74 | impl FileResolver for DummyResolver { | ||
75 | fn file_stem(&self, _file_: FileId) -> String { | ||
76 | panic!("file resolver not set") | ||
77 | } | ||
78 | fn resolve( | ||
79 | &self, | ||
80 | _file_id: FileId, | ||
81 | _path: &::relative_path::RelativePath, | ||
82 | ) -> Option<FileId> { | ||
83 | panic!("file resolver not set") | ||
84 | } | ||
85 | } | ||
86 | FileResolverImp { | ||
87 | inner: Arc::new(DummyResolver), | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | #[derive(Debug, Default)] | 31 | #[derive(Debug, Default)] |
93 | pub(crate) struct AnalysisHostImpl { | 32 | pub(crate) struct AnalysisHostImpl { |
94 | db: db::RootDatabase, | 33 | db: db::RootDatabase, |
@@ -105,7 +44,7 @@ impl AnalysisHostImpl { | |||
105 | 44 | ||
106 | for (file_id, text) in change.files_changed { | 45 | for (file_id, text) in change.files_changed { |
107 | self.db | 46 | self.db |
108 | .query_mut(crate::input::FileTextQuery) | 47 | .query_mut(ra_db::FileTextQuery) |
109 | .set(file_id, Arc::new(text)) | 48 | .set(file_id, Arc::new(text)) |
110 | } | 49 | } |
111 | if !(change.files_added.is_empty() && change.files_removed.is_empty()) { | 50 | if !(change.files_added.is_empty() && change.files_removed.is_empty()) { |
@@ -115,22 +54,22 @@ impl AnalysisHostImpl { | |||
115 | let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE)); | 54 | let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE)); |
116 | for (file_id, text) in change.files_added { | 55 | for (file_id, text) in change.files_added { |
117 | self.db | 56 | self.db |
118 | .query_mut(crate::input::FileTextQuery) | 57 | .query_mut(ra_db::FileTextQuery) |
119 | .set(file_id, Arc::new(text)); | 58 | .set(file_id, Arc::new(text)); |
120 | self.db | 59 | self.db |
121 | .query_mut(crate::input::FileSourceRootQuery) | 60 | .query_mut(ra_db::FileSourceRootQuery) |
122 | .set(file_id, crate::input::WORKSPACE); | 61 | .set(file_id, ra_db::WORKSPACE); |
123 | source_root.files.insert(file_id); | 62 | source_root.files.insert(file_id); |
124 | } | 63 | } |
125 | for file_id in change.files_removed { | 64 | for file_id in change.files_removed { |
126 | self.db | 65 | self.db |
127 | .query_mut(crate::input::FileTextQuery) | 66 | .query_mut(ra_db::FileTextQuery) |
128 | .set(file_id, Arc::new(String::new())); | 67 | .set(file_id, Arc::new(String::new())); |
129 | source_root.files.remove(&file_id); | 68 | source_root.files.remove(&file_id); |
130 | } | 69 | } |
131 | source_root.file_resolver = file_resolver; | 70 | source_root.file_resolver = file_resolver; |
132 | self.db | 71 | self.db |
133 | .query_mut(crate::input::SourceRootQuery) | 72 | .query_mut(ra_db::SourceRootQuery) |
134 | .set(WORKSPACE, Arc::new(source_root)) | 73 | .set(WORKSPACE, Arc::new(source_root)) |
135 | } | 74 | } |
136 | if !change.libraries_added.is_empty() { | 75 | if !change.libraries_added.is_empty() { |
@@ -147,10 +86,10 @@ impl AnalysisHostImpl { | |||
147 | library.file_resolver.debug_path(file_id) | 86 | library.file_resolver.debug_path(file_id) |
148 | ); | 87 | ); |
149 | self.db | 88 | self.db |
150 | .query_mut(crate::input::FileSourceRootQuery) | 89 | .query_mut(ra_db::FileSourceRootQuery) |
151 | .set_constant(file_id, source_root_id); | 90 | .set_constant(file_id, source_root_id); |
152 | self.db | 91 | self.db |
153 | .query_mut(crate::input::FileTextQuery) | 92 | .query_mut(ra_db::FileTextQuery) |
154 | .set_constant(file_id, Arc::new(text)); | 93 | .set_constant(file_id, Arc::new(text)); |
155 | } | 94 | } |
156 | let source_root = SourceRoot { | 95 | let source_root = SourceRoot { |
@@ -158,19 +97,19 @@ impl AnalysisHostImpl { | |||
158 | file_resolver: library.file_resolver, | 97 | file_resolver: library.file_resolver, |
159 | }; | 98 | }; |
160 | self.db | 99 | self.db |
161 | .query_mut(crate::input::SourceRootQuery) | 100 | .query_mut(ra_db::SourceRootQuery) |
162 | .set(source_root_id, Arc::new(source_root)); | 101 | .set(source_root_id, Arc::new(source_root)); |
163 | self.db | 102 | self.db |
164 | .query_mut(crate::input::LibrarySymbolsQuery) | 103 | .query_mut(crate::symbol_index::LibrarySymbolsQuery) |
165 | .set(source_root_id, Arc::new(library.symbol_index)); | 104 | .set(source_root_id, Arc::new(library.symbol_index)); |
166 | } | 105 | } |
167 | self.db | 106 | self.db |
168 | .query_mut(crate::input::LibrariesQuery) | 107 | .query_mut(ra_db::LibrariesQuery) |
169 | .set((), Arc::new(libraries)); | 108 | .set((), Arc::new(libraries)); |
170 | } | 109 | } |
171 | if let Some(crate_graph) = change.crate_graph { | 110 | if let Some(crate_graph) = change.crate_graph { |
172 | self.db | 111 | self.db |
173 | .query_mut(crate::input::CrateGraphQuery) | 112 | .query_mut(ra_db::CrateGraphQuery) |
174 | .set((), Arc::new(crate_graph)) | 113 | .set((), Arc::new(crate_graph)) |
175 | } | 114 | } |
176 | } | 115 | } |
@@ -189,7 +128,7 @@ impl fmt::Debug for AnalysisImpl { | |||
189 | 128 | ||
190 | impl AnalysisImpl { | 129 | impl AnalysisImpl { |
191 | pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { | 130 | pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { |
192 | self.db.file_syntax(file_id) | 131 | self.db.source_file(file_id) |
193 | } | 132 | } |
194 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { | 133 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { |
195 | self.db.file_lines(file_id) | 134 | self.db.file_lines(file_id) |
@@ -220,14 +159,14 @@ impl AnalysisImpl { | |||
220 | .collect() | 159 | .collect() |
221 | }; | 160 | }; |
222 | self.db | 161 | self.db |
223 | .query(FileSyntaxQuery) | 162 | .query(SourceFileQuery) |
224 | .sweep(salsa::SweepStrategy::default().discard_values()); | 163 | .sweep(salsa::SweepStrategy::default().discard_values()); |
225 | Ok(query.search(&buf)) | 164 | Ok(query.search(&buf)) |
226 | } | 165 | } |
227 | /// This return `Vec`: a module may be included from several places. We | 166 | /// This return `Vec`: a module may be included from several places. We |
228 | /// don't handle this case yet though, so the Vec has length at most one. | 167 | /// don't handle this case yet though, so the Vec has length at most one. |
229 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 168 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
230 | let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? { | 169 | let descr = match hir::Module::guess_from_position(&*self.db, position)? { |
231 | None => return Ok(Vec::new()), | 170 | None => return Ok(Vec::new()), |
232 | Some(it) => it, | 171 | Some(it) => it, |
233 | }; | 172 | }; |
@@ -246,7 +185,7 @@ impl AnalysisImpl { | |||
246 | } | 185 | } |
247 | /// Returns `Vec` for the same reason as `parent_module` | 186 | /// Returns `Vec` for the same reason as `parent_module` |
248 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 187 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
249 | let descr = match ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? { | 188 | let descr = match hir::Module::guess_from_file_id(&*self.db, file_id)? { |
250 | None => return Ok(Vec::new()), | 189 | None => return Ok(Vec::new()), |
251 | Some(it) => it, | 190 | Some(it) => it, |
252 | }; | 191 | }; |
@@ -261,7 +200,7 @@ impl AnalysisImpl { | |||
261 | Ok(crate_id.into_iter().collect()) | 200 | Ok(crate_id.into_iter().collect()) |
262 | } | 201 | } |
263 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | 202 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { |
264 | self.db.crate_graph().crate_roots[&crate_id] | 203 | self.db.crate_graph().crate_root(crate_id) |
265 | } | 204 | } |
266 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { | 205 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { |
267 | completions(&self.db, position) | 206 | completions(&self.db, position) |
@@ -270,33 +209,36 @@ impl AnalysisImpl { | |||
270 | &self, | 209 | &self, |
271 | position: FilePosition, | 210 | position: FilePosition, |
272 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 211 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
273 | let file = self.db.file_syntax(position.file_id); | 212 | let file = self.db.source_file(position.file_id); |
274 | let syntax = file.syntax(); | 213 | let syntax = file.syntax(); |
275 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { | 214 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { |
276 | // First try to resolve the symbol locally | 215 | if let Some(fn_descr) = |
277 | return if let Some((name, range)) = | 216 | hir::Function::guess_for_name_ref(&*self.db, position.file_id, name_ref) |
278 | resolve_local_name(&self.db, position.file_id, name_ref) | ||
279 | { | 217 | { |
280 | let mut vec = vec![]; | 218 | let scope = fn_descr.scope(&*self.db); |
281 | vec.push(( | 219 | // First try to resolve the symbol locally |
282 | position.file_id, | 220 | return if let Some(entry) = scope.resolve_local_name(name_ref) { |
283 | FileSymbol { | 221 | let mut vec = vec![]; |
284 | name, | 222 | vec.push(( |
285 | node_range: range, | 223 | position.file_id, |
286 | kind: NAME, | 224 | FileSymbol { |
287 | }, | 225 | name: entry.name().clone(), |
288 | )); | 226 | node_range: entry.ptr().range(), |
289 | Ok(vec) | 227 | kind: NAME, |
290 | } else { | 228 | }, |
291 | // If that fails try the index based approach. | 229 | )); |
292 | self.index_resolve(name_ref) | 230 | Ok(vec) |
293 | }; | 231 | } else { |
232 | // If that fails try the index based approach. | ||
233 | self.index_resolve(name_ref) | ||
234 | }; | ||
235 | } | ||
294 | } | 236 | } |
295 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { | 237 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { |
296 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 238 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
297 | if module.has_semi() { | 239 | if module.has_semi() { |
298 | let parent_module = | 240 | let parent_module = |
299 | ModuleDescriptor::guess_from_file_id(&*self.db, position.file_id)?; | 241 | hir::Module::guess_from_file_id(&*self.db, position.file_id)?; |
300 | let child_name = module.name(); | 242 | let child_name = module.name(); |
301 | match (parent_module, child_name) { | 243 | match (parent_module, child_name) { |
302 | (Some(parent_module), Some(child_name)) => { | 244 | (Some(parent_module), Some(child_name)) => { |
@@ -319,32 +261,42 @@ impl AnalysisImpl { | |||
319 | } | 261 | } |
320 | 262 | ||
321 | pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { | 263 | pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { |
322 | let file = self.db.file_syntax(position.file_id); | 264 | let file = self.db.source_file(position.file_id); |
323 | let syntax = file.syntax(); | ||
324 | |||
325 | // Find the binding associated with the offset | 265 | // Find the binding associated with the offset |
326 | let maybe_binding = | 266 | let (binding, descr) = match find_binding(&self.db, &file, position) { |
327 | find_node_at_offset::<ast::BindPat>(syntax, position.offset).or_else(|| { | ||
328 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; | ||
329 | let resolved = resolve_local_name(&self.db, position.file_id, name_ref)?; | ||
330 | find_node_at_offset::<ast::BindPat>(syntax, resolved.1.end()) | ||
331 | }); | ||
332 | |||
333 | let binding = match maybe_binding { | ||
334 | None => return Vec::new(), | 267 | None => return Vec::new(), |
335 | Some(it) => it, | 268 | Some(it) => it, |
336 | }; | 269 | }; |
337 | 270 | ||
338 | let decl = DeclarationDescriptor::new(binding); | 271 | let mut ret = vec![(position.file_id, binding.syntax().range())]; |
339 | |||
340 | let mut ret = vec![(position.file_id, decl.range)]; | ||
341 | ret.extend( | 272 | ret.extend( |
342 | decl.find_all_refs() | 273 | descr |
274 | .scope(&*self.db) | ||
275 | .find_all_refs(binding) | ||
343 | .into_iter() | 276 | .into_iter() |
344 | .map(|ref_desc| (position.file_id, ref_desc.range)), | 277 | .map(|ref_desc| (position.file_id, ref_desc.range)), |
345 | ); | 278 | ); |
346 | 279 | ||
347 | ret | 280 | return ret; |
281 | |||
282 | fn find_binding<'a>( | ||
283 | db: &db::RootDatabase, | ||
284 | source_file: &'a SourceFileNode, | ||
285 | position: FilePosition, | ||
286 | ) -> Option<(ast::BindPat<'a>, hir::Function)> { | ||
287 | let syntax = source_file.syntax(); | ||
288 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { | ||
289 | let descr = hir::Function::guess_for_bind_pat(db, position.file_id, binding)?; | ||
290 | return Some((binding, descr)); | ||
291 | }; | ||
292 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; | ||
293 | let descr = hir::Function::guess_for_name_ref(db, position.file_id, name_ref)?; | ||
294 | let scope = descr.scope(db); | ||
295 | let resolved = scope.resolve_local_name(name_ref)?; | ||
296 | let resolved = resolved.ptr().resolve(source_file); | ||
297 | let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?; | ||
298 | Some((binding, descr)) | ||
299 | } | ||
348 | } | 300 | } |
349 | 301 | ||
350 | pub fn doc_comment_for( | 302 | pub fn doc_comment_for( |
@@ -352,13 +304,13 @@ impl AnalysisImpl { | |||
352 | file_id: FileId, | 304 | file_id: FileId, |
353 | symbol: FileSymbol, | 305 | symbol: FileSymbol, |
354 | ) -> Cancelable<Option<String>> { | 306 | ) -> Cancelable<Option<String>> { |
355 | let file = self.db.file_syntax(file_id); | 307 | let file = self.db.source_file(file_id); |
356 | 308 | ||
357 | Ok(symbol.docs(&file)) | 309 | Ok(symbol.docs(&file)) |
358 | } | 310 | } |
359 | 311 | ||
360 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 312 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
361 | let syntax = self.db.file_syntax(file_id); | 313 | let syntax = self.db.source_file(file_id); |
362 | 314 | ||
363 | let mut res = ra_editor::diagnostics(&syntax) | 315 | let mut res = ra_editor::diagnostics(&syntax) |
364 | .into_iter() | 316 | .into_iter() |
@@ -368,7 +320,7 @@ impl AnalysisImpl { | |||
368 | fix: None, | 320 | fix: None, |
369 | }) | 321 | }) |
370 | .collect::<Vec<_>>(); | 322 | .collect::<Vec<_>>(); |
371 | if let Some(m) = ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? { | 323 | if let Some(m) = hir::Module::guess_from_file_id(&*self.db, file_id)? { |
372 | for (name_node, problem) in m.problems(&*self.db) { | 324 | for (name_node, problem) in m.problems(&*self.db) { |
373 | let diag = match problem { | 325 | let diag = match problem { |
374 | Problem::UnresolvedModule { candidate } => { | 326 | Problem::UnresolvedModule { candidate } => { |
@@ -445,8 +397,8 @@ impl AnalysisImpl { | |||
445 | pub fn resolve_callable( | 397 | pub fn resolve_callable( |
446 | &self, | 398 | &self, |
447 | position: FilePosition, | 399 | position: FilePosition, |
448 | ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { | 400 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { |
449 | let file = self.db.file_syntax(position.file_id); | 401 | let file = self.db.source_file(position.file_id); |
450 | let syntax = file.syntax(); | 402 | let syntax = file.syntax(); |
451 | 403 | ||
452 | // Find the calling expression and it's NameRef | 404 | // Find the calling expression and it's NameRef |
@@ -455,11 +407,12 @@ impl AnalysisImpl { | |||
455 | 407 | ||
456 | // Resolve the function's NameRef (NOTE: this isn't entirely accurate). | 408 | // Resolve the function's NameRef (NOTE: this isn't entirely accurate). |
457 | let file_symbols = self.index_resolve(name_ref)?; | 409 | let file_symbols = self.index_resolve(name_ref)?; |
458 | for (fn_fiel_id, fs) in file_symbols { | 410 | for (fn_file_id, fs) in file_symbols { |
459 | if fs.kind == FN_DEF { | 411 | if fs.kind == FN_DEF { |
460 | let fn_file = self.db.file_syntax(fn_fiel_id); | 412 | let fn_file = self.db.source_file(fn_file_id); |
461 | if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { | 413 | if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { |
462 | if let Some(descriptor) = FnDescriptor::new(fn_def) { | 414 | let descr = hir::Function::guess_from_source(&*self.db, fn_file_id, fn_def); |
415 | if let Some(descriptor) = descr.signature_info(&*self.db) { | ||
463 | // If we have a calling expression let's find which argument we are on | 416 | // If we have a calling expression let's find which argument we are on |
464 | let mut current_parameter = None; | 417 | let mut current_parameter = None; |
465 | 418 | ||
@@ -532,16 +485,6 @@ impl SourceChange { | |||
532 | } | 485 | } |
533 | } | 486 | } |
534 | 487 | ||
535 | impl CrateGraph { | ||
536 | fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { | ||
537 | let (&crate_id, _) = self | ||
538 | .crate_roots | ||
539 | .iter() | ||
540 | .find(|(_crate_id, &root_id)| root_id == file_id)?; | ||
541 | Some(crate_id) | ||
542 | } | ||
543 | } | ||
544 | |||
545 | enum FnCallNode<'a> { | 488 | enum FnCallNode<'a> { |
546 | CallExpr(ast::CallExpr<'a>), | 489 | CallExpr(ast::CallExpr<'a>), |
547 | MethodCallExpr(ast::MethodCallExpr<'a>), | 490 | MethodCallExpr(ast::MethodCallExpr<'a>), |
@@ -580,16 +523,3 @@ impl<'a> FnCallNode<'a> { | |||
580 | } | 523 | } |
581 | } | 524 | } |
582 | } | 525 | } |
583 | |||
584 | fn resolve_local_name( | ||
585 | db: &db::RootDatabase, | ||
586 | file_id: FileId, | ||
587 | name_ref: ast::NameRef, | ||
588 | ) -> Option<(SmolStr, TextRange)> { | ||
589 | let fn_def = name_ref.syntax().ancestors().find_map(ast::FnDef::cast)?; | ||
590 | let fn_id = FnId::get(db, file_id, fn_def); | ||
591 | let scopes = db.fn_scopes(fn_id); | ||
592 | let scope_entry = crate::descriptors::function::resolve_local_name(name_ref, &scopes)?; | ||
593 | let syntax = db.resolve_syntax_ptr(scope_entry.ptr().into_global(file_id)); | ||
594 | Some((scope_entry.name().clone(), syntax.range())) | ||
595 | } | ||
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 0fbfd8a40..350a6d627 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -18,49 +18,36 @@ macro_rules! ctry { | |||
18 | }; | 18 | }; |
19 | } | 19 | } |
20 | 20 | ||
21 | mod arena; | ||
22 | mod db; | 21 | mod db; |
23 | mod loc2id; | ||
24 | mod input; | ||
25 | mod imp; | 22 | mod imp; |
26 | mod completion; | 23 | mod completion; |
27 | mod descriptors; | ||
28 | mod symbol_index; | 24 | mod symbol_index; |
29 | mod syntax_ptr; | ||
30 | pub mod mock_analysis; | 25 | pub mod mock_analysis; |
31 | 26 | ||
32 | use std::{fmt, sync::Arc}; | 27 | use std::{fmt, sync::Arc}; |
33 | 28 | ||
34 | use ra_syntax::{AtomEdit, SourceFileNode, TextRange, TextUnit}; | 29 | use ra_syntax::{AtomEdit, SourceFileNode, TextRange, TextUnit}; |
30 | use ra_db::FileResolverImp; | ||
35 | use rayon::prelude::*; | 31 | use rayon::prelude::*; |
36 | use relative_path::RelativePathBuf; | 32 | use relative_path::RelativePathBuf; |
37 | 33 | ||
38 | use crate::{ | 34 | use crate::{ |
39 | imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}, | 35 | imp::{AnalysisHostImpl, AnalysisImpl}, |
40 | symbol_index::SymbolIndex, | 36 | symbol_index::SymbolIndex, |
41 | }; | 37 | }; |
42 | 38 | ||
43 | pub use crate::{ | 39 | pub use crate::{ |
44 | completion::CompletionItem, | 40 | completion::CompletionItem, |
45 | descriptors::function::FnDescriptor, | ||
46 | input::{CrateGraph, CrateId, FileId, FileResolver}, | ||
47 | }; | 41 | }; |
48 | pub use ra_editor::{ | 42 | pub use ra_editor::{ |
49 | FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode, | 43 | FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode, |
50 | }; | 44 | }; |
45 | pub use hir::FnSignatureInfo; | ||
51 | 46 | ||
52 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 47 | pub use ra_db::{ |
53 | pub struct Canceled; | 48 | Canceled, Cancelable, FilePosition, |
54 | 49 | CrateGraph, CrateId, FileId, FileResolver | |
55 | pub type Cancelable<T> = Result<T, Canceled>; | 50 | }; |
56 | |||
57 | impl std::fmt::Display for Canceled { | ||
58 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
59 | fmt.write_str("Canceled") | ||
60 | } | ||
61 | } | ||
62 | |||
63 | impl std::error::Error for Canceled {} | ||
64 | 51 | ||
65 | #[derive(Default)] | 52 | #[derive(Default)] |
66 | pub struct AnalysisChange { | 53 | pub struct AnalysisChange { |
@@ -130,12 +117,6 @@ impl AnalysisHost { | |||
130 | } | 117 | } |
131 | } | 118 | } |
132 | 119 | ||
133 | #[derive(Clone, Copy, Debug)] | ||
134 | pub struct FilePosition { | ||
135 | pub file_id: FileId, | ||
136 | pub offset: TextUnit, | ||
137 | } | ||
138 | |||
139 | #[derive(Debug)] | 120 | #[derive(Debug)] |
140 | pub struct SourceChange { | 121 | pub struct SourceChange { |
141 | pub label: String, | 122 | pub label: String, |
@@ -305,7 +286,7 @@ impl Analysis { | |||
305 | pub fn resolve_callable( | 286 | pub fn resolve_callable( |
306 | &self, | 287 | &self, |
307 | position: FilePosition, | 288 | position: FilePosition, |
308 | ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { | 289 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { |
309 | self.imp.resolve_callable(position) | 290 | self.imp.resolve_callable(position) |
310 | } | 291 | } |
311 | } | 292 | } |
@@ -336,3 +317,112 @@ fn analysis_is_send() { | |||
336 | fn is_send<T: Send>() {} | 317 | fn is_send<T: Send>() {} |
337 | is_send::<Analysis>(); | 318 | is_send::<Analysis>(); |
338 | } | 319 | } |
320 | |||
321 | //TODO: move to hir | ||
322 | #[cfg(test)] | ||
323 | mod hir_namres_tests { | ||
324 | use std::sync::Arc; | ||
325 | use ra_db::FilesDatabase; | ||
326 | use ra_syntax::SmolStr; | ||
327 | use hir::{self, db::HirDatabase}; | ||
328 | |||
329 | use crate::{ | ||
330 | AnalysisChange, | ||
331 | mock_analysis::{MockAnalysis, analysis_and_position}, | ||
332 | }; | ||
333 | |||
334 | fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) { | ||
335 | let (analysis, pos) = analysis_and_position(fixture); | ||
336 | let db = analysis.imp.db; | ||
337 | let source_root = db.file_source_root(pos.file_id); | ||
338 | let descr = hir::Module::guess_from_position(&*db, pos) | ||
339 | .unwrap() | ||
340 | .unwrap(); | ||
341 | let module_id = descr.module_id; | ||
342 | (db.item_map(source_root).unwrap(), module_id) | ||
343 | } | ||
344 | |||
345 | #[test] | ||
346 | fn test_item_map() { | ||
347 | let (item_map, module_id) = item_map( | ||
348 | " | ||
349 | //- /lib.rs | ||
350 | mod foo; | ||
351 | |||
352 | use crate::foo::bar::Baz; | ||
353 | <|> | ||
354 | |||
355 | //- /foo/mod.rs | ||
356 | pub mod bar; | ||
357 | |||
358 | //- /foo/bar.rs | ||
359 | pub struct Baz; | ||
360 | ", | ||
361 | ); | ||
362 | let name = SmolStr::from("Baz"); | ||
363 | let resolution = &item_map.per_module[&module_id].items[&name]; | ||
364 | assert!(resolution.def_id.is_some()); | ||
365 | } | ||
366 | |||
367 | #[test] | ||
368 | fn typing_inside_a_function_should_not_invalidate_item_map() { | ||
369 | let mock_analysis = MockAnalysis::with_files( | ||
370 | " | ||
371 | //- /lib.rs | ||
372 | mod foo; | ||
373 | |||
374 | use crate::foo::bar::Baz; | ||
375 | |||
376 | fn foo() -> i32 { | ||
377 | 1 + 1 | ||
378 | } | ||
379 | //- /foo/mod.rs | ||
380 | pub mod bar; | ||
381 | |||
382 | //- /foo/bar.rs | ||
383 | pub struct Baz; | ||
384 | ", | ||
385 | ); | ||
386 | |||
387 | let file_id = mock_analysis.id_of("/lib.rs"); | ||
388 | let mut host = mock_analysis.analysis_host(); | ||
389 | |||
390 | let source_root = host.analysis().imp.db.file_source_root(file_id); | ||
391 | |||
392 | { | ||
393 | let db = host.analysis().imp.db; | ||
394 | let events = db.log_executed(|| { | ||
395 | db.item_map(source_root).unwrap(); | ||
396 | }); | ||
397 | assert!(format!("{:?}", events).contains("item_map")) | ||
398 | } | ||
399 | |||
400 | let mut change = AnalysisChange::new(); | ||
401 | |||
402 | change.change_file( | ||
403 | file_id, | ||
404 | " | ||
405 | mod foo; | ||
406 | |||
407 | use crate::foo::bar::Baz; | ||
408 | |||
409 | fn foo() -> i32 { 92 } | ||
410 | " | ||
411 | .to_string(), | ||
412 | ); | ||
413 | |||
414 | host.apply_change(change); | ||
415 | |||
416 | { | ||
417 | let db = host.analysis().imp.db; | ||
418 | let events = db.log_executed(|| { | ||
419 | db.item_map(source_root).unwrap(); | ||
420 | }); | ||
421 | assert!( | ||
422 | !format!("{:?}", events).contains("_item_map"), | ||
423 | "{:#?}", | ||
424 | events | ||
425 | ) | ||
426 | } | ||
427 | } | ||
428 | } | ||
diff --git a/crates/ra_analysis/src/loc2id.rs b/crates/ra_analysis/src/loc2id.rs deleted file mode 100644 index c7c799a91..000000000 --- a/crates/ra_analysis/src/loc2id.rs +++ /dev/null | |||
@@ -1,141 +0,0 @@ | |||
1 | use parking_lot::Mutex; | ||
2 | |||
3 | use std::{ | ||
4 | hash::Hash, | ||
5 | sync::Arc, | ||
6 | }; | ||
7 | |||
8 | use rustc_hash::FxHashMap; | ||
9 | |||
10 | use crate::{ | ||
11 | FileId, | ||
12 | descriptors::FileItemId, | ||
13 | descriptors::module::ModuleId, | ||
14 | syntax_ptr::SyntaxPtr, | ||
15 | input::SourceRootId, | ||
16 | }; | ||
17 | |||
18 | /// There are two principle ways to refer to things: | ||
19 | /// - by their locatinon (module in foo/bar/baz.rs at line 42) | ||
20 | /// - by their numeric id (module `ModuleId(42)`) | ||
21 | /// | ||
22 | /// The first one is more powerful (you can actually find the thing in question | ||
23 | /// by id), but the second one is so much more compact. | ||
24 | /// | ||
25 | /// `Loc2IdMap` allows us to have a cake an eat it as well: by maintaining a | ||
26 | /// bidirectional mapping between positional and numeric ids, we can use compact | ||
27 | /// representation wich still allows us to get the actual item | ||
28 | #[derive(Debug)] | ||
29 | pub(crate) struct Loc2IdMap<L, ID> | ||
30 | where | ||
31 | ID: NumericId, | ||
32 | L: Clone + Eq + Hash, | ||
33 | { | ||
34 | loc2id: FxHashMap<L, ID>, | ||
35 | id2loc: FxHashMap<ID, L>, | ||
36 | } | ||
37 | |||
38 | impl<L, ID> Default for Loc2IdMap<L, ID> | ||
39 | where | ||
40 | ID: NumericId, | ||
41 | L: Clone + Eq + Hash, | ||
42 | { | ||
43 | fn default() -> Self { | ||
44 | Loc2IdMap { | ||
45 | loc2id: FxHashMap::default(), | ||
46 | id2loc: FxHashMap::default(), | ||
47 | } | ||
48 | } | ||
49 | } | ||
50 | |||
51 | impl<L, ID> Loc2IdMap<L, ID> | ||
52 | where | ||
53 | ID: NumericId, | ||
54 | L: Clone + Eq + Hash, | ||
55 | { | ||
56 | pub fn loc2id(&mut self, loc: &L) -> ID { | ||
57 | match self.loc2id.get(loc) { | ||
58 | Some(id) => return id.clone(), | ||
59 | None => (), | ||
60 | } | ||
61 | let id = self.loc2id.len(); | ||
62 | assert!(id < u32::max_value() as usize); | ||
63 | let id = ID::from_u32(id as u32); | ||
64 | self.loc2id.insert(loc.clone(), id.clone()); | ||
65 | self.id2loc.insert(id.clone(), loc.clone()); | ||
66 | id | ||
67 | } | ||
68 | |||
69 | pub fn id2loc(&self, id: ID) -> L { | ||
70 | self.id2loc[&id].clone() | ||
71 | } | ||
72 | } | ||
73 | |||
74 | pub(crate) trait NumericId: Clone + Eq + Hash { | ||
75 | fn from_u32(id: u32) -> Self; | ||
76 | fn to_u32(self) -> u32; | ||
77 | } | ||
78 | |||
79 | macro_rules! impl_numeric_id { | ||
80 | ($id:ident) => { | ||
81 | impl NumericId for $id { | ||
82 | fn from_u32(id: u32) -> Self { | ||
83 | $id(id) | ||
84 | } | ||
85 | fn to_u32(self) -> u32 { | ||
86 | self.0 | ||
87 | } | ||
88 | } | ||
89 | }; | ||
90 | } | ||
91 | |||
92 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
93 | pub(crate) struct FnId(u32); | ||
94 | impl_numeric_id!(FnId); | ||
95 | |||
96 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
97 | pub(crate) struct DefId(u32); | ||
98 | impl_numeric_id!(DefId); | ||
99 | |||
100 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
101 | pub(crate) enum DefLoc { | ||
102 | Module { | ||
103 | id: ModuleId, | ||
104 | source_root: SourceRootId, | ||
105 | }, | ||
106 | Item { | ||
107 | file_id: FileId, | ||
108 | id: FileItemId, | ||
109 | }, | ||
110 | } | ||
111 | |||
112 | pub(crate) trait IdDatabase: salsa::Database { | ||
113 | fn id_maps(&self) -> &IdMaps; | ||
114 | } | ||
115 | |||
116 | #[derive(Debug, Default, Clone)] | ||
117 | pub(crate) struct IdMaps { | ||
118 | inner: Arc<IdMapsInner>, | ||
119 | } | ||
120 | |||
121 | impl IdMaps { | ||
122 | pub(crate) fn fn_id(&self, ptr: SyntaxPtr) -> FnId { | ||
123 | self.inner.fns.lock().loc2id(&ptr) | ||
124 | } | ||
125 | pub(crate) fn fn_ptr(&self, fn_id: FnId) -> SyntaxPtr { | ||
126 | self.inner.fns.lock().id2loc(fn_id) | ||
127 | } | ||
128 | |||
129 | pub(crate) fn def_id(&self, loc: DefLoc) -> DefId { | ||
130 | self.inner.defs.lock().loc2id(&loc) | ||
131 | } | ||
132 | pub(crate) fn def_loc(&self, def_id: DefId) -> DefLoc { | ||
133 | self.inner.defs.lock().id2loc(def_id) | ||
134 | } | ||
135 | } | ||
136 | |||
137 | #[derive(Debug, Default)] | ||
138 | struct IdMapsInner { | ||
139 | fns: Mutex<Loc2IdMap<SyntaxPtr, FnId>>, | ||
140 | defs: Mutex<Loc2IdMap<DefLoc, DefId>>, | ||
141 | } | ||
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 3a0667ecd..b48a37229 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs | |||
@@ -4,14 +4,36 @@ use std::{ | |||
4 | }; | 4 | }; |
5 | 5 | ||
6 | use fst::{self, Streamer}; | 6 | use fst::{self, Streamer}; |
7 | use ra_editor::{file_symbols, FileSymbol}; | 7 | use ra_editor::{self, FileSymbol}; |
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | SourceFileNode, | 9 | SourceFileNode, |
10 | SyntaxKind::{self, *}, | 10 | SyntaxKind::{self, *}, |
11 | }; | 11 | }; |
12 | use ra_db::{SyntaxDatabase, SourceRootId}; | ||
12 | use rayon::prelude::*; | 13 | use rayon::prelude::*; |
13 | 14 | ||
14 | use crate::{FileId, Query}; | 15 | use crate::{ |
16 | Cancelable, | ||
17 | FileId, Query, | ||
18 | }; | ||
19 | |||
20 | salsa::query_group! { | ||
21 | pub(crate) trait SymbolsDatabase: SyntaxDatabase { | ||
22 | fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { | ||
23 | type FileSymbolsQuery; | ||
24 | } | ||
25 | fn library_symbols(id: SourceRootId) -> Arc<SymbolIndex> { | ||
26 | type LibrarySymbolsQuery; | ||
27 | storage input; | ||
28 | } | ||
29 | } | ||
30 | } | ||
31 | |||
32 | fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { | ||
33 | db.check_canceled()?; | ||
34 | let syntax = db.source_file(file_id); | ||
35 | Ok(Arc::new(SymbolIndex::for_file(file_id, syntax))) | ||
36 | } | ||
15 | 37 | ||
16 | #[derive(Default, Debug)] | 38 | #[derive(Default, Debug)] |
17 | pub(crate) struct SymbolIndex { | 39 | pub(crate) struct SymbolIndex { |
@@ -39,7 +61,7 @@ impl SymbolIndex { | |||
39 | ) -> SymbolIndex { | 61 | ) -> SymbolIndex { |
40 | let mut symbols = files | 62 | let mut symbols = files |
41 | .flat_map(|(file_id, file)| { | 63 | .flat_map(|(file_id, file)| { |
42 | file_symbols(&file) | 64 | ra_editor::file_symbols(&file) |
43 | .into_iter() | 65 | .into_iter() |
44 | .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol))) | 66 | .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol))) |
45 | .collect::<Vec<_>>() | 67 | .collect::<Vec<_>>() |
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index 72b2ebf97..fbe89f444 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs | |||
@@ -10,10 +10,10 @@ use test_utils::assert_eq_dbg; | |||
10 | 10 | ||
11 | use ra_analysis::{ | 11 | use ra_analysis::{ |
12 | mock_analysis::{analysis_and_position, single_file, single_file_with_position, MockAnalysis}, | 12 | mock_analysis::{analysis_and_position, single_file, single_file_with_position, MockAnalysis}, |
13 | AnalysisChange, CrateGraph, FileId, FnDescriptor, | 13 | AnalysisChange, CrateGraph, FileId, FnSignatureInfo, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) { | 16 | fn get_signature(text: &str) -> (FnSignatureInfo, Option<usize>) { |
17 | let (analysis, position) = single_file_with_position(text); | 17 | let (analysis, position) = single_file_with_position(text); |
18 | analysis.resolve_callable(position).unwrap().unwrap() | 18 | analysis.resolve_callable(position).unwrap().unwrap() |
19 | } | 19 | } |
@@ -126,7 +126,7 @@ fn test_resolve_crate_root() { | |||
126 | let mut host = mock.analysis_host(); | 126 | let mut host = mock.analysis_host(); |
127 | assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); | 127 | assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); |
128 | 128 | ||
129 | let mut crate_graph = CrateGraph::new(); | 129 | let mut crate_graph = CrateGraph::default(); |
130 | let crate_id = crate_graph.add_crate_root(root_file); | 130 | let crate_id = crate_graph.add_crate_root(root_file); |
131 | let mut change = AnalysisChange::new(); | 131 | let mut change = AnalysisChange::new(); |
132 | change.set_crate_graph(crate_graph); | 132 | change.set_crate_graph(crate_graph); |
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml new file mode 100644 index 000000000..3bf2f635e --- /dev/null +++ b/crates/ra_db/Cargo.toml | |||
@@ -0,0 +1,16 @@ | |||
1 | [package] | ||
2 | edition = "2018" | ||
3 | name = "ra_db" | ||
4 | version = "0.1.0" | ||
5 | authors = ["Aleksey Kladov <[email protected]>"] | ||
6 | |||
7 | [dependencies] | ||
8 | log = "0.4.5" | ||
9 | relative-path = "0.4.0" | ||
10 | salsa = "0.8.0" | ||
11 | rustc-hash = "1.0" | ||
12 | parking_lot = "0.6.4" | ||
13 | id-arena = { git = "https://github.com/fitzgen/id-arena/", rev = "43ecd67" } | ||
14 | ra_syntax = { path = "../ra_syntax" } | ||
15 | ra_editor = { path = "../ra_editor" } | ||
16 | test_utils = { path = "../test_utils" } | ||
diff --git a/crates/ra_db/src/file_resolver.rs b/crates/ra_db/src/file_resolver.rs new file mode 100644 index 000000000..f849ac752 --- /dev/null +++ b/crates/ra_db/src/file_resolver.rs | |||
@@ -0,0 +1,76 @@ | |||
1 | use std::{ | ||
2 | sync::Arc, | ||
3 | hash::{Hash, Hasher}, | ||
4 | fmt, | ||
5 | }; | ||
6 | |||
7 | use relative_path::RelativePath; | ||
8 | |||
9 | use crate::input::FileId; | ||
10 | |||
11 | pub trait FileResolver: fmt::Debug + Send + Sync + 'static { | ||
12 | fn file_stem(&self, file_id: FileId) -> String; | ||
13 | fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId>; | ||
14 | fn debug_path(&self, _1file_id: FileId) -> Option<std::path::PathBuf> { | ||
15 | None | ||
16 | } | ||
17 | } | ||
18 | |||
19 | #[derive(Clone, Debug)] | ||
20 | pub struct FileResolverImp { | ||
21 | inner: Arc<FileResolver>, | ||
22 | } | ||
23 | |||
24 | impl PartialEq for FileResolverImp { | ||
25 | fn eq(&self, other: &FileResolverImp) -> bool { | ||
26 | self.inner() == other.inner() | ||
27 | } | ||
28 | } | ||
29 | |||
30 | impl Eq for FileResolverImp {} | ||
31 | |||
32 | impl Hash for FileResolverImp { | ||
33 | fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
34 | self.inner().hash(hasher); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | impl FileResolverImp { | ||
39 | pub fn new(inner: Arc<FileResolver>) -> FileResolverImp { | ||
40 | FileResolverImp { inner } | ||
41 | } | ||
42 | pub fn file_stem(&self, file_id: FileId) -> String { | ||
43 | self.inner.file_stem(file_id) | ||
44 | } | ||
45 | pub fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> { | ||
46 | self.inner.resolve(file_id, path) | ||
47 | } | ||
48 | pub fn debug_path(&self, file_id: FileId) -> Option<std::path::PathBuf> { | ||
49 | self.inner.debug_path(file_id) | ||
50 | } | ||
51 | fn inner(&self) -> *const FileResolver { | ||
52 | &*self.inner | ||
53 | } | ||
54 | } | ||
55 | |||
56 | impl Default for FileResolverImp { | ||
57 | fn default() -> FileResolverImp { | ||
58 | #[derive(Debug)] | ||
59 | struct DummyResolver; | ||
60 | impl FileResolver for DummyResolver { | ||
61 | fn file_stem(&self, _file_: FileId) -> String { | ||
62 | panic!("file resolver not set") | ||
63 | } | ||
64 | fn resolve( | ||
65 | &self, | ||
66 | _file_id: FileId, | ||
67 | _path: &::relative_path::RelativePath, | ||
68 | ) -> Option<FileId> { | ||
69 | panic!("file resolver not set") | ||
70 | } | ||
71 | } | ||
72 | FileResolverImp { | ||
73 | inner: Arc::new(DummyResolver), | ||
74 | } | ||
75 | } | ||
76 | } | ||
diff --git a/crates/ra_analysis/src/input.rs b/crates/ra_db/src/input.rs index a78b6e397..9101ac7a8 100644 --- a/crates/ra_analysis/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -1,11 +1,10 @@ | |||
1 | use std::{fmt, sync::Arc}; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use relative_path::RelativePath; | ||
4 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
5 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
6 | use salsa; | 5 | use salsa; |
7 | 6 | ||
8 | use crate::{symbol_index::SymbolIndex, FileResolverImp}; | 7 | use crate::file_resolver::FileResolverImp; |
9 | 8 | ||
10 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 9 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
11 | pub struct FileId(pub u32); | 10 | pub struct FileId(pub u32); |
@@ -19,8 +18,8 @@ pub struct CrateGraph { | |||
19 | } | 18 | } |
20 | 19 | ||
21 | impl CrateGraph { | 20 | impl CrateGraph { |
22 | pub fn new() -> CrateGraph { | 21 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { |
23 | CrateGraph::default() | 22 | self.crate_roots[&crate_id] |
24 | } | 23 | } |
25 | pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { | 24 | pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { |
26 | let crate_id = CrateId(self.crate_roots.len() as u32); | 25 | let crate_id = CrateId(self.crate_roots.len() as u32); |
@@ -28,18 +27,17 @@ impl CrateGraph { | |||
28 | assert!(prev.is_none()); | 27 | assert!(prev.is_none()); |
29 | crate_id | 28 | crate_id |
30 | } | 29 | } |
31 | } | 30 | pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { |
32 | 31 | let (&crate_id, _) = self | |
33 | pub trait FileResolver: fmt::Debug + Send + Sync + 'static { | 32 | .crate_roots |
34 | fn file_stem(&self, file_id: FileId) -> String; | 33 | .iter() |
35 | fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId>; | 34 | .find(|(_crate_id, &root_id)| root_id == file_id)?; |
36 | fn debug_path(&self, _file_id: FileId) -> Option<std::path::PathBuf> { | 35 | Some(crate_id) |
37 | None | ||
38 | } | 36 | } |
39 | } | 37 | } |
40 | 38 | ||
41 | salsa::query_group! { | 39 | salsa::query_group! { |
42 | pub(crate) trait FilesDatabase: salsa::Database { | 40 | pub trait FilesDatabase: salsa::Database { |
43 | fn file_text(file_id: FileId) -> Arc<String> { | 41 | fn file_text(file_id: FileId) -> Arc<String> { |
44 | type FileTextQuery; | 42 | type FileTextQuery; |
45 | storage input; | 43 | storage input; |
@@ -56,10 +54,6 @@ salsa::query_group! { | |||
56 | type LibrariesQuery; | 54 | type LibrariesQuery; |
57 | storage input; | 55 | storage input; |
58 | } | 56 | } |
59 | fn library_symbols(id: SourceRootId) -> Arc<SymbolIndex> { | ||
60 | type LibrarySymbolsQuery; | ||
61 | storage input; | ||
62 | } | ||
63 | fn crate_graph() -> Arc<CrateGraph> { | 57 | fn crate_graph() -> Arc<CrateGraph> { |
64 | type CrateGraphQuery; | 58 | type CrateGraphQuery; |
65 | storage input; | 59 | storage input; |
@@ -68,12 +62,12 @@ salsa::query_group! { | |||
68 | } | 62 | } |
69 | 63 | ||
70 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] | 64 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] |
71 | pub(crate) struct SourceRootId(pub(crate) u32); | 65 | pub struct SourceRootId(pub u32); |
72 | 66 | ||
73 | #[derive(Default, Clone, Debug, PartialEq, Eq)] | 67 | #[derive(Default, Clone, Debug, PartialEq, Eq)] |
74 | pub(crate) struct SourceRoot { | 68 | pub struct SourceRoot { |
75 | pub(crate) file_resolver: FileResolverImp, | 69 | pub file_resolver: FileResolverImp, |
76 | pub(crate) files: FxHashSet<FileId>, | 70 | pub files: FxHashSet<FileId>, |
77 | } | 71 | } |
78 | 72 | ||
79 | pub(crate) const WORKSPACE: SourceRootId = SourceRootId(0); | 73 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs new file mode 100644 index 000000000..33cb0e2ec --- /dev/null +++ b/crates/ra_db/src/lib.rs | |||
@@ -0,0 +1,89 @@ | |||
1 | //! ra_db defines basic database traits. Concrete DB is defined by ra_analysis. | ||
2 | |||
3 | extern crate ra_editor; | ||
4 | extern crate ra_syntax; | ||
5 | extern crate relative_path; | ||
6 | extern crate rustc_hash; | ||
7 | extern crate salsa; | ||
8 | |||
9 | mod syntax_ptr; | ||
10 | mod file_resolver; | ||
11 | mod input; | ||
12 | mod loc2id; | ||
13 | |||
14 | use std::sync::Arc; | ||
15 | use ra_editor::LineIndex; | ||
16 | use ra_syntax::{TextUnit, SourceFileNode}; | ||
17 | |||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
19 | pub struct Canceled; | ||
20 | |||
21 | pub type Cancelable<T> = Result<T, Canceled>; | ||
22 | |||
23 | impl std::fmt::Display for Canceled { | ||
24 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
25 | fmt.write_str("Canceled") | ||
26 | } | ||
27 | } | ||
28 | |||
29 | impl std::error::Error for Canceled {} | ||
30 | |||
31 | pub use crate::{ | ||
32 | syntax_ptr::LocalSyntaxPtr, | ||
33 | file_resolver::{FileResolver, FileResolverImp}, | ||
34 | input::{ | ||
35 | FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, WORKSPACE, | ||
36 | FileTextQuery, FileSourceRootQuery, SourceRootQuery, LibrariesQuery, CrateGraphQuery, | ||
37 | }, | ||
38 | loc2id::{LocationIntener, NumericId}, | ||
39 | }; | ||
40 | |||
41 | #[macro_export] | ||
42 | macro_rules! impl_numeric_id { | ||
43 | ($id:ident) => { | ||
44 | impl $crate::NumericId for $id { | ||
45 | fn from_u32(id: u32) -> Self { | ||
46 | $id(id) | ||
47 | } | ||
48 | fn to_u32(self) -> u32 { | ||
49 | self.0 | ||
50 | } | ||
51 | } | ||
52 | }; | ||
53 | } | ||
54 | |||
55 | pub trait BaseDatabase: salsa::Database { | ||
56 | fn check_canceled(&self) -> Cancelable<()> { | ||
57 | if self.salsa_runtime().is_current_revision_canceled() { | ||
58 | Err(Canceled) | ||
59 | } else { | ||
60 | Ok(()) | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | |||
65 | salsa::query_group! { | ||
66 | pub trait SyntaxDatabase: crate::input::FilesDatabase + BaseDatabase { | ||
67 | fn source_file(file_id: FileId) -> SourceFileNode { | ||
68 | type SourceFileQuery; | ||
69 | } | ||
70 | fn file_lines(file_id: FileId) -> Arc<LineIndex> { | ||
71 | type FileLinesQuery; | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | fn source_file(db: &impl SyntaxDatabase, file_id: FileId) -> SourceFileNode { | ||
77 | let text = db.file_text(file_id); | ||
78 | SourceFileNode::parse(&*text) | ||
79 | } | ||
80 | fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> { | ||
81 | let text = db.file_text(file_id); | ||
82 | Arc::new(LineIndex::new(&*text)) | ||
83 | } | ||
84 | |||
85 | #[derive(Clone, Copy, Debug)] | ||
86 | pub struct FilePosition { | ||
87 | pub file_id: FileId, | ||
88 | pub offset: TextUnit, | ||
89 | } | ||
diff --git a/crates/ra_db/src/loc2id.rs b/crates/ra_db/src/loc2id.rs new file mode 100644 index 000000000..69ba43d0f --- /dev/null +++ b/crates/ra_db/src/loc2id.rs | |||
@@ -0,0 +1,100 @@ | |||
1 | use parking_lot::Mutex; | ||
2 | |||
3 | use std::hash::Hash; | ||
4 | |||
5 | use rustc_hash::FxHashMap; | ||
6 | |||
7 | /// There are two principle ways to refer to things: | ||
8 | /// - by their locatinon (module in foo/bar/baz.rs at line 42) | ||
9 | /// - by their numeric id (module `ModuleId(42)`) | ||
10 | /// | ||
11 | /// The first one is more powerful (you can actually find the thing in question | ||
12 | /// by id), but the second one is so much more compact. | ||
13 | /// | ||
14 | /// `Loc2IdMap` allows us to have a cake an eat it as well: by maintaining a | ||
15 | /// bidirectional mapping between positional and numeric ids, we can use compact | ||
16 | /// representation wich still allows us to get the actual item | ||
17 | #[derive(Debug)] | ||
18 | struct Loc2IdMap<LOC, ID> | ||
19 | where | ||
20 | ID: NumericId, | ||
21 | LOC: Clone + Eq + Hash, | ||
22 | { | ||
23 | loc2id: FxHashMap<LOC, ID>, | ||
24 | id2loc: FxHashMap<ID, LOC>, | ||
25 | } | ||
26 | |||
27 | impl<LOC, ID> Default for Loc2IdMap<LOC, ID> | ||
28 | where | ||
29 | ID: NumericId, | ||
30 | LOC: Clone + Eq + Hash, | ||
31 | { | ||
32 | fn default() -> Self { | ||
33 | Loc2IdMap { | ||
34 | loc2id: FxHashMap::default(), | ||
35 | id2loc: FxHashMap::default(), | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl<LOC, ID> Loc2IdMap<LOC, ID> | ||
41 | where | ||
42 | ID: NumericId, | ||
43 | LOC: Clone + Eq + Hash, | ||
44 | { | ||
45 | pub fn loc2id(&mut self, loc: &LOC) -> ID { | ||
46 | match self.loc2id.get(loc) { | ||
47 | Some(id) => return id.clone(), | ||
48 | None => (), | ||
49 | } | ||
50 | let id = self.loc2id.len(); | ||
51 | assert!(id < u32::max_value() as usize); | ||
52 | let id = ID::from_u32(id as u32); | ||
53 | self.loc2id.insert(loc.clone(), id.clone()); | ||
54 | self.id2loc.insert(id.clone(), loc.clone()); | ||
55 | id | ||
56 | } | ||
57 | |||
58 | pub fn id2loc(&self, id: ID) -> LOC { | ||
59 | self.id2loc[&id].clone() | ||
60 | } | ||
61 | } | ||
62 | |||
63 | pub trait NumericId: Clone + Eq + Hash { | ||
64 | fn from_u32(id: u32) -> Self; | ||
65 | fn to_u32(self) -> u32; | ||
66 | } | ||
67 | |||
68 | #[derive(Debug)] | ||
69 | pub struct LocationIntener<LOC, ID> | ||
70 | where | ||
71 | ID: NumericId, | ||
72 | LOC: Clone + Eq + Hash, | ||
73 | { | ||
74 | map: Mutex<Loc2IdMap<LOC, ID>>, | ||
75 | } | ||
76 | |||
77 | impl<LOC, ID> Default for LocationIntener<LOC, ID> | ||
78 | where | ||
79 | ID: NumericId, | ||
80 | LOC: Clone + Eq + Hash, | ||
81 | { | ||
82 | fn default() -> Self { | ||
83 | LocationIntener { | ||
84 | map: Default::default(), | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | impl<LOC, ID> LocationIntener<LOC, ID> | ||
90 | where | ||
91 | ID: NumericId, | ||
92 | LOC: Clone + Eq + Hash, | ||
93 | { | ||
94 | pub fn loc2id(&self, loc: &LOC) -> ID { | ||
95 | self.map.lock().loc2id(loc) | ||
96 | } | ||
97 | pub fn id2loc(&self, id: ID) -> LOC { | ||
98 | self.map.lock().id2loc(id) | ||
99 | } | ||
100 | } | ||
diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_db/src/syntax_ptr.rs index e45934ce0..dac94dd36 100644 --- a/crates/ra_analysis/src/syntax_ptr.rs +++ b/crates/ra_db/src/syntax_ptr.rs | |||
@@ -1,49 +1,21 @@ | |||
1 | use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange}; | 1 | use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange}; |
2 | 2 | ||
3 | use crate::db::SyntaxDatabase; | ||
4 | use crate::FileId; | ||
5 | |||
6 | pub(crate) fn resolve_syntax_ptr(db: &impl SyntaxDatabase, ptr: SyntaxPtr) -> SyntaxNode { | ||
7 | let syntax = db.file_syntax(ptr.file_id); | ||
8 | ptr.local.resolve(&syntax) | ||
9 | } | ||
10 | |||
11 | /// SyntaxPtr is a cheap `Copy` id which identifies a particular syntax node, | ||
12 | /// without retaining syntax tree in memory. You need to explicitly `resolve` | ||
13 | /// `SyntaxPtr` to get a `SyntaxNode` | ||
14 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
15 | pub(crate) struct SyntaxPtr { | ||
16 | file_id: FileId, | ||
17 | local: LocalSyntaxPtr, | ||
18 | } | ||
19 | |||
20 | impl SyntaxPtr { | ||
21 | pub(crate) fn new(file_id: FileId, node: SyntaxNodeRef) -> SyntaxPtr { | ||
22 | let local = LocalSyntaxPtr::new(node); | ||
23 | SyntaxPtr { file_id, local } | ||
24 | } | ||
25 | |||
26 | pub(crate) fn file_id(self) -> FileId { | ||
27 | self.file_id | ||
28 | } | ||
29 | } | ||
30 | |||
31 | /// A pionter to a syntax node inside a file. | 3 | /// A pionter to a syntax node inside a file. |
32 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
33 | pub(crate) struct LocalSyntaxPtr { | 5 | pub struct LocalSyntaxPtr { |
34 | range: TextRange, | 6 | range: TextRange, |
35 | kind: SyntaxKind, | 7 | kind: SyntaxKind, |
36 | } | 8 | } |
37 | 9 | ||
38 | impl LocalSyntaxPtr { | 10 | impl LocalSyntaxPtr { |
39 | pub(crate) fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr { | 11 | pub fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr { |
40 | LocalSyntaxPtr { | 12 | LocalSyntaxPtr { |
41 | range: node.range(), | 13 | range: node.range(), |
42 | kind: node.kind(), | 14 | kind: node.kind(), |
43 | } | 15 | } |
44 | } | 16 | } |
45 | 17 | ||
46 | pub(crate) fn resolve(self, file: &SourceFileNode) -> SyntaxNode { | 18 | pub fn resolve(self, file: &SourceFileNode) -> SyntaxNode { |
47 | let mut curr = file.syntax(); | 19 | let mut curr = file.syntax(); |
48 | loop { | 20 | loop { |
49 | if curr.range() == self.range && curr.kind() == self.kind { | 21 | if curr.range() == self.range && curr.kind() == self.kind { |
@@ -56,11 +28,8 @@ impl LocalSyntaxPtr { | |||
56 | } | 28 | } |
57 | } | 29 | } |
58 | 30 | ||
59 | pub(crate) fn into_global(self, file_id: FileId) -> SyntaxPtr { | 31 | pub fn range(self) -> TextRange { |
60 | SyntaxPtr { | 32 | self.range |
61 | file_id, | ||
62 | local: self, | ||
63 | } | ||
64 | } | 33 | } |
65 | } | 34 | } |
66 | 35 | ||
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml new file mode 100644 index 000000000..9bde289e7 --- /dev/null +++ b/crates/ra_hir/Cargo.toml | |||
@@ -0,0 +1,17 @@ | |||
1 | [package] | ||
2 | edition = "2018" | ||
3 | name = "ra_hir" | ||
4 | version = "0.1.0" | ||
5 | authors = ["Aleksey Kladov <[email protected]>"] | ||
6 | |||
7 | [dependencies] | ||
8 | log = "0.4.5" | ||
9 | relative-path = "0.4.0" | ||
10 | salsa = "0.8.0" | ||
11 | rustc-hash = "1.0" | ||
12 | parking_lot = "0.6.4" | ||
13 | id-arena = { git = "https://github.com/fitzgen/id-arena/", rev = "43ecd67" } | ||
14 | ra_syntax = { path = "../ra_syntax" } | ||
15 | ra_editor = { path = "../ra_editor" } | ||
16 | ra_db = { path = "../ra_db" } | ||
17 | test_utils = { path = "../test_utils" } | ||
diff --git a/crates/ra_analysis/src/arena.rs b/crates/ra_hir/src/arena.rs index a752ec0c1..8d67ab1c9 100644 --- a/crates/ra_analysis/src/arena.rs +++ b/crates/ra_hir/src/arena.rs | |||
@@ -8,7 +8,7 @@ use std::{ | |||
8 | marker::PhantomData, | 8 | marker::PhantomData, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | pub(crate) struct Id<T> { | 11 | pub struct Id<T> { |
12 | idx: u32, | 12 | idx: u32, |
13 | _ty: PhantomData<fn() -> T>, | 13 | _ty: PhantomData<fn() -> T>, |
14 | } | 14 | } |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs new file mode 100644 index 000000000..2f01bae6d --- /dev/null +++ b/crates/ra_hir/src/db.rs | |||
@@ -0,0 +1,66 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_syntax::{ | ||
4 | SyntaxNode, | ||
5 | ast::FnDefNode, | ||
6 | }; | ||
7 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable}; | ||
8 | |||
9 | use crate::{ | ||
10 | DefLoc, DefId, FnId, | ||
11 | SourceFileItems, SourceItemId, | ||
12 | query_definitions, | ||
13 | FnScopes, | ||
14 | module::{ModuleId, ModuleTree, ModuleSource, | ||
15 | nameres::{ItemMap, InputModuleItems}}, | ||
16 | }; | ||
17 | |||
18 | salsa::query_group! { | ||
19 | |||
20 | pub trait HirDatabase: SyntaxDatabase | ||
21 | + AsRef<LocationIntener<DefLoc, DefId>> | ||
22 | + AsRef<LocationIntener<SourceItemId, FnId>> | ||
23 | { | ||
24 | fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { | ||
25 | type FnScopesQuery; | ||
26 | use fn query_definitions::fn_scopes; | ||
27 | } | ||
28 | fn fn_syntax(fn_id: FnId) -> FnDefNode { | ||
29 | type FnSyntaxQuery; | ||
30 | // Don't retain syntax trees in memory | ||
31 | storage dependencies; | ||
32 | use fn query_definitions::fn_syntax; | ||
33 | } | ||
34 | |||
35 | fn file_items(file_id: FileId) -> Arc<SourceFileItems> { | ||
36 | type SourceFileItemsQuery; | ||
37 | storage dependencies; | ||
38 | use fn query_definitions::file_items; | ||
39 | } | ||
40 | |||
41 | fn file_item(source_item_id: SourceItemId) -> SyntaxNode { | ||
42 | type FileItemQuery; | ||
43 | storage dependencies; | ||
44 | use fn query_definitions::file_item; | ||
45 | } | ||
46 | |||
47 | fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<crate::module::imp::Submodule>>> { | ||
48 | type SubmodulesQuery; | ||
49 | use fn query_definitions::submodules; | ||
50 | } | ||
51 | |||
52 | fn input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<InputModuleItems>> { | ||
53 | type InputModuleItemsQuery; | ||
54 | use fn query_definitions::input_module_items; | ||
55 | } | ||
56 | fn item_map(source_root_id: SourceRootId) -> Cancelable<Arc<ItemMap>> { | ||
57 | type ItemMapQuery; | ||
58 | use fn query_definitions::item_map; | ||
59 | } | ||
60 | fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { | ||
61 | type ModuleTreeQuery; | ||
62 | use fn crate::module::imp::module_tree; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | } | ||
diff --git a/crates/ra_analysis/src/descriptors/function/mod.rs b/crates/ra_hir/src/function/mod.rs index 86eee5e93..c8af2e54f 100644 --- a/crates/ra_analysis/src/descriptors/function/mod.rs +++ b/crates/ra_hir/src/function/mod.rs | |||
@@ -1,30 +1,83 @@ | |||
1 | pub(super) mod imp; | ||
2 | mod scope; | 1 | mod scope; |
3 | 2 | ||
4 | use std::cmp::{max, min}; | 3 | use std::{ |
4 | cmp::{max, min}, | ||
5 | sync::Arc, | ||
6 | }; | ||
5 | 7 | ||
6 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | TextRange, TextUnit, SyntaxNodeRef, | ||
7 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
8 | TextRange, TextUnit, | ||
9 | }; | 11 | }; |
12 | use ra_db::FileId; | ||
10 | 13 | ||
11 | use crate::{ | 14 | use crate::{ |
12 | syntax_ptr::SyntaxPtr, FileId, | 15 | FnId, HirDatabase, SourceItemId, |
13 | loc2id::IdDatabase, | ||
14 | }; | 16 | }; |
15 | 17 | ||
16 | pub(crate) use self::scope::{resolve_local_name, FnScopes}; | 18 | pub use self::scope::FnScopes; |
17 | pub(crate) use crate::loc2id::FnId; | ||
18 | 19 | ||
19 | impl FnId { | 20 | impl FnId { |
20 | pub(crate) fn get(db: &impl IdDatabase, file_id: FileId, fn_def: ast::FnDef) -> FnId { | 21 | pub fn get(db: &impl HirDatabase, file_id: FileId, fn_def: ast::FnDef) -> FnId { |
21 | let ptr = SyntaxPtr::new(file_id, fn_def.syntax()); | 22 | let file_items = db.file_items(file_id); |
22 | db.id_maps().fn_id(ptr) | 23 | let item_id = file_items.id_of(fn_def.syntax()); |
24 | let item_id = SourceItemId { file_id, item_id }; | ||
25 | FnId::from_loc(db, &item_id) | ||
26 | } | ||
27 | } | ||
28 | |||
29 | pub struct Function { | ||
30 | fn_id: FnId, | ||
31 | } | ||
32 | |||
33 | impl Function { | ||
34 | pub fn guess_from_source( | ||
35 | db: &impl HirDatabase, | ||
36 | file_id: FileId, | ||
37 | fn_def: ast::FnDef, | ||
38 | ) -> Function { | ||
39 | let fn_id = FnId::get(db, file_id, fn_def); | ||
40 | Function { fn_id } | ||
41 | } | ||
42 | |||
43 | pub fn guess_for_name_ref( | ||
44 | db: &impl HirDatabase, | ||
45 | file_id: FileId, | ||
46 | name_ref: ast::NameRef, | ||
47 | ) -> Option<Function> { | ||
48 | Function::guess_for_node(db, file_id, name_ref.syntax()) | ||
49 | } | ||
50 | |||
51 | pub fn guess_for_bind_pat( | ||
52 | db: &impl HirDatabase, | ||
53 | file_id: FileId, | ||
54 | bind_pat: ast::BindPat, | ||
55 | ) -> Option<Function> { | ||
56 | Function::guess_for_node(db, file_id, bind_pat.syntax()) | ||
57 | } | ||
58 | |||
59 | fn guess_for_node( | ||
60 | db: &impl HirDatabase, | ||
61 | file_id: FileId, | ||
62 | node: SyntaxNodeRef, | ||
63 | ) -> Option<Function> { | ||
64 | let fn_def = node.ancestors().find_map(ast::FnDef::cast)?; | ||
65 | let res = Function::guess_from_source(db, file_id, fn_def); | ||
66 | Some(res) | ||
67 | } | ||
68 | |||
69 | pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> { | ||
70 | db.fn_scopes(self.fn_id) | ||
71 | } | ||
72 | |||
73 | pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> { | ||
74 | let syntax = db.fn_syntax(self.fn_id); | ||
75 | FnSignatureInfo::new(syntax.borrowed()) | ||
23 | } | 76 | } |
24 | } | 77 | } |
25 | 78 | ||
26 | #[derive(Debug, Clone)] | 79 | #[derive(Debug, Clone)] |
27 | pub struct FnDescriptor { | 80 | pub struct FnSignatureInfo { |
28 | pub name: String, | 81 | pub name: String, |
29 | pub label: String, | 82 | pub label: String, |
30 | pub ret_type: Option<String>, | 83 | pub ret_type: Option<String>, |
@@ -32,8 +85,8 @@ pub struct FnDescriptor { | |||
32 | pub doc: Option<String>, | 85 | pub doc: Option<String>, |
33 | } | 86 | } |
34 | 87 | ||
35 | impl FnDescriptor { | 88 | impl FnSignatureInfo { |
36 | pub fn new(node: ast::FnDef) -> Option<Self> { | 89 | fn new(node: ast::FnDef) -> Option<Self> { |
37 | let name = node.name()?.text().to_string(); | 90 | let name = node.name()?.text().to_string(); |
38 | 91 | ||
39 | let mut doc = None; | 92 | let mut doc = None; |
@@ -52,7 +105,7 @@ impl FnDescriptor { | |||
52 | node.syntax().text().to_string() | 105 | node.syntax().text().to_string() |
53 | }; | 106 | }; |
54 | 107 | ||
55 | if let Some((comment_range, docs)) = FnDescriptor::extract_doc_comments(node) { | 108 | if let Some((comment_range, docs)) = FnSignatureInfo::extract_doc_comments(node) { |
56 | let comment_range = comment_range | 109 | let comment_range = comment_range |
57 | .checked_sub(node.syntax().range().start()) | 110 | .checked_sub(node.syntax().range().start()) |
58 | .unwrap(); | 111 | .unwrap(); |
@@ -84,10 +137,10 @@ impl FnDescriptor { | |||
84 | } | 137 | } |
85 | } | 138 | } |
86 | 139 | ||
87 | let params = FnDescriptor::param_list(node); | 140 | let params = FnSignatureInfo::param_list(node); |
88 | let ret_type = node.ret_type().map(|r| r.syntax().text().to_string()); | 141 | let ret_type = node.ret_type().map(|r| r.syntax().text().to_string()); |
89 | 142 | ||
90 | Some(FnDescriptor { | 143 | Some(FnSignatureInfo { |
91 | name, | 144 | name, |
92 | ret_type, | 145 | ret_type, |
93 | params, | 146 | params, |
diff --git a/crates/ra_analysis/src/descriptors/function/scope.rs b/crates/ra_hir/src/function/scope.rs index 5307a0a8e..863453291 100644 --- a/crates/ra_analysis/src/descriptors/function/scope.rs +++ b/crates/ra_hir/src/function/scope.rs | |||
@@ -1,13 +1,13 @@ | |||
1 | use rustc_hash::{FxHashMap, FxHashSet}; | 1 | use rustc_hash::{FxHashMap, FxHashSet}; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | AstNode, SmolStr, SyntaxNodeRef, TextRange, | ||
4 | algo::generate, | 5 | algo::generate, |
5 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, | 6 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, |
6 | AstNode, SmolStr, SyntaxNodeRef, | ||
7 | }; | 7 | }; |
8 | use ra_db::LocalSyntaxPtr; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | syntax_ptr::LocalSyntaxPtr, | ||
11 | arena::{Arena, Id}, | 11 | arena::{Arena, Id}, |
12 | }; | 12 | }; |
13 | 13 | ||
@@ -15,7 +15,7 @@ pub(crate) type ScopeId = Id<ScopeData>; | |||
15 | 15 | ||
16 | #[derive(Debug, PartialEq, Eq)] | 16 | #[derive(Debug, PartialEq, Eq)] |
17 | pub struct FnScopes { | 17 | pub struct FnScopes { |
18 | pub(crate) self_param: Option<LocalSyntaxPtr>, | 18 | pub self_param: Option<LocalSyntaxPtr>, |
19 | scopes: Arena<ScopeData>, | 19 | scopes: Arena<ScopeData>, |
20 | scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>, | 20 | scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>, |
21 | } | 21 | } |
@@ -27,13 +27,13 @@ pub struct ScopeEntry { | |||
27 | } | 27 | } |
28 | 28 | ||
29 | #[derive(Debug, PartialEq, Eq)] | 29 | #[derive(Debug, PartialEq, Eq)] |
30 | pub(crate) struct ScopeData { | 30 | pub struct ScopeData { |
31 | parent: Option<ScopeId>, | 31 | parent: Option<ScopeId>, |
32 | entries: Vec<ScopeEntry>, | 32 | entries: Vec<ScopeEntry>, |
33 | } | 33 | } |
34 | 34 | ||
35 | impl FnScopes { | 35 | impl FnScopes { |
36 | pub(crate) fn new(fn_def: ast::FnDef) -> FnScopes { | 36 | pub fn new(fn_def: ast::FnDef) -> FnScopes { |
37 | let mut scopes = FnScopes { | 37 | let mut scopes = FnScopes { |
38 | self_param: fn_def | 38 | self_param: fn_def |
39 | .param_list() | 39 | .param_list() |
@@ -49,7 +49,7 @@ impl FnScopes { | |||
49 | } | 49 | } |
50 | scopes | 50 | scopes |
51 | } | 51 | } |
52 | pub(crate) fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | 52 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { |
53 | &self.scopes[scope].entries | 53 | &self.scopes[scope].entries |
54 | } | 54 | } |
55 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { | 55 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { |
@@ -57,6 +57,37 @@ impl FnScopes { | |||
57 | self.scopes[scope].parent | 57 | self.scopes[scope].parent |
58 | }) | 58 | }) |
59 | } | 59 | } |
60 | pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> { | ||
61 | let mut shadowed = FxHashSet::default(); | ||
62 | let ret = self | ||
63 | .scope_chain(name_ref.syntax()) | ||
64 | .flat_map(|scope| self.entries(scope).iter()) | ||
65 | .filter(|entry| shadowed.insert(entry.name())) | ||
66 | .filter(|entry| entry.name() == &name_ref.text()) | ||
67 | .nth(0); | ||
68 | ret | ||
69 | } | ||
70 | |||
71 | pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> { | ||
72 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | ||
73 | let name_ptr = LocalSyntaxPtr::new(pat.syntax()); | ||
74 | let refs: Vec<_> = fn_def | ||
75 | .syntax() | ||
76 | .descendants() | ||
77 | .filter_map(ast::NameRef::cast) | ||
78 | .filter(|name_ref| match self.resolve_local_name(*name_ref) { | ||
79 | None => false, | ||
80 | Some(entry) => entry.ptr() == name_ptr, | ||
81 | }) | ||
82 | .map(|name_ref| ReferenceDescriptor { | ||
83 | name: name_ref.syntax().text().to_string(), | ||
84 | range: name_ref.syntax().range(), | ||
85 | }) | ||
86 | .collect(); | ||
87 | |||
88 | refs | ||
89 | } | ||
90 | |||
60 | fn root_scope(&mut self) -> ScopeId { | 91 | fn root_scope(&mut self) -> ScopeId { |
61 | self.scopes.alloc(ScopeData { | 92 | self.scopes.alloc(ScopeData { |
62 | parent: None, | 93 | parent: None, |
@@ -104,10 +135,10 @@ impl ScopeEntry { | |||
104 | }; | 135 | }; |
105 | Some(res) | 136 | Some(res) |
106 | } | 137 | } |
107 | pub(crate) fn name(&self) -> &SmolStr { | 138 | pub fn name(&self) -> &SmolStr { |
108 | &self.name | 139 | &self.name |
109 | } | 140 | } |
110 | pub(crate) fn ptr(&self) -> LocalSyntaxPtr { | 141 | pub fn ptr(&self) -> LocalSyntaxPtr { |
111 | self.ptr | 142 | self.ptr |
112 | } | 143 | } |
113 | } | 144 | } |
@@ -249,18 +280,10 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | |||
249 | } | 280 | } |
250 | } | 281 | } |
251 | 282 | ||
252 | pub fn resolve_local_name<'a>( | 283 | #[derive(Debug)] |
253 | name_ref: ast::NameRef, | 284 | pub struct ReferenceDescriptor { |
254 | scopes: &'a FnScopes, | 285 | pub range: TextRange, |
255 | ) -> Option<&'a ScopeEntry> { | 286 | pub name: String, |
256 | let mut shadowed = FxHashSet::default(); | ||
257 | let ret = scopes | ||
258 | .scope_chain(name_ref.syntax()) | ||
259 | .flat_map(|scope| scopes.entries(scope).iter()) | ||
260 | .filter(|entry| shadowed.insert(entry.name())) | ||
261 | .filter(|entry| entry.name() == &name_ref.text()) | ||
262 | .nth(0); | ||
263 | ret | ||
264 | } | 287 | } |
265 | 288 | ||
266 | #[cfg(test)] | 289 | #[cfg(test)] |
@@ -376,7 +399,7 @@ mod tests { | |||
376 | 399 | ||
377 | let scopes = FnScopes::new(fn_def); | 400 | let scopes = FnScopes::new(fn_def); |
378 | 401 | ||
379 | let local_name_entry = resolve_local_name(name_ref, &scopes).unwrap(); | 402 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); |
380 | let local_name = local_name_entry.ptr().resolve(&file); | 403 | let local_name = local_name_entry.ptr().resolve(&file); |
381 | let expected_name = | 404 | let expected_name = |
382 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); | 405 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs new file mode 100644 index 000000000..f13f0107e --- /dev/null +++ b/crates/ra_hir/src/lib.rs | |||
@@ -0,0 +1,139 @@ | |||
1 | //! HIR (previsouly known as descriptors) provides a high-level OO acess to Rust | ||
2 | //! code. | ||
3 | //! | ||
4 | //! The principal difference between HIR and syntax trees is that HIR is bound | ||
5 | //! to a particular crate instance. That is, it has cfg flags and features | ||
6 | //! applied. So, there relation between syntax and HIR is many-to-one. | ||
7 | |||
8 | macro_rules! ctry { | ||
9 | ($expr:expr) => { | ||
10 | match $expr { | ||
11 | None => return Ok(None), | ||
12 | Some(it) => it, | ||
13 | } | ||
14 | }; | ||
15 | } | ||
16 | |||
17 | pub mod db; | ||
18 | mod query_definitions; | ||
19 | mod function; | ||
20 | mod module; | ||
21 | mod path; | ||
22 | mod arena; | ||
23 | |||
24 | use std::ops::Index; | ||
25 | |||
26 | use ra_syntax::{SyntaxNodeRef, SyntaxNode}; | ||
27 | use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable}; | ||
28 | |||
29 | use crate::{ | ||
30 | db::HirDatabase, | ||
31 | arena::{Arena, Id}, | ||
32 | }; | ||
33 | |||
34 | pub use self::{ | ||
35 | path::{Path, PathKind}, | ||
36 | module::{Module, ModuleId, Problem, nameres::ItemMap}, | ||
37 | function::{Function, FnScopes}, | ||
38 | }; | ||
39 | |||
40 | pub use self::function::FnSignatureInfo; | ||
41 | |||
42 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
43 | pub struct FnId(u32); | ||
44 | ra_db::impl_numeric_id!(FnId); | ||
45 | |||
46 | impl FnId { | ||
47 | pub fn from_loc( | ||
48 | db: &impl AsRef<LocationIntener<SourceItemId, FnId>>, | ||
49 | loc: &SourceItemId, | ||
50 | ) -> FnId { | ||
51 | db.as_ref().loc2id(loc) | ||
52 | } | ||
53 | pub fn loc(self, db: &impl AsRef<LocationIntener<SourceItemId, FnId>>) -> SourceItemId { | ||
54 | db.as_ref().id2loc(self) | ||
55 | } | ||
56 | } | ||
57 | |||
58 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
59 | pub struct DefId(u32); | ||
60 | ra_db::impl_numeric_id!(DefId); | ||
61 | |||
62 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
63 | pub enum DefLoc { | ||
64 | Module { | ||
65 | id: ModuleId, | ||
66 | source_root: SourceRootId, | ||
67 | }, | ||
68 | Item { | ||
69 | source_item_id: SourceItemId, | ||
70 | }, | ||
71 | } | ||
72 | |||
73 | impl DefId { | ||
74 | pub fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc { | ||
75 | db.as_ref().id2loc(self) | ||
76 | } | ||
77 | } | ||
78 | |||
79 | impl DefLoc { | ||
80 | pub fn id(&self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefId { | ||
81 | db.as_ref().loc2id(&self) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | pub enum Def { | ||
86 | Module(Module), | ||
87 | Item, | ||
88 | } | ||
89 | |||
90 | impl DefId { | ||
91 | pub fn resolve(self, db: &impl HirDatabase) -> Cancelable<Def> { | ||
92 | let loc = self.loc(db); | ||
93 | let res = match loc { | ||
94 | DefLoc::Module { id, source_root } => { | ||
95 | let descr = Module::new(db, source_root, id)?; | ||
96 | Def::Module(descr) | ||
97 | } | ||
98 | DefLoc::Item { .. } => Def::Item, | ||
99 | }; | ||
100 | Ok(res) | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /// Identifier of item within a specific file. This is stable over reparses, so | ||
105 | /// it's OK to use it as a salsa key/value. | ||
106 | pub(crate) type SourceFileItemId = Id<SyntaxNode>; | ||
107 | |||
108 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
109 | pub struct SourceItemId { | ||
110 | file_id: FileId, | ||
111 | item_id: SourceFileItemId, | ||
112 | } | ||
113 | |||
114 | /// Maps item's `SyntaxNode`s to `SourceFileItemId` and back. | ||
115 | #[derive(Debug, PartialEq, Eq, Default)] | ||
116 | pub struct SourceFileItems { | ||
117 | arena: Arena<SyntaxNode>, | ||
118 | } | ||
119 | |||
120 | impl SourceFileItems { | ||
121 | fn alloc(&mut self, item: SyntaxNode) -> SourceFileItemId { | ||
122 | self.arena.alloc(item) | ||
123 | } | ||
124 | pub fn id_of(&self, item: SyntaxNodeRef) -> SourceFileItemId { | ||
125 | let (id, _item) = self | ||
126 | .arena | ||
127 | .iter() | ||
128 | .find(|(_id, i)| i.borrowed() == item) | ||
129 | .unwrap(); | ||
130 | id | ||
131 | } | ||
132 | } | ||
133 | |||
134 | impl Index<SourceFileItemId> for SourceFileItems { | ||
135 | type Output = SyntaxNode; | ||
136 | fn index(&self, idx: SourceFileItemId) -> &SyntaxNode { | ||
137 | &self.arena[idx] | ||
138 | } | ||
139 | } | ||
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_hir/src/module/imp.rs index 80892acb7..76ea129a7 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_hir/src/module/imp.rs | |||
@@ -6,21 +6,19 @@ use ra_syntax::{ | |||
6 | }; | 6 | }; |
7 | use relative_path::RelativePathBuf; | 7 | use relative_path::RelativePathBuf; |
8 | use rustc_hash::{FxHashMap, FxHashSet}; | 8 | use rustc_hash::{FxHashMap, FxHashSet}; |
9 | use ra_db::{SourceRoot, SourceRootId, FileResolverImp, Cancelable, FileId,}; | ||
9 | 10 | ||
10 | use crate::{ | 11 | use crate::{ |
11 | db, | 12 | HirDatabase, |
12 | descriptors::DescriptorDatabase, | ||
13 | input::{SourceRoot, SourceRootId}, | ||
14 | Cancelable, FileId, FileResolverImp, | ||
15 | }; | 13 | }; |
16 | 14 | ||
17 | use super::{ | 15 | use super::{ |
18 | LinkData, LinkId, ModuleData, ModuleId, ModuleSource, ModuleSourceNode, | 16 | LinkData, LinkId, ModuleData, ModuleId, ModuleSource, |
19 | ModuleTree, Problem, | 17 | ModuleTree, Problem, |
20 | }; | 18 | }; |
21 | 19 | ||
22 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] | 20 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] |
23 | pub(crate) enum Submodule { | 21 | pub enum Submodule { |
24 | Declaration(SmolStr), | 22 | Declaration(SmolStr), |
25 | Definition(SmolStr, ModuleSource), | 23 | Definition(SmolStr, ModuleSource), |
26 | } | 24 | } |
@@ -34,39 +32,6 @@ impl Submodule { | |||
34 | } | 32 | } |
35 | } | 33 | } |
36 | 34 | ||
37 | pub(crate) fn submodules( | ||
38 | db: &impl DescriptorDatabase, | ||
39 | source: ModuleSource, | ||
40 | ) -> Cancelable<Arc<Vec<Submodule>>> { | ||
41 | db::check_canceled(db)?; | ||
42 | let file_id = source.file_id(); | ||
43 | let submodules = match source.resolve(db) { | ||
44 | ModuleSourceNode::SourceFile(it) => collect_submodules(file_id, it.borrowed()), | ||
45 | ModuleSourceNode::Module(it) => it | ||
46 | .borrowed() | ||
47 | .item_list() | ||
48 | .map(|it| collect_submodules(file_id, it)) | ||
49 | .unwrap_or_else(Vec::new), | ||
50 | }; | ||
51 | return Ok(Arc::new(submodules)); | ||
52 | |||
53 | fn collect_submodules<'a>( | ||
54 | file_id: FileId, | ||
55 | root: impl ast::ModuleItemOwner<'a>, | ||
56 | ) -> Vec<Submodule> { | ||
57 | modules(root) | ||
58 | .map(|(name, m)| { | ||
59 | if m.has_semi() { | ||
60 | Submodule::Declaration(name) | ||
61 | } else { | ||
62 | let src = ModuleSource::new_inline(file_id, m); | ||
63 | Submodule::Definition(name, src) | ||
64 | } | ||
65 | }) | ||
66 | .collect() | ||
67 | } | ||
68 | } | ||
69 | |||
70 | pub(crate) fn modules<'a>( | 35 | pub(crate) fn modules<'a>( |
71 | root: impl ast::ModuleItemOwner<'a>, | 36 | root: impl ast::ModuleItemOwner<'a>, |
72 | ) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> { | 37 | ) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> { |
@@ -82,16 +47,16 @@ pub(crate) fn modules<'a>( | |||
82 | } | 47 | } |
83 | 48 | ||
84 | pub(crate) fn module_tree( | 49 | pub(crate) fn module_tree( |
85 | db: &impl DescriptorDatabase, | 50 | db: &impl HirDatabase, |
86 | source_root: SourceRootId, | 51 | source_root: SourceRootId, |
87 | ) -> Cancelable<Arc<ModuleTree>> { | 52 | ) -> Cancelable<Arc<ModuleTree>> { |
88 | db::check_canceled(db)?; | 53 | db.check_canceled()?; |
89 | let res = create_module_tree(db, source_root)?; | 54 | let res = create_module_tree(db, source_root)?; |
90 | Ok(Arc::new(res)) | 55 | Ok(Arc::new(res)) |
91 | } | 56 | } |
92 | 57 | ||
93 | fn create_module_tree<'a>( | 58 | fn create_module_tree<'a>( |
94 | db: &impl DescriptorDatabase, | 59 | db: &impl HirDatabase, |
95 | source_root: SourceRootId, | 60 | source_root: SourceRootId, |
96 | ) -> Cancelable<ModuleTree> { | 61 | ) -> Cancelable<ModuleTree> { |
97 | let mut tree = ModuleTree::default(); | 62 | let mut tree = ModuleTree::default(); |
@@ -121,7 +86,7 @@ fn create_module_tree<'a>( | |||
121 | } | 86 | } |
122 | 87 | ||
123 | fn build_subtree( | 88 | fn build_subtree( |
124 | db: &impl DescriptorDatabase, | 89 | db: &impl HirDatabase, |
125 | source_root: &SourceRoot, | 90 | source_root: &SourceRoot, |
126 | tree: &mut ModuleTree, | 91 | tree: &mut ModuleTree, |
127 | visited: &mut FxHashSet<ModuleSource>, | 92 | visited: &mut FxHashSet<ModuleSource>, |
@@ -135,7 +100,7 @@ fn build_subtree( | |||
135 | parent, | 100 | parent, |
136 | children: Vec::new(), | 101 | children: Vec::new(), |
137 | }); | 102 | }); |
138 | for sub in db._submodules(source)?.iter() { | 103 | for sub in db.submodules(source)?.iter() { |
139 | let link = tree.push_link(LinkData { | 104 | let link = tree.push_link(LinkData { |
140 | name: sub.name().clone(), | 105 | name: sub.name().clone(), |
141 | owner: id, | 106 | owner: id, |
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_hir/src/module/mod.rs index 78911d5d9..a011fd53e 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_hir/src/module/mod.rs | |||
@@ -10,65 +10,64 @@ use ra_syntax::{ | |||
10 | ast::{self, AstNode, NameOwner}, | 10 | ast::{self, AstNode, NameOwner}, |
11 | SmolStr, SyntaxNode, | 11 | SmolStr, SyntaxNode, |
12 | }; | 12 | }; |
13 | use ra_db::{SourceRootId, FileId, FilePosition, Cancelable}; | ||
13 | use relative_path::RelativePathBuf; | 14 | use relative_path::RelativePathBuf; |
14 | 15 | ||
15 | use crate::{ | 16 | use crate::{ |
16 | db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId, FilePosition, Cancelable, | 17 | DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, |
17 | descriptors::{Path, PathKind, DescriptorDatabase}, | ||
18 | input::SourceRootId, | ||
19 | arena::{Arena, Id}, | 18 | arena::{Arena, Id}, |
20 | loc2id::{DefLoc, DefId}, | ||
21 | }; | 19 | }; |
22 | 20 | ||
23 | pub(crate) use self::nameres::ModuleScope; | 21 | pub use self::nameres::ModuleScope; |
24 | 22 | ||
25 | /// `ModuleDescriptor` is API entry point to get all the information | 23 | /// `Module` is API entry point to get all the information |
26 | /// about a particular module. | 24 | /// about a particular module. |
27 | #[derive(Debug, Clone)] | 25 | #[derive(Debug, Clone)] |
28 | pub(crate) struct ModuleDescriptor { | 26 | pub struct Module { |
29 | tree: Arc<ModuleTree>, | 27 | tree: Arc<ModuleTree>, |
30 | source_root_id: SourceRootId, | 28 | source_root_id: SourceRootId, |
31 | module_id: ModuleId, | 29 | //TODO: make private |
30 | pub module_id: ModuleId, | ||
32 | } | 31 | } |
33 | 32 | ||
34 | impl ModuleDescriptor { | 33 | impl Module { |
35 | /// Lookup `ModuleDescriptor` by `FileId`. Note that this is inherently | 34 | /// Lookup `Module` by `FileId`. Note that this is inherently |
36 | /// lossy transformation: in general, a single source might correspond to | 35 | /// lossy transformation: in general, a single source might correspond to |
37 | /// several modules. | 36 | /// several modules. |
38 | pub fn guess_from_file_id( | 37 | pub fn guess_from_file_id( |
39 | db: &impl DescriptorDatabase, | 38 | db: &impl HirDatabase, |
40 | file_id: FileId, | 39 | file_id: FileId, |
41 | ) -> Cancelable<Option<ModuleDescriptor>> { | 40 | ) -> Cancelable<Option<Module>> { |
42 | ModuleDescriptor::guess_from_source(db, file_id, ModuleSource::SourceFile(file_id)) | 41 | Module::guess_from_source(db, file_id, ModuleSource::SourceFile(file_id)) |
43 | } | 42 | } |
44 | 43 | ||
45 | /// Lookup `ModuleDescriptor` by position in the source code. Note that this | 44 | /// Lookup `Module` by position in the source code. Note that this |
46 | /// is inherently lossy transformation: in general, a single source might | 45 | /// is inherently lossy transformation: in general, a single source might |
47 | /// correspond to several modules. | 46 | /// correspond to several modules. |
48 | pub fn guess_from_position( | 47 | pub fn guess_from_position( |
49 | db: &impl DescriptorDatabase, | 48 | db: &impl HirDatabase, |
50 | position: FilePosition, | 49 | position: FilePosition, |
51 | ) -> Cancelable<Option<ModuleDescriptor>> { | 50 | ) -> Cancelable<Option<Module>> { |
52 | let file = db.file_syntax(position.file_id); | 51 | let file = db.source_file(position.file_id); |
53 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) | 52 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) |
54 | { | 53 | { |
55 | Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m), | 54 | Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m), |
56 | _ => ModuleSource::SourceFile(position.file_id), | 55 | _ => ModuleSource::SourceFile(position.file_id), |
57 | }; | 56 | }; |
58 | ModuleDescriptor::guess_from_source(db, position.file_id, module_source) | 57 | Module::guess_from_source(db, position.file_id, module_source) |
59 | } | 58 | } |
60 | 59 | ||
61 | fn guess_from_source( | 60 | fn guess_from_source( |
62 | db: &impl DescriptorDatabase, | 61 | db: &impl HirDatabase, |
63 | file_id: FileId, | 62 | file_id: FileId, |
64 | module_source: ModuleSource, | 63 | module_source: ModuleSource, |
65 | ) -> Cancelable<Option<ModuleDescriptor>> { | 64 | ) -> Cancelable<Option<Module>> { |
66 | let source_root_id = db.file_source_root(file_id); | 65 | let source_root_id = db.file_source_root(file_id); |
67 | let module_tree = db._module_tree(source_root_id)?; | 66 | let module_tree = db.module_tree(source_root_id)?; |
68 | 67 | ||
69 | let res = match module_tree.any_module_for_source(module_source) { | 68 | let res = match module_tree.any_module_for_source(module_source) { |
70 | None => None, | 69 | None => None, |
71 | Some(module_id) => Some(ModuleDescriptor { | 70 | Some(module_id) => Some(Module { |
72 | tree: module_tree, | 71 | tree: module_tree, |
73 | source_root_id, | 72 | source_root_id, |
74 | module_id, | 73 | module_id, |
@@ -78,12 +77,12 @@ impl ModuleDescriptor { | |||
78 | } | 77 | } |
79 | 78 | ||
80 | pub(super) fn new( | 79 | pub(super) fn new( |
81 | db: &impl DescriptorDatabase, | 80 | db: &impl HirDatabase, |
82 | source_root_id: SourceRootId, | 81 | source_root_id: SourceRootId, |
83 | module_id: ModuleId, | 82 | module_id: ModuleId, |
84 | ) -> Cancelable<ModuleDescriptor> { | 83 | ) -> Cancelable<Module> { |
85 | let module_tree = db._module_tree(source_root_id)?; | 84 | let module_tree = db.module_tree(source_root_id)?; |
86 | let res = ModuleDescriptor { | 85 | let res = Module { |
87 | tree: module_tree, | 86 | tree: module_tree, |
88 | source_root_id, | 87 | source_root_id, |
89 | module_id, | 88 | module_id, |
@@ -93,10 +92,7 @@ impl ModuleDescriptor { | |||
93 | 92 | ||
94 | /// Returns `mod foo;` or `mod foo {}` node whihc declared this module. | 93 | /// Returns `mod foo;` or `mod foo {}` node whihc declared this module. |
95 | /// Returns `None` for the root module | 94 | /// Returns `None` for the root module |
96 | pub fn parent_link_source( | 95 | pub fn parent_link_source(&self, db: &impl HirDatabase) -> Option<(FileId, ast::ModuleNode)> { |
97 | &self, | ||
98 | db: &impl DescriptorDatabase, | ||
99 | ) -> Option<(FileId, ast::ModuleNode)> { | ||
100 | let link = self.module_id.parent_link(&self.tree)?; | 96 | let link = self.module_id.parent_link(&self.tree)?; |
101 | let file_id = link.owner(&self.tree).source(&self.tree).file_id(); | 97 | let file_id = link.owner(&self.tree).source(&self.tree).file_id(); |
102 | let src = link.bind_source(&self.tree, db); | 98 | let src = link.bind_source(&self.tree, db); |
@@ -108,18 +104,18 @@ impl ModuleDescriptor { | |||
108 | } | 104 | } |
109 | 105 | ||
110 | /// Parent module. Returns `None` if this is a root module. | 106 | /// Parent module. Returns `None` if this is a root module. |
111 | pub fn parent(&self) -> Option<ModuleDescriptor> { | 107 | pub fn parent(&self) -> Option<Module> { |
112 | let parent_id = self.module_id.parent(&self.tree)?; | 108 | let parent_id = self.module_id.parent(&self.tree)?; |
113 | Some(ModuleDescriptor { | 109 | Some(Module { |
114 | module_id: parent_id, | 110 | module_id: parent_id, |
115 | ..self.clone() | 111 | ..self.clone() |
116 | }) | 112 | }) |
117 | } | 113 | } |
118 | 114 | ||
119 | /// The root of the tree this module is part of | 115 | /// The root of the tree this module is part of |
120 | pub fn crate_root(&self) -> ModuleDescriptor { | 116 | pub fn crate_root(&self) -> Module { |
121 | let root_id = self.module_id.crate_root(&self.tree); | 117 | let root_id = self.module_id.crate_root(&self.tree); |
122 | ModuleDescriptor { | 118 | Module { |
123 | module_id: root_id, | 119 | module_id: root_id, |
124 | ..self.clone() | 120 | ..self.clone() |
125 | } | 121 | } |
@@ -132,35 +128,31 @@ impl ModuleDescriptor { | |||
132 | Some(link.name(&self.tree)) | 128 | Some(link.name(&self.tree)) |
133 | } | 129 | } |
134 | 130 | ||
135 | pub fn def_id(&self, db: &impl DescriptorDatabase) -> DefId { | 131 | pub fn def_id(&self, db: &impl HirDatabase) -> DefId { |
136 | let def_loc = DefLoc::Module { | 132 | let def_loc = DefLoc::Module { |
137 | id: self.module_id, | 133 | id: self.module_id, |
138 | source_root: self.source_root_id, | 134 | source_root: self.source_root_id, |
139 | }; | 135 | }; |
140 | db.id_maps().def_id(def_loc) | 136 | def_loc.id(db) |
141 | } | 137 | } |
142 | 138 | ||
143 | /// Finds a child module with the specified name. | 139 | /// Finds a child module with the specified name. |
144 | pub fn child(&self, name: &str) -> Option<ModuleDescriptor> { | 140 | pub fn child(&self, name: &str) -> Option<Module> { |
145 | let child_id = self.module_id.child(&self.tree, name)?; | 141 | let child_id = self.module_id.child(&self.tree, name)?; |
146 | Some(ModuleDescriptor { | 142 | Some(Module { |
147 | module_id: child_id, | 143 | module_id: child_id, |
148 | ..self.clone() | 144 | ..self.clone() |
149 | }) | 145 | }) |
150 | } | 146 | } |
151 | 147 | ||
152 | /// Returns a `ModuleScope`: a set of items, visible in this module. | 148 | /// Returns a `ModuleScope`: a set of items, visible in this module. |
153 | pub(crate) fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable<ModuleScope> { | 149 | pub fn scope(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> { |
154 | let item_map = db._item_map(self.source_root_id)?; | 150 | let item_map = db.item_map(self.source_root_id)?; |
155 | let res = item_map.per_module[&self.module_id].clone(); | 151 | let res = item_map.per_module[&self.module_id].clone(); |
156 | Ok(res) | 152 | Ok(res) |
157 | } | 153 | } |
158 | 154 | ||
159 | pub(crate) fn resolve_path( | 155 | pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<Option<DefId>> { |
160 | &self, | ||
161 | db: &impl DescriptorDatabase, | ||
162 | path: Path, | ||
163 | ) -> Cancelable<Option<DefId>> { | ||
164 | let mut curr = match path.kind { | 156 | let mut curr = match path.kind { |
165 | PathKind::Crate => self.crate_root(), | 157 | PathKind::Crate => self.crate_root(), |
166 | PathKind::Self_ | PathKind::Plain => self.clone(), | 158 | PathKind::Self_ | PathKind::Plain => self.clone(), |
@@ -170,8 +162,8 @@ impl ModuleDescriptor { | |||
170 | 162 | ||
171 | let segments = path.segments; | 163 | let segments = path.segments; |
172 | for name in segments.iter() { | 164 | for name in segments.iter() { |
173 | let module = match db.id_maps().def_loc(curr) { | 165 | let module = match curr.loc(db) { |
174 | DefLoc::Module { id, source_root } => ModuleDescriptor::new(db, source_root, id)?, | 166 | DefLoc::Module { id, source_root } => Module::new(db, source_root, id)?, |
175 | _ => return Ok(None), | 167 | _ => return Ok(None), |
176 | }; | 168 | }; |
177 | let scope = module.scope(db)?; | 169 | let scope = module.scope(db)?; |
@@ -180,7 +172,7 @@ impl ModuleDescriptor { | |||
180 | Ok(Some(curr)) | 172 | Ok(Some(curr)) |
181 | } | 173 | } |
182 | 174 | ||
183 | pub fn problems(&self, db: &impl DescriptorDatabase) -> Vec<(SyntaxNode, Problem)> { | 175 | pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> { |
184 | self.module_id.problems(&self.tree, db) | 176 | self.module_id.problems(&self.tree, db) |
185 | } | 177 | } |
186 | } | 178 | } |
@@ -193,13 +185,13 @@ impl ModuleDescriptor { | |||
193 | /// (which can have multiple parents) to the precise world of modules (which | 185 | /// (which can have multiple parents) to the precise world of modules (which |
194 | /// always have one parent). | 186 | /// always have one parent). |
195 | #[derive(Default, Debug, PartialEq, Eq)] | 187 | #[derive(Default, Debug, PartialEq, Eq)] |
196 | pub(crate) struct ModuleTree { | 188 | pub struct ModuleTree { |
197 | mods: Arena<ModuleData>, | 189 | mods: Arena<ModuleData>, |
198 | links: Arena<LinkData>, | 190 | links: Arena<LinkData>, |
199 | } | 191 | } |
200 | 192 | ||
201 | impl ModuleTree { | 193 | impl ModuleTree { |
202 | fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a { | 194 | pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a { |
203 | self.mods.iter().map(|(id, _)| id) | 195 | self.mods.iter().map(|(id, _)| id) |
204 | } | 196 | } |
205 | 197 | ||
@@ -219,20 +211,19 @@ impl ModuleTree { | |||
219 | /// `ModuleSource` is the syntax tree element that produced this module: | 211 | /// `ModuleSource` is the syntax tree element that produced this module: |
220 | /// either a file, or an inlinde module. | 212 | /// either a file, or an inlinde module. |
221 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 213 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
222 | pub(crate) enum ModuleSource { | 214 | pub enum ModuleSource { |
223 | SourceFile(FileId), | 215 | SourceFile(FileId), |
224 | #[allow(dead_code)] | 216 | Module(SourceItemId), |
225 | Module(SyntaxPtr), | ||
226 | } | 217 | } |
227 | 218 | ||
228 | /// An owned syntax node for a module. Unlike `ModuleSource`, | 219 | /// An owned syntax node for a module. Unlike `ModuleSource`, |
229 | /// this holds onto the AST for the whole file. | 220 | /// this holds onto the AST for the whole file. |
230 | enum ModuleSourceNode { | 221 | pub enum ModuleSourceNode { |
231 | SourceFile(ast::SourceFileNode), | 222 | SourceFile(ast::SourceFileNode), |
232 | Module(ast::ModuleNode), | 223 | Module(ast::ModuleNode), |
233 | } | 224 | } |
234 | 225 | ||
235 | pub(crate) type ModuleId = Id<ModuleData>; | 226 | pub type ModuleId = Id<ModuleData>; |
236 | type LinkId = Id<LinkData>; | 227 | type LinkId = Id<LinkData>; |
237 | 228 | ||
238 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 229 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
@@ -247,7 +238,7 @@ pub enum Problem { | |||
247 | } | 238 | } |
248 | 239 | ||
249 | impl ModuleId { | 240 | impl ModuleId { |
250 | fn source(self, tree: &ModuleTree) -> ModuleSource { | 241 | pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource { |
251 | tree.mods[self].source | 242 | tree.mods[self].source |
252 | } | 243 | } |
253 | fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { | 244 | fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { |
@@ -277,7 +268,7 @@ impl ModuleId { | |||
277 | Some((link.name.clone(), module)) | 268 | Some((link.name.clone(), module)) |
278 | }) | 269 | }) |
279 | } | 270 | } |
280 | fn problems(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> Vec<(SyntaxNode, Problem)> { | 271 | fn problems(self, tree: &ModuleTree, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> { |
281 | tree.mods[self] | 272 | tree.mods[self] |
282 | .children | 273 | .children |
283 | .iter() | 274 | .iter() |
@@ -298,7 +289,7 @@ impl LinkId { | |||
298 | fn name(self, tree: &ModuleTree) -> SmolStr { | 289 | fn name(self, tree: &ModuleTree) -> SmolStr { |
299 | tree.links[self].name.clone() | 290 | tree.links[self].name.clone() |
300 | } | 291 | } |
301 | fn bind_source<'a>(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> ast::ModuleNode { | 292 | fn bind_source<'a>(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode { |
302 | let owner = self.owner(tree); | 293 | let owner = self.owner(tree); |
303 | match owner.source(tree).resolve(db) { | 294 | match owner.source(tree).resolve(db) { |
304 | ModuleSourceNode::SourceFile(root) => { | 295 | ModuleSourceNode::SourceFile(root) => { |
@@ -314,41 +305,47 @@ impl LinkId { | |||
314 | } | 305 | } |
315 | 306 | ||
316 | #[derive(Debug, PartialEq, Eq, Hash)] | 307 | #[derive(Debug, PartialEq, Eq, Hash)] |
317 | pub(crate) struct ModuleData { | 308 | pub struct ModuleData { |
318 | source: ModuleSource, | 309 | source: ModuleSource, |
319 | parent: Option<LinkId>, | 310 | parent: Option<LinkId>, |
320 | children: Vec<LinkId>, | 311 | children: Vec<LinkId>, |
321 | } | 312 | } |
322 | 313 | ||
323 | impl ModuleSource { | 314 | impl ModuleSource { |
324 | fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { | 315 | pub(crate) fn new_inline( |
316 | db: &impl HirDatabase, | ||
317 | file_id: FileId, | ||
318 | module: ast::Module, | ||
319 | ) -> ModuleSource { | ||
325 | assert!(!module.has_semi()); | 320 | assert!(!module.has_semi()); |
326 | let ptr = SyntaxPtr::new(file_id, module.syntax()); | 321 | let items = db.file_items(file_id); |
327 | ModuleSource::Module(ptr) | 322 | let item_id = items.id_of(module.syntax()); |
323 | let id = SourceItemId { file_id, item_id }; | ||
324 | ModuleSource::Module(id) | ||
328 | } | 325 | } |
329 | 326 | ||
330 | pub(crate) fn as_file(self) -> Option<FileId> { | 327 | pub fn as_file(self) -> Option<FileId> { |
331 | match self { | 328 | match self { |
332 | ModuleSource::SourceFile(f) => Some(f), | 329 | ModuleSource::SourceFile(f) => Some(f), |
333 | ModuleSource::Module(..) => None, | 330 | ModuleSource::Module(..) => None, |
334 | } | 331 | } |
335 | } | 332 | } |
336 | 333 | ||
337 | pub(crate) fn file_id(self) -> FileId { | 334 | pub fn file_id(self) -> FileId { |
338 | match self { | 335 | match self { |
339 | ModuleSource::SourceFile(f) => f, | 336 | ModuleSource::SourceFile(f) => f, |
340 | ModuleSource::Module(ptr) => ptr.file_id(), | 337 | ModuleSource::Module(source_item_id) => source_item_id.file_id, |
341 | } | 338 | } |
342 | } | 339 | } |
343 | 340 | ||
344 | fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode { | 341 | pub fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode { |
345 | match self { | 342 | match self { |
346 | ModuleSource::SourceFile(file_id) => { | 343 | ModuleSource::SourceFile(file_id) => { |
347 | let syntax = db.file_syntax(file_id); | 344 | let syntax = db.source_file(file_id); |
348 | ModuleSourceNode::SourceFile(syntax.ast().owned()) | 345 | ModuleSourceNode::SourceFile(syntax.ast().owned()) |
349 | } | 346 | } |
350 | ModuleSource::Module(ptr) => { | 347 | ModuleSource::Module(item_id) => { |
351 | let syntax = db.resolve_syntax_ptr(ptr); | 348 | let syntax = db.file_item(item_id); |
352 | let syntax = syntax.borrowed(); | 349 | let syntax = syntax.borrowed(); |
353 | let module = ast::Module::cast(syntax).unwrap(); | 350 | let module = ast::Module::cast(syntax).unwrap(); |
354 | ModuleSourceNode::Module(module.owned()) | 351 | ModuleSourceNode::Module(module.owned()) |
diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index d2964f67f..837a8d5ae 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -16,101 +16,42 @@ | |||
16 | //! structure itself is modified. | 16 | //! structure itself is modified. |
17 | use std::{ | 17 | use std::{ |
18 | sync::Arc, | 18 | sync::Arc, |
19 | time::Instant, | ||
20 | ops::Index, | ||
21 | }; | 19 | }; |
22 | 20 | ||
23 | use rustc_hash::FxHashMap; | 21 | use rustc_hash::FxHashMap; |
24 | |||
25 | use ra_syntax::{ | 22 | use ra_syntax::{ |
26 | SyntaxNode, SyntaxNodeRef, TextRange, | 23 | TextRange, |
27 | SmolStr, SyntaxKind::{self, *}, | 24 | SmolStr, SyntaxKind::{self, *}, |
28 | ast::{self, ModuleItemOwner, AstNode} | 25 | ast::{self, AstNode} |
29 | }; | 26 | }; |
27 | use ra_db::SourceRootId; | ||
30 | 28 | ||
31 | use crate::{ | 29 | use crate::{ |
32 | Cancelable, FileId, | 30 | Cancelable, FileId, |
33 | loc2id::{DefId, DefLoc}, | 31 | DefId, DefLoc, |
34 | descriptors::{ | 32 | SourceItemId, SourceFileItemId, SourceFileItems, |
35 | Path, PathKind, | 33 | Path, PathKind, |
36 | DescriptorDatabase, | 34 | HirDatabase, |
37 | module::{ModuleId, ModuleTree, ModuleSourceNode}, | 35 | module::{ModuleId, ModuleTree}, |
38 | }, | ||
39 | input::SourceRootId, | ||
40 | arena::{Arena, Id} | ||
41 | }; | 36 | }; |
42 | 37 | ||
43 | /// Identifier of item within a specific file. This is stable over reparses, so | ||
44 | /// it's OK to use it as a salsa key/value. | ||
45 | pub(crate) type FileItemId = Id<SyntaxNode>; | ||
46 | |||
47 | /// Maps item's `SyntaxNode`s to `FileItemId` and back. | ||
48 | #[derive(Debug, PartialEq, Eq, Default)] | ||
49 | pub(crate) struct FileItems { | ||
50 | arena: Arena<SyntaxNode>, | ||
51 | } | ||
52 | |||
53 | impl FileItems { | ||
54 | fn alloc(&mut self, item: SyntaxNode) -> FileItemId { | ||
55 | self.arena.alloc(item) | ||
56 | } | ||
57 | fn id_of(&self, item: SyntaxNodeRef) -> FileItemId { | ||
58 | let (id, _item) = self | ||
59 | .arena | ||
60 | .iter() | ||
61 | .find(|(_id, i)| i.borrowed() == item) | ||
62 | .unwrap(); | ||
63 | id | ||
64 | } | ||
65 | } | ||
66 | |||
67 | impl Index<FileItemId> for FileItems { | ||
68 | type Output = SyntaxNode; | ||
69 | fn index(&self, idx: FileItemId) -> &SyntaxNode { | ||
70 | &self.arena[idx] | ||
71 | } | ||
72 | } | ||
73 | |||
74 | pub(crate) fn file_items(db: &impl DescriptorDatabase, file_id: FileId) -> Arc<FileItems> { | ||
75 | let source_file = db.file_syntax(file_id); | ||
76 | let source_file = source_file.borrowed(); | ||
77 | let mut res = FileItems::default(); | ||
78 | source_file | ||
79 | .syntax() | ||
80 | .descendants() | ||
81 | .filter_map(ast::ModuleItem::cast) | ||
82 | .map(|it| it.syntax().owned()) | ||
83 | .for_each(|it| { | ||
84 | res.alloc(it); | ||
85 | }); | ||
86 | Arc::new(res) | ||
87 | } | ||
88 | |||
89 | pub(crate) fn file_item( | ||
90 | db: &impl DescriptorDatabase, | ||
91 | file_id: FileId, | ||
92 | file_item_id: FileItemId, | ||
93 | ) -> SyntaxNode { | ||
94 | db._file_items(file_id)[file_item_id].clone() | ||
95 | } | ||
96 | |||
97 | /// Item map is the result of the name resolution. Item map contains, for each | 38 | /// Item map is the result of the name resolution. Item map contains, for each |
98 | /// module, the set of visible items. | 39 | /// module, the set of visible items. |
99 | #[derive(Default, Debug, PartialEq, Eq)] | 40 | #[derive(Default, Debug, PartialEq, Eq)] |
100 | pub(crate) struct ItemMap { | 41 | pub struct ItemMap { |
101 | pub(crate) per_module: FxHashMap<ModuleId, ModuleScope>, | 42 | pub per_module: FxHashMap<ModuleId, ModuleScope>, |
102 | } | 43 | } |
103 | 44 | ||
104 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 45 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
105 | pub(crate) struct ModuleScope { | 46 | pub struct ModuleScope { |
106 | items: FxHashMap<SmolStr, Resolution>, | 47 | pub items: FxHashMap<SmolStr, Resolution>, |
107 | } | 48 | } |
108 | 49 | ||
109 | impl ModuleScope { | 50 | impl ModuleScope { |
110 | pub(crate) fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &Resolution)> + 'a { | 51 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &Resolution)> + 'a { |
111 | self.items.iter() | 52 | self.items.iter() |
112 | } | 53 | } |
113 | pub(crate) fn get(&self, name: &SmolStr) -> Option<&Resolution> { | 54 | pub fn get(&self, name: &SmolStr) -> Option<&Resolution> { |
114 | self.items.get(name) | 55 | self.items.get(name) |
115 | } | 56 | } |
116 | } | 57 | } |
@@ -122,14 +63,14 @@ impl ModuleScope { | |||
122 | /// recomputing name res: if `InputModuleItems` are the same, we can avoid | 63 | /// recomputing name res: if `InputModuleItems` are the same, we can avoid |
123 | /// running name resolution. | 64 | /// running name resolution. |
124 | #[derive(Debug, Default, PartialEq, Eq)] | 65 | #[derive(Debug, Default, PartialEq, Eq)] |
125 | pub(crate) struct InputModuleItems { | 66 | pub struct InputModuleItems { |
126 | items: Vec<ModuleItem>, | 67 | items: Vec<ModuleItem>, |
127 | imports: Vec<Import>, | 68 | imports: Vec<Import>, |
128 | } | 69 | } |
129 | 70 | ||
130 | #[derive(Debug, PartialEq, Eq)] | 71 | #[derive(Debug, PartialEq, Eq)] |
131 | struct ModuleItem { | 72 | struct ModuleItem { |
132 | id: FileItemId, | 73 | id: SourceFileItemId, |
133 | name: SmolStr, | 74 | name: SmolStr, |
134 | kind: SyntaxKind, | 75 | kind: SyntaxKind, |
135 | vis: Vis, | 76 | vis: Vis, |
@@ -148,14 +89,18 @@ struct Import { | |||
148 | } | 89 | } |
149 | 90 | ||
150 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 91 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
151 | pub(crate) struct NamedImport { | 92 | pub struct NamedImport { |
152 | file_item_id: FileItemId, | 93 | pub file_item_id: SourceFileItemId, |
153 | relative_range: TextRange, | 94 | pub relative_range: TextRange, |
154 | } | 95 | } |
155 | 96 | ||
156 | impl NamedImport { | 97 | impl NamedImport { |
157 | pub(crate) fn range(&self, db: &impl DescriptorDatabase, file_id: FileId) -> TextRange { | 98 | pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange { |
158 | let syntax = db._file_item(file_id, self.file_item_id); | 99 | let source_item_id = SourceItemId { |
100 | file_id, | ||
101 | item_id: self.file_item_id, | ||
102 | }; | ||
103 | let syntax = db.file_item(source_item_id); | ||
159 | let offset = syntax.borrowed().range().start(); | 104 | let offset = syntax.borrowed().range().start(); |
160 | self.relative_range + offset | 105 | self.relative_range + offset |
161 | } | 106 | } |
@@ -167,66 +112,14 @@ enum ImportKind { | |||
167 | Named(NamedImport), | 112 | Named(NamedImport), |
168 | } | 113 | } |
169 | 114 | ||
170 | pub(crate) fn input_module_items( | ||
171 | db: &impl DescriptorDatabase, | ||
172 | source_root: SourceRootId, | ||
173 | module_id: ModuleId, | ||
174 | ) -> Cancelable<Arc<InputModuleItems>> { | ||
175 | let module_tree = db._module_tree(source_root)?; | ||
176 | let source = module_id.source(&module_tree); | ||
177 | let file_items = db._file_items(source.file_id()); | ||
178 | let res = match source.resolve(db) { | ||
179 | ModuleSourceNode::SourceFile(it) => { | ||
180 | let items = it.borrowed().items(); | ||
181 | InputModuleItems::new(&file_items, items) | ||
182 | } | ||
183 | ModuleSourceNode::Module(it) => { | ||
184 | let items = it | ||
185 | .borrowed() | ||
186 | .item_list() | ||
187 | .into_iter() | ||
188 | .flat_map(|it| it.items()); | ||
189 | InputModuleItems::new(&file_items, items) | ||
190 | } | ||
191 | }; | ||
192 | Ok(Arc::new(res)) | ||
193 | } | ||
194 | |||
195 | pub(crate) fn item_map( | ||
196 | db: &impl DescriptorDatabase, | ||
197 | source_root: SourceRootId, | ||
198 | ) -> Cancelable<Arc<ItemMap>> { | ||
199 | let start = Instant::now(); | ||
200 | let module_tree = db._module_tree(source_root)?; | ||
201 | let input = module_tree | ||
202 | .modules() | ||
203 | .map(|id| { | ||
204 | let items = db._input_module_items(source_root, id)?; | ||
205 | Ok((id, items)) | ||
206 | }) | ||
207 | .collect::<Cancelable<FxHashMap<_, _>>>()?; | ||
208 | let mut resolver = Resolver { | ||
209 | db: db, | ||
210 | input: &input, | ||
211 | source_root, | ||
212 | module_tree, | ||
213 | result: ItemMap::default(), | ||
214 | }; | ||
215 | resolver.resolve()?; | ||
216 | let res = resolver.result; | ||
217 | let elapsed = start.elapsed(); | ||
218 | log::info!("item_map: {:?}", elapsed); | ||
219 | Ok(Arc::new(res)) | ||
220 | } | ||
221 | |||
222 | /// Resolution is basically `DefId` atm, but it should account for stuff like | 115 | /// Resolution is basically `DefId` atm, but it should account for stuff like |
223 | /// multiple namespaces, ambiguity and errors. | 116 | /// multiple namespaces, ambiguity and errors. |
224 | #[derive(Debug, Clone, PartialEq, Eq)] | 117 | #[derive(Debug, Clone, PartialEq, Eq)] |
225 | pub(crate) struct Resolution { | 118 | pub struct Resolution { |
226 | /// None for unresolved | 119 | /// None for unresolved |
227 | pub(crate) def_id: Option<DefId>, | 120 | pub def_id: Option<DefId>, |
228 | /// ident by whitch this is imported into local scope. | 121 | /// ident by whitch this is imported into local scope. |
229 | pub(crate) import: Option<NamedImport>, | 122 | pub import: Option<NamedImport>, |
230 | } | 123 | } |
231 | 124 | ||
232 | // #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | 125 | // #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
@@ -242,8 +135,8 @@ pub(crate) struct Resolution { | |||
242 | // } | 135 | // } |
243 | 136 | ||
244 | impl InputModuleItems { | 137 | impl InputModuleItems { |
245 | fn new<'a>( | 138 | pub(crate) fn new<'a>( |
246 | file_items: &FileItems, | 139 | file_items: &SourceFileItems, |
247 | items: impl Iterator<Item = ast::ModuleItem<'a>>, | 140 | items: impl Iterator<Item = ast::ModuleItem<'a>>, |
248 | ) -> InputModuleItems { | 141 | ) -> InputModuleItems { |
249 | let mut res = InputModuleItems::default(); | 142 | let mut res = InputModuleItems::default(); |
@@ -253,7 +146,7 @@ impl InputModuleItems { | |||
253 | res | 146 | res |
254 | } | 147 | } |
255 | 148 | ||
256 | fn add_item(&mut self, file_items: &FileItems, item: ast::ModuleItem) -> Option<()> { | 149 | fn add_item(&mut self, file_items: &SourceFileItems, item: ast::ModuleItem) -> Option<()> { |
257 | match item { | 150 | match item { |
258 | ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(file_items, it)?), | 151 | ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
259 | ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(file_items, it)?), | 152 | ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
@@ -274,7 +167,7 @@ impl InputModuleItems { | |||
274 | Some(()) | 167 | Some(()) |
275 | } | 168 | } |
276 | 169 | ||
277 | fn add_use_item(&mut self, file_items: &FileItems, item: ast::UseItem) { | 170 | fn add_use_item(&mut self, file_items: &SourceFileItems, item: ast::UseItem) { |
278 | let file_item_id = file_items.id_of(item.syntax()); | 171 | let file_item_id = file_items.id_of(item.syntax()); |
279 | let start_offset = item.syntax().range().start(); | 172 | let start_offset = item.syntax().range().start(); |
280 | Path::expand_use_item(item, |path, range| { | 173 | Path::expand_use_item(item, |path, range| { |
@@ -291,7 +184,7 @@ impl InputModuleItems { | |||
291 | } | 184 | } |
292 | 185 | ||
293 | impl ModuleItem { | 186 | impl ModuleItem { |
294 | fn new<'a>(file_items: &FileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> { | 187 | fn new<'a>(file_items: &SourceFileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> { |
295 | let name = item.name()?.text(); | 188 | let name = item.name()?.text(); |
296 | let kind = item.syntax().kind(); | 189 | let kind = item.syntax().kind(); |
297 | let vis = Vis::Other; | 190 | let vis = Vis::Other; |
@@ -306,28 +199,28 @@ impl ModuleItem { | |||
306 | } | 199 | } |
307 | } | 200 | } |
308 | 201 | ||
309 | struct Resolver<'a, DB> { | 202 | pub(crate) struct Resolver<'a, DB> { |
310 | db: &'a DB, | 203 | pub db: &'a DB, |
311 | input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, | 204 | pub input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, |
312 | source_root: SourceRootId, | 205 | pub source_root: SourceRootId, |
313 | module_tree: Arc<ModuleTree>, | 206 | pub module_tree: Arc<ModuleTree>, |
314 | result: ItemMap, | 207 | pub result: ItemMap, |
315 | } | 208 | } |
316 | 209 | ||
317 | impl<'a, DB> Resolver<'a, DB> | 210 | impl<'a, DB> Resolver<'a, DB> |
318 | where | 211 | where |
319 | DB: DescriptorDatabase, | 212 | DB: HirDatabase, |
320 | { | 213 | { |
321 | fn resolve(&mut self) -> Cancelable<()> { | 214 | pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> { |
322 | for (&module_id, items) in self.input.iter() { | 215 | for (&module_id, items) in self.input.iter() { |
323 | self.populate_module(module_id, items) | 216 | self.populate_module(module_id, items) |
324 | } | 217 | } |
325 | 218 | ||
326 | for &module_id in self.input.keys() { | 219 | for &module_id in self.input.keys() { |
327 | crate::db::check_canceled(self.db)?; | 220 | self.db.check_canceled()?; |
328 | self.resolve_imports(module_id); | 221 | self.resolve_imports(module_id); |
329 | } | 222 | } |
330 | Ok(()) | 223 | Ok(self.result) |
331 | } | 224 | } |
332 | 225 | ||
333 | fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { | 226 | fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { |
@@ -355,10 +248,12 @@ where | |||
355 | continue; | 248 | continue; |
356 | } | 249 | } |
357 | let def_loc = DefLoc::Item { | 250 | let def_loc = DefLoc::Item { |
358 | file_id, | 251 | source_item_id: SourceItemId { |
359 | id: item.id, | 252 | file_id, |
253 | item_id: item.id, | ||
254 | }, | ||
360 | }; | 255 | }; |
361 | let def_id = self.db.id_maps().def_id(def_loc); | 256 | let def_id = def_loc.id(self.db); |
362 | let resolution = Resolution { | 257 | let resolution = Resolution { |
363 | def_id: Some(def_id), | 258 | def_id: Some(def_id), |
364 | import: None, | 259 | import: None, |
@@ -371,7 +266,7 @@ where | |||
371 | id: mod_id, | 266 | id: mod_id, |
372 | source_root: self.source_root, | 267 | source_root: self.source_root, |
373 | }; | 268 | }; |
374 | let def_id = self.db.id_maps().def_id(def_loc); | 269 | let def_id = def_loc.id(self.db); |
375 | let resolution = Resolution { | 270 | let resolution = Resolution { |
376 | def_id: Some(def_id), | 271 | def_id: Some(def_id), |
377 | import: None, | 272 | import: None, |
@@ -420,7 +315,7 @@ where | |||
420 | }; | 315 | }; |
421 | 316 | ||
422 | if !is_last { | 317 | if !is_last { |
423 | curr = match self.db.id_maps().def_loc(def_id) { | 318 | curr = match def_id.loc(self.db) { |
424 | DefLoc::Module { id, .. } => id, | 319 | DefLoc::Module { id, .. } => id, |
425 | _ => return, | 320 | _ => return, |
426 | } | 321 | } |
@@ -441,109 +336,3 @@ where | |||
441 | f(module_items) | 336 | f(module_items) |
442 | } | 337 | } |
443 | } | 338 | } |
444 | |||
445 | #[cfg(test)] | ||
446 | mod tests { | ||
447 | use crate::{ | ||
448 | AnalysisChange, | ||
449 | mock_analysis::{MockAnalysis, analysis_and_position}, | ||
450 | descriptors::{DescriptorDatabase, module::ModuleDescriptor}, | ||
451 | input::FilesDatabase, | ||
452 | }; | ||
453 | use super::*; | ||
454 | |||
455 | fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) { | ||
456 | let (analysis, pos) = analysis_and_position(fixture); | ||
457 | let db = analysis.imp.db; | ||
458 | let source_root = db.file_source_root(pos.file_id); | ||
459 | let descr = ModuleDescriptor::guess_from_position(&*db, pos) | ||
460 | .unwrap() | ||
461 | .unwrap(); | ||
462 | let module_id = descr.module_id; | ||
463 | (db._item_map(source_root).unwrap(), module_id) | ||
464 | } | ||
465 | |||
466 | #[test] | ||
467 | fn test_item_map() { | ||
468 | let (item_map, module_id) = item_map( | ||
469 | " | ||
470 | //- /lib.rs | ||
471 | mod foo; | ||
472 | |||
473 | use crate::foo::bar::Baz; | ||
474 | <|> | ||
475 | |||
476 | //- /foo/mod.rs | ||
477 | pub mod bar; | ||
478 | |||
479 | //- /foo/bar.rs | ||
480 | pub struct Baz; | ||
481 | ", | ||
482 | ); | ||
483 | let name = SmolStr::from("Baz"); | ||
484 | let resolution = &item_map.per_module[&module_id].items[&name]; | ||
485 | assert!(resolution.def_id.is_some()); | ||
486 | } | ||
487 | |||
488 | #[test] | ||
489 | fn typing_inside_a_function_should_not_invalidate_item_map() { | ||
490 | let mock_analysis = MockAnalysis::with_files( | ||
491 | " | ||
492 | //- /lib.rs | ||
493 | mod foo; | ||
494 | |||
495 | use crate::foo::bar::Baz; | ||
496 | |||
497 | fn foo() -> i32 { | ||
498 | 1 + 1 | ||
499 | } | ||
500 | //- /foo/mod.rs | ||
501 | pub mod bar; | ||
502 | |||
503 | //- /foo/bar.rs | ||
504 | pub struct Baz; | ||
505 | ", | ||
506 | ); | ||
507 | |||
508 | let file_id = mock_analysis.id_of("/lib.rs"); | ||
509 | let mut host = mock_analysis.analysis_host(); | ||
510 | |||
511 | let source_root = host.analysis().imp.db.file_source_root(file_id); | ||
512 | |||
513 | { | ||
514 | let db = host.analysis().imp.db; | ||
515 | let events = db.log_executed(|| { | ||
516 | db._item_map(source_root).unwrap(); | ||
517 | }); | ||
518 | assert!(format!("{:?}", events).contains("_item_map")) | ||
519 | } | ||
520 | |||
521 | let mut change = AnalysisChange::new(); | ||
522 | |||
523 | change.change_file( | ||
524 | file_id, | ||
525 | " | ||
526 | mod foo; | ||
527 | |||
528 | use crate::foo::bar::Baz; | ||
529 | |||
530 | fn foo() -> i32 { 92 } | ||
531 | " | ||
532 | .to_string(), | ||
533 | ); | ||
534 | |||
535 | host.apply_change(change); | ||
536 | |||
537 | { | ||
538 | let db = host.analysis().imp.db; | ||
539 | let events = db.log_executed(|| { | ||
540 | db._item_map(source_root).unwrap(); | ||
541 | }); | ||
542 | assert!( | ||
543 | !format!("{:?}", events).contains("_item_map"), | ||
544 | "{:#?}", | ||
545 | events | ||
546 | ) | ||
547 | } | ||
548 | } | ||
549 | } | ||
diff --git a/crates/ra_analysis/src/descriptors/path.rs b/crates/ra_hir/src/path.rs index 8279daf4b..4a2e427cd 100644 --- a/crates/ra_analysis/src/descriptors/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -1,13 +1,13 @@ | |||
1 | use ra_syntax::{SmolStr, ast, AstNode, TextRange}; | 1 | use ra_syntax::{SmolStr, ast, AstNode, TextRange}; |
2 | 2 | ||
3 | #[derive(Debug, Clone, PartialEq, Eq)] | 3 | #[derive(Debug, Clone, PartialEq, Eq)] |
4 | pub(crate) struct Path { | 4 | pub struct Path { |
5 | pub(crate) kind: PathKind, | 5 | pub kind: PathKind, |
6 | pub(crate) segments: Vec<SmolStr>, | 6 | pub segments: Vec<SmolStr>, |
7 | } | 7 | } |
8 | 8 | ||
9 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 9 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
10 | pub(crate) enum PathKind { | 10 | pub enum PathKind { |
11 | Plain, | 11 | Plain, |
12 | Self_, | 12 | Self_, |
13 | Super, | 13 | Super, |
@@ -16,14 +16,14 @@ pub(crate) enum PathKind { | |||
16 | 16 | ||
17 | impl Path { | 17 | impl Path { |
18 | /// Calls `cb` with all paths, represented by this use item. | 18 | /// Calls `cb` with all paths, represented by this use item. |
19 | pub(crate) fn expand_use_item(item: ast::UseItem, mut cb: impl FnMut(Path, Option<TextRange>)) { | 19 | pub fn expand_use_item(item: ast::UseItem, mut cb: impl FnMut(Path, Option<TextRange>)) { |
20 | if let Some(tree) = item.use_tree() { | 20 | if let Some(tree) = item.use_tree() { |
21 | expand_use_tree(None, tree, &mut cb); | 21 | expand_use_tree(None, tree, &mut cb); |
22 | } | 22 | } |
23 | } | 23 | } |
24 | 24 | ||
25 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 25 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
26 | pub(crate) fn from_ast(mut path: ast::Path) -> Option<Path> { | 26 | pub fn from_ast(mut path: ast::Path) -> Option<Path> { |
27 | let mut kind = PathKind::Plain; | 27 | let mut kind = PathKind::Plain; |
28 | let mut segments = Vec::new(); | 28 | let mut segments = Vec::new(); |
29 | loop { | 29 | loop { |
@@ -64,7 +64,7 @@ impl Path { | |||
64 | } | 64 | } |
65 | 65 | ||
66 | /// `true` is this path is a single identifier, like `foo` | 66 | /// `true` is this path is a single identifier, like `foo` |
67 | pub(crate) fn is_ident(&self) -> bool { | 67 | pub fn is_ident(&self) -> bool { |
68 | self.kind == PathKind::Plain && self.segments.len() == 1 | 68 | self.kind == PathKind::Plain && self.segments.len() == 1 |
69 | } | 69 | } |
70 | } | 70 | } |
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs new file mode 100644 index 000000000..6f602878c --- /dev/null +++ b/crates/ra_hir/src/query_definitions.rs | |||
@@ -0,0 +1,154 @@ | |||
1 | use std::{ | ||
2 | sync::Arc, | ||
3 | time::Instant, | ||
4 | }; | ||
5 | |||
6 | use rustc_hash::FxHashMap; | ||
7 | use ra_syntax::{ | ||
8 | AstNode, SyntaxNode, SmolStr, | ||
9 | ast::{self, FnDef, FnDefNode, NameOwner, ModuleItemOwner} | ||
10 | }; | ||
11 | use ra_db::{SourceRootId, FileId, Cancelable,}; | ||
12 | |||
13 | use crate::{ | ||
14 | FnId, | ||
15 | SourceFileItems, SourceItemId, | ||
16 | db::HirDatabase, | ||
17 | function::FnScopes, | ||
18 | module::{ | ||
19 | ModuleSource, ModuleSourceNode, ModuleId, | ||
20 | imp::Submodule, | ||
21 | nameres::{InputModuleItems, ItemMap, Resolver}, | ||
22 | }, | ||
23 | }; | ||
24 | |||
25 | /// Resolve `FnId` to the corresponding `SyntaxNode` | ||
26 | pub(super) fn fn_syntax(db: &impl HirDatabase, fn_id: FnId) -> FnDefNode { | ||
27 | let item_id = fn_id.loc(db); | ||
28 | let syntax = db.file_item(item_id); | ||
29 | FnDef::cast(syntax.borrowed()).unwrap().owned() | ||
30 | } | ||
31 | |||
32 | pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> { | ||
33 | let syntax = db.fn_syntax(fn_id); | ||
34 | let res = FnScopes::new(syntax.borrowed()); | ||
35 | Arc::new(res) | ||
36 | } | ||
37 | |||
38 | pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { | ||
39 | let source_file = db.source_file(file_id); | ||
40 | let source_file = source_file.borrowed(); | ||
41 | let mut res = SourceFileItems::default(); | ||
42 | source_file | ||
43 | .syntax() | ||
44 | .descendants() | ||
45 | .filter_map(ast::ModuleItem::cast) | ||
46 | .map(|it| it.syntax().owned()) | ||
47 | .for_each(|it| { | ||
48 | res.alloc(it); | ||
49 | }); | ||
50 | Arc::new(res) | ||
51 | } | ||
52 | |||
53 | pub(super) fn file_item(db: &impl HirDatabase, source_item_id: SourceItemId) -> SyntaxNode { | ||
54 | db.file_items(source_item_id.file_id)[source_item_id.item_id].clone() | ||
55 | } | ||
56 | |||
57 | pub(crate) fn submodules( | ||
58 | db: &impl HirDatabase, | ||
59 | source: ModuleSource, | ||
60 | ) -> Cancelable<Arc<Vec<Submodule>>> { | ||
61 | db.check_canceled()?; | ||
62 | let file_id = source.file_id(); | ||
63 | let submodules = match source.resolve(db) { | ||
64 | ModuleSourceNode::SourceFile(it) => collect_submodules(db, file_id, it.borrowed()), | ||
65 | ModuleSourceNode::Module(it) => it | ||
66 | .borrowed() | ||
67 | .item_list() | ||
68 | .map(|it| collect_submodules(db, file_id, it)) | ||
69 | .unwrap_or_else(Vec::new), | ||
70 | }; | ||
71 | return Ok(Arc::new(submodules)); | ||
72 | |||
73 | fn collect_submodules<'a>( | ||
74 | db: &impl HirDatabase, | ||
75 | file_id: FileId, | ||
76 | root: impl ast::ModuleItemOwner<'a>, | ||
77 | ) -> Vec<Submodule> { | ||
78 | modules(root) | ||
79 | .map(|(name, m)| { | ||
80 | if m.has_semi() { | ||
81 | Submodule::Declaration(name) | ||
82 | } else { | ||
83 | let src = ModuleSource::new_inline(db, file_id, m); | ||
84 | Submodule::Definition(name, src) | ||
85 | } | ||
86 | }) | ||
87 | .collect() | ||
88 | } | ||
89 | } | ||
90 | |||
91 | pub(crate) fn modules<'a>( | ||
92 | root: impl ast::ModuleItemOwner<'a>, | ||
93 | ) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> { | ||
94 | root.items() | ||
95 | .filter_map(|item| match item { | ||
96 | ast::ModuleItem::Module(m) => Some(m), | ||
97 | _ => None, | ||
98 | }) | ||
99 | .filter_map(|module| { | ||
100 | let name = module.name()?.text(); | ||
101 | Some((name, module)) | ||
102 | }) | ||
103 | } | ||
104 | |||
105 | pub(super) fn input_module_items( | ||
106 | db: &impl HirDatabase, | ||
107 | source_root: SourceRootId, | ||
108 | module_id: ModuleId, | ||
109 | ) -> Cancelable<Arc<InputModuleItems>> { | ||
110 | let module_tree = db.module_tree(source_root)?; | ||
111 | let source = module_id.source(&module_tree); | ||
112 | let file_items = db.file_items(source.file_id()); | ||
113 | let res = match source.resolve(db) { | ||
114 | ModuleSourceNode::SourceFile(it) => { | ||
115 | let items = it.borrowed().items(); | ||
116 | InputModuleItems::new(&file_items, items) | ||
117 | } | ||
118 | ModuleSourceNode::Module(it) => { | ||
119 | let items = it | ||
120 | .borrowed() | ||
121 | .item_list() | ||
122 | .into_iter() | ||
123 | .flat_map(|it| it.items()); | ||
124 | InputModuleItems::new(&file_items, items) | ||
125 | } | ||
126 | }; | ||
127 | Ok(Arc::new(res)) | ||
128 | } | ||
129 | |||
130 | pub(super) fn item_map( | ||
131 | db: &impl HirDatabase, | ||
132 | source_root: SourceRootId, | ||
133 | ) -> Cancelable<Arc<ItemMap>> { | ||
134 | let start = Instant::now(); | ||
135 | let module_tree = db.module_tree(source_root)?; | ||
136 | let input = module_tree | ||
137 | .modules() | ||
138 | .map(|id| { | ||
139 | let items = db.input_module_items(source_root, id)?; | ||
140 | Ok((id, items)) | ||
141 | }) | ||
142 | .collect::<Cancelable<FxHashMap<_, _>>>()?; | ||
143 | let resolver = Resolver { | ||
144 | db: db, | ||
145 | input: &input, | ||
146 | source_root, | ||
147 | module_tree, | ||
148 | result: ItemMap::default(), | ||
149 | }; | ||
150 | let res = resolver.resolve()?; | ||
151 | let elapsed = start.elapsed(); | ||
152 | log::info!("item_map: {:?}", elapsed); | ||
153 | Ok(Arc::new(res)) | ||
154 | } | ||
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 3e7670fcc..12faeb93a 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs | |||
@@ -140,7 +140,7 @@ impl ServerWorldState { | |||
140 | Ok(file_id) | 140 | Ok(file_id) |
141 | } | 141 | } |
142 | pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { | 142 | pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { |
143 | let mut crate_graph = CrateGraph::new(); | 143 | let mut crate_graph = CrateGraph::default(); |
144 | ws.iter() | 144 | ws.iter() |
145 | .flat_map(|ws| { | 145 | .flat_map(|ws| { |
146 | ws.packages() | 146 | ws.packages() |