aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-10-25 08:57:55 +0100
committerAleksey Kladov <[email protected]>2018-10-25 14:25:40 +0100
commitee4d904cfb1b604bc8627491e05980ac43cd59e3 (patch)
tree54d1b937de544b8f6a8f2821ad9599aa82192375 /crates/ra_analysis
parent2cb2074c4b7219b32993abdcc7084637c0123d49 (diff)
Store all the data in the Salsa Database
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/completion.rs5
-rw-r--r--crates/ra_analysis/src/db/input.rs83
-rw-r--r--crates/ra_analysis/src/db/mod.rs (renamed from crates/ra_analysis/src/db.rs)51
-rw-r--r--crates/ra_analysis/src/descriptors/module/imp.rs22
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs10
-rw-r--r--crates/ra_analysis/src/imp.rs179
-rw-r--r--crates/ra_analysis/src/lib.rs81
-rw-r--r--crates/ra_analysis/src/symbol_index.rs2
-rw-r--r--crates/ra_analysis/tests/tests.rs20
9 files changed, 281 insertions, 172 deletions
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs
index a0fd6828d..04bb82c18 100644
--- a/crates/ra_analysis/src/completion.rs
+++ b/crates/ra_analysis/src/completion.rs
@@ -6,13 +6,14 @@ use ra_syntax::{
6 6
7use crate::{ 7use crate::{
8 FileId, Cancelable, 8 FileId, Cancelable,
9 db::{self, SyntaxDatabase}, 9 db::{self, SyntaxDatabase, input::FilesDatabase},
10 descriptors::module::{ModulesDatabase, ModuleTree, ModuleId}, 10 descriptors::module::{ModulesDatabase, ModuleTree, ModuleId},
11}; 11};
12 12
13pub(crate) fn resolve_based_completion(db: &db::RootDatabase, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { 13pub(crate) fn resolve_based_completion(db: &db::RootDatabase, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
14 let source_root_id = db.file_source_root(file_id);
14 let file = db.file_syntax(file_id); 15 let file = db.file_syntax(file_id);
15 let module_tree = db.module_tree()?; 16 let module_tree = db.module_tree(source_root_id)?;
16 let file = { 17 let file = {
17 let edit = AtomEdit::insert(offset, "intellijRulezz".to_string()); 18 let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
18 file.reparse(&edit) 19 file.reparse(&edit)
diff --git a/crates/ra_analysis/src/db/input.rs b/crates/ra_analysis/src/db/input.rs
new file mode 100644
index 000000000..957d082f9
--- /dev/null
+++ b/crates/ra_analysis/src/db/input.rs
@@ -0,0 +1,83 @@
1use std::{
2 sync::Arc,
3 hash::{Hasher, Hash},
4};
5
6use salsa;
7use rustc_hash::FxHashSet;
8
9use crate::{FileId, FileResolverImp, CrateGraph, symbol_index::SymbolIndex};
10
11salsa::query_group! {
12 pub(crate) trait FilesDatabase: salsa::Database {
13 fn file_text(file_id: FileId) -> Arc<String> {
14 type FileTextQuery;
15 storage input;
16 }
17 fn file_source_root(file_id: FileId) -> SourceRootId {
18 type FileSourceRootQuery;
19 storage input;
20 }
21 fn source_root(id: SourceRootId) -> Arc<SourceRoot> {
22 type SourceRootQuery;
23 storage input;
24 }
25 fn libraries() -> Arc<Vec<SourceRootId>> {
26 type LibrarieseQuery;
27 storage input;
28 }
29 fn library_symbols(id: SourceRootId) -> Arc<SymbolIndex> {
30 type LibrarySymbolsQuery;
31 storage input;
32 }
33 fn crate_graph() -> Arc<CrateGraph> {
34 type CrateGraphQuery;
35 storage input;
36 }
37 }
38}
39
40#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
41pub(crate) struct SourceRootId(pub(crate) u32);
42
43#[derive(Clone, Default, Debug, Eq)]
44pub(crate) struct SourceRoot {
45 pub(crate) file_resolver: FileResolverImp,
46 pub(crate) files: FxHashSet<FileId>,
47}
48
49impl PartialEq for SourceRoot {
50 fn eq(&self, other: &SourceRoot) -> bool {
51 self.file_resolver == other.file_resolver
52 }
53}
54
55impl Hash for SourceRoot {
56 fn hash<H: Hasher>(&self, hasher: &mut H) {
57 self.file_resolver.hash(hasher);
58 }
59}
60
61pub(crate) const WORKSPACE: SourceRootId = SourceRootId(0);
62
63
64#[derive(Default, Debug, Eq)]
65pub(crate) struct FileSet {
66 pub(crate) files: FxHashSet<FileId>,
67 pub(crate) resolver: FileResolverImp,
68}
69
70impl PartialEq for FileSet {
71 fn eq(&self, other: &FileSet) -> bool {
72 self.files == other.files && self.resolver == other.resolver
73 }
74}
75
76impl Hash for FileSet {
77 fn hash<H: Hasher>(&self, hasher: &mut H) {
78 let mut files = self.files.iter().cloned().collect::<Vec<_>>();
79 files.sort();
80 files.hash(hasher);
81 }
82}
83
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db/mod.rs
index b527cde61..8387118ad 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db/mod.rs
@@ -1,12 +1,12 @@
1pub(crate) mod input;
2
1use std::{ 3use std::{
2 fmt, 4 fmt,
3 hash::{Hash, Hasher},
4 sync::Arc, 5 sync::Arc,
5}; 6};
6 7
7use ra_editor::LineIndex; 8use ra_editor::LineIndex;
8use ra_syntax::File; 9use ra_syntax::File;
9use rustc_hash::FxHashSet;
10use salsa; 10use salsa;
11 11
12use crate::{ 12use crate::{
@@ -14,7 +14,7 @@ use crate::{
14 Cancelable, Canceled, 14 Cancelable, Canceled,
15 descriptors::module::{SubmodulesQuery, ModuleTreeQuery, ModulesDatabase}, 15 descriptors::module::{SubmodulesQuery, ModuleTreeQuery, ModulesDatabase},
16 symbol_index::SymbolIndex, 16 symbol_index::SymbolIndex,
17 FileId, FileResolverImp, 17 FileId,
18}; 18};
19 19
20#[derive(Default)] 20#[derive(Default)]
@@ -58,9 +58,13 @@ impl Clone for RootDatabase {
58 58
59salsa::database_storage! { 59salsa::database_storage! {
60 pub(crate) struct RootDatabaseStorage for RootDatabase { 60 pub(crate) struct RootDatabaseStorage for RootDatabase {
61 impl FilesDatabase { 61 impl input::FilesDatabase {
62 fn file_text() for FileTextQuery; 62 fn file_text() for input::FileTextQuery;
63 fn file_set() for FileSetQuery; 63 fn file_source_root() for input::FileSourceRootQuery;
64 fn source_root() for input::SourceRootQuery;
65 fn libraries() for input::LibrarieseQuery;
66 fn library_symbols() for input::LibrarySymbolsQuery;
67 fn crate_graph() for input::CrateGraphQuery;
64 } 68 }
65 impl SyntaxDatabase { 69 impl SyntaxDatabase {
66 fn file_syntax() for FileSyntaxQuery; 70 fn file_syntax() for FileSyntaxQuery;
@@ -75,40 +79,7 @@ salsa::database_storage! {
75} 79}
76 80
77salsa::query_group! { 81salsa::query_group! {
78 pub(crate) trait FilesDatabase: salsa::Database { 82 pub(crate) trait SyntaxDatabase: input::FilesDatabase {
79 fn file_text(file_id: FileId) -> Arc<String> {
80 type FileTextQuery;
81 storage input;
82 }
83 fn file_set() -> Arc<FileSet> {
84 type FileSetQuery;
85 storage input;
86 }
87 }
88}
89
90#[derive(Default, Debug, Eq)]
91pub(crate) struct FileSet {
92 pub(crate) files: FxHashSet<FileId>,
93 pub(crate) resolver: FileResolverImp,
94}
95
96impl PartialEq for FileSet {
97 fn eq(&self, other: &FileSet) -> bool {
98 self.files == other.files && self.resolver == other.resolver
99 }
100}
101
102impl Hash for FileSet {
103 fn hash<H: Hasher>(&self, hasher: &mut H) {
104 let mut files = self.files.iter().cloned().collect::<Vec<_>>();
105 files.sort();
106 files.hash(hasher);
107 }
108}
109
110salsa::query_group! {
111 pub(crate) trait SyntaxDatabase: FilesDatabase {
112 fn file_syntax(file_id: FileId) -> File { 83 fn file_syntax(file_id: FileId) -> File {
113 type FileSyntaxQuery; 84 type FileSyntaxQuery;
114 } 85 }
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs
index 22e4bd785..6a408dc89 100644
--- a/crates/ra_analysis/src/descriptors/module/imp.rs
+++ b/crates/ra_analysis/src/descriptors/module/imp.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9 9
10use crate::{ 10use crate::{
11 FileId, Cancelable, FileResolverImp, 11 FileId, Cancelable, FileResolverImp,
12 db, 12 db::{self, input::{SourceRoot, SourceRootId}},
13}; 13};
14 14
15use super::{ 15use super::{
@@ -35,9 +35,12 @@ pub(super) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast
35 }) 35 })
36} 36}
37 37
38pub(super) fn module_tree(db: &impl ModulesDatabase) -> Cancelable<Arc<ModuleTree>> { 38pub(super) fn module_tree(
39 db: &impl ModulesDatabase,
40 source_root: SourceRootId,
41) -> Cancelable<Arc<ModuleTree>> {
39 db::check_canceled(db)?; 42 db::check_canceled(db)?;
40 let res = create_module_tree(db)?; 43 let res = create_module_tree(db, source_root)?;
41 Ok(Arc::new(res)) 44 Ok(Arc::new(res))
42} 45}
43 46
@@ -50,6 +53,7 @@ pub struct Submodule {
50 53
51fn create_module_tree<'a>( 54fn create_module_tree<'a>(
52 db: &impl ModulesDatabase, 55 db: &impl ModulesDatabase,
56 source_root: SourceRootId,
53) -> Cancelable<ModuleTree> { 57) -> Cancelable<ModuleTree> {
54 let mut tree = ModuleTree { 58 let mut tree = ModuleTree {
55 mods: Vec::new(), 59 mods: Vec::new(),
@@ -59,12 +63,13 @@ fn create_module_tree<'a>(
59 let mut roots = FxHashMap::default(); 63 let mut roots = FxHashMap::default();
60 let mut visited = FxHashSet::default(); 64 let mut visited = FxHashSet::default();
61 65
62 for &file_id in db.file_set().files.iter() { 66 let source_root = db.source_root(source_root);
67 for &file_id in source_root.files.iter() {
63 if visited.contains(&file_id) { 68 if visited.contains(&file_id) {
64 continue; // TODO: use explicit crate_roots here 69 continue; // TODO: use explicit crate_roots here
65 } 70 }
66 assert!(!roots.contains_key(&file_id)); 71 assert!(!roots.contains_key(&file_id));
67 let module_id = build_subtree(db, &mut tree, &mut visited, &mut roots, None, file_id)?; 72 let module_id = build_subtree(db, &source_root, &mut tree, &mut visited, &mut roots, None, file_id)?;
68 roots.insert(file_id, module_id); 73 roots.insert(file_id, module_id);
69 } 74 }
70 Ok(tree) 75 Ok(tree)
@@ -72,6 +77,7 @@ fn create_module_tree<'a>(
72 77
73fn build_subtree( 78fn build_subtree(
74 db: &impl ModulesDatabase, 79 db: &impl ModulesDatabase,
80 source_root: &SourceRoot,
75 tree: &mut ModuleTree, 81 tree: &mut ModuleTree,
76 visited: &mut FxHashSet<FileId>, 82 visited: &mut FxHashSet<FileId>,
77 roots: &mut FxHashMap<FileId, ModuleId>, 83 roots: &mut FxHashMap<FileId, ModuleId>,
@@ -84,10 +90,8 @@ fn build_subtree(
84 parent, 90 parent,
85 children: Vec::new(), 91 children: Vec::new(),
86 }); 92 });
87 let file_set = db.file_set();
88 let file_resolver = &file_set.resolver;
89 for name in db.submodules(file_id)?.iter() { 93 for name in db.submodules(file_id)?.iter() {
90 let (points_to, problem) = resolve_submodule(file_id, name, file_resolver); 94 let (points_to, problem) = resolve_submodule(file_id, name, &source_root.file_resolver);
91 let link = tree.push_link(LinkData { 95 let link = tree.push_link(LinkData {
92 name: name.clone(), 96 name: name.clone(),
93 owner: id, 97 owner: id,
@@ -102,7 +106,7 @@ fn build_subtree(
102 tree.module_mut(module_id).parent = Some(link); 106 tree.module_mut(module_id).parent = Some(link);
103 Ok(module_id) 107 Ok(module_id)
104 } 108 }
105 None => build_subtree(db, tree, visited, roots, Some(link), file_id), 109 None => build_subtree(db, source_root, tree, visited, roots, Some(link), file_id),
106 }) 110 })
107 .collect::<Cancelable<Vec<_>>>()?; 111 .collect::<Cancelable<Vec<_>>>()?;
108 tree.link_mut(link).points_to = points_to; 112 tree.link_mut(link).points_to = points_to;
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs
index 52da650b3..98024cc15 100644
--- a/crates/ra_analysis/src/descriptors/module/mod.rs
+++ b/crates/ra_analysis/src/descriptors/module/mod.rs
@@ -7,12 +7,12 @@ use ra_syntax::{ast::{self, NameOwner, AstNode}, SmolStr, SyntaxNode};
7 7
8use crate::{ 8use crate::{
9 FileId, Cancelable, 9 FileId, Cancelable,
10 db::SyntaxDatabase, 10 db::{SyntaxDatabase, input::SourceRootId},
11}; 11};
12 12
13salsa::query_group! { 13salsa::query_group! {
14 pub(crate) trait ModulesDatabase: SyntaxDatabase { 14 pub(crate) trait ModulesDatabase: SyntaxDatabase {
15 fn module_tree() -> Cancelable<Arc<ModuleTree>> { 15 fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
16 type ModuleTreeQuery; 16 type ModuleTreeQuery;
17 use fn imp::module_tree; 17 use fn imp::module_tree;
18 } 18 }
@@ -110,15 +110,9 @@ impl ModuleId {
110} 110}
111 111
112impl LinkId { 112impl LinkId {
113 pub(crate) fn name(self, tree: &ModuleTree) -> SmolStr {
114 tree.link(self).name.clone()
115 }
116 pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { 113 pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
117 tree.link(self).owner 114 tree.link(self).owner
118 } 115 }
119 fn points_to(self, tree: &ModuleTree) -> &[ModuleId] {
120 &tree.link(self).points_to
121 }
122 pub(crate) fn bind_source<'a>( 116 pub(crate) fn bind_source<'a>(
123 self, 117 self,
124 tree: &ModuleTree, 118 tree: &ModuleTree,
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index f3e5b2887..97ed55465 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -1,7 +1,5 @@
1use std::{ 1use std::{
2 fmt,
3 hash::{Hash, Hasher}, 2 hash::{Hash, Hasher},
4 iter,
5 sync::Arc, 3 sync::Arc,
6}; 4};
7 5
@@ -14,12 +12,16 @@ use ra_syntax::{
14}; 12};
15use relative_path::RelativePath; 13use relative_path::RelativePath;
16use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15use salsa::{ParallelDatabase, Database};
17 16
18use crate::{ 17use crate::{
19 db::SyntaxDatabase, 18 AnalysisChange,
19 db::{
20 self, SyntaxDatabase,
21 input::{SourceRootId, FilesDatabase, SourceRoot, WORKSPACE}
22 },
20 descriptors::module::{ModulesDatabase, ModuleTree, Problem}, 23 descriptors::module::{ModulesDatabase, ModuleTree, Problem},
21 descriptors::{FnDescriptor}, 24 descriptors::{FnDescriptor},
22 roots::{ReadonlySourceRoot, SourceRoot, WritableSourceRoot},
23 CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position, 25 CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position,
24 Query, SourceChange, SourceFileEdit, Cancelable, 26 Query, SourceChange, SourceFileEdit, Cancelable,
25}; 27};
@@ -80,96 +82,123 @@ impl Default for FileResolverImp {
80 } 82 }
81} 83}
82 84
83#[derive(Debug)] 85#[derive(Debug, Default)]
84pub(crate) struct AnalysisHostImpl { 86pub(crate) struct AnalysisHostImpl {
85 data: WorldData, 87 db: db::RootDatabase,
86} 88}
87 89
90
88impl AnalysisHostImpl { 91impl AnalysisHostImpl {
89 pub fn new() -> AnalysisHostImpl { 92 pub fn new() -> AnalysisHostImpl {
90 AnalysisHostImpl { 93 AnalysisHostImpl::default()
91 data: WorldData::default(),
92 }
93 } 94 }
94 pub fn analysis(&self) -> AnalysisImpl { 95 pub fn analysis(&self) -> AnalysisImpl {
95 AnalysisImpl { 96 AnalysisImpl {
96 data: self.data.clone(), 97 db: self.db.fork() // freeze revision here
97 } 98 }
98 } 99 }
99 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item = (FileId, Option<String>)>) { 100 pub fn apply_change(&mut self, change: AnalysisChange) {
100 self.data_mut().root.apply_changes(changes, None); 101 for (file_id, text) in change.files_changed {
101 } 102 self.db
102 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { 103 .query(db::input::FileTextQuery)
103 self.data_mut() 104 .set(file_id, Arc::new(text))
104 .root 105 }
105 .apply_changes(&mut iter::empty(), Some(resolver)); 106 if !(change.files_added.is_empty() && change.files_removed.is_empty()) {
106 } 107 let file_resolver = change.file_resolver
107 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 108 .expect("change resolver when changing set of files");
108 let mut visited = FxHashSet::default(); 109 let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE));
109 for &file_id in graph.crate_roots.values() { 110 for (file_id, text) in change.files_added {
110 if !visited.insert(file_id) { 111 self.db
111 panic!("duplicate crate root: {:?}", file_id); 112 .query(db::input::FileTextQuery)
113 .set(file_id, Arc::new(text));
114 self.db
115 .query(db::input::FileSourceRootQuery)
116 .set(file_id, db::input::WORKSPACE);
117 source_root.files.insert(file_id);
118 }
119 for file_id in change.files_removed {
120 self.db
121 .query(db::input::FileTextQuery)
122 .set(file_id, Arc::new(String::new()));
123 source_root.files.remove(&file_id);
112 } 124 }
125 source_root.file_resolver = file_resolver;
126 self.db
127 .query(db::input::SourceRootQuery)
128 .set(WORKSPACE, Arc::new(source_root))
129 }
130 if !change.libraries_added.is_empty() {
131 let mut libraries = Vec::clone(&self.db.libraries());
132 for library in change.libraries_added {
133 let source_root_id = SourceRootId(1 + libraries.len() as u32);
134 libraries.push(source_root_id);
135 let mut files = FxHashSet::default();
136 for (file_id, text) in library.files {
137 files.insert(file_id);
138 self.db
139 .query(db::input::FileSourceRootQuery)
140 .set_constant(file_id, source_root_id);
141 self.db
142 .query(db::input::FileTextQuery)
143 .set_constant(file_id, Arc::new(text));
144 }
145 let source_root = SourceRoot {
146 files,
147 file_resolver: library.file_resolver,
148 };
149 self.db
150 .query(db::input::SourceRootQuery)
151 .set(source_root_id, Arc::new(source_root));
152 self.db
153 .query(db::input::LibrarySymbolsQuery)
154 .set(source_root_id, Arc::new(library.symbol_index));
155 }
156 self.db
157 .query(db::input::LibrarieseQuery)
158 .set((), Arc::new(libraries));
159 }
160 if let Some(crate_graph) = change.crate_graph {
161 self.db.query(db::input::CrateGraphQuery)
162 .set((), Arc::new(crate_graph))
113 } 163 }
114 self.data_mut().crate_graph = graph;
115 }
116 pub fn add_library(&mut self, root: ReadonlySourceRoot) {
117 self.data_mut().libs.push(root);
118 }
119 fn data_mut(&mut self) -> &mut WorldData {
120 &mut self.data
121 } 164 }
122} 165}
123 166
167#[derive(Debug)]
124pub(crate) struct AnalysisImpl { 168pub(crate) struct AnalysisImpl {
125 data: WorldData, 169 db: db::RootDatabase,
126}
127
128impl fmt::Debug for AnalysisImpl {
129 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
130 self.data.fmt(f)
131 }
132} 170}
133 171
134impl AnalysisImpl { 172impl AnalysisImpl {
135 fn root(&self, file_id: FileId) -> &SourceRoot {
136 if self.data.root.contains(file_id) {
137 return &self.data.root;
138 }
139 self
140 .data
141 .libs
142 .iter()
143 .find(|it| it.contains(file_id))
144 .unwrap()
145 }
146 pub fn file_syntax(&self, file_id: FileId) -> File { 173 pub fn file_syntax(&self, file_id: FileId) -> File {
147 self.root(file_id).db().file_syntax(file_id) 174 self.db.file_syntax(file_id)
148 } 175 }
149 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { 176 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> {
150 self.root(file_id).db().file_lines(file_id) 177 self.db.file_lines(file_id)
151 } 178 }
152 pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> { 179 pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> {
153 let mut buf = Vec::new(); 180 let mut buf = Vec::new();
154 if query.libs { 181 for &lib_id in self.db.libraries().iter() {
155 for lib in self.data.libs.iter() { 182 buf.push(self.db.library_symbols(lib_id));
156 lib.symbols(&mut buf)?; 183 }
157 } 184 for &file_id in self.db.source_root(WORKSPACE).files.iter() {
158 } else { 185 buf.push(self.db.file_symbols(file_id)?);
159 self.data.root.symbols(&mut buf)?;
160 } 186 }
161 Ok(query.search(&buf)) 187 Ok(query.search(&buf))
162 } 188 }
189 fn module_tree(&self, file_id: FileId) -> Cancelable<Arc<ModuleTree>> {
190 let source_root = self.db.file_source_root(file_id);
191 self.db.module_tree(source_root)
192 }
163 pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> { 193 pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> {
164 let root = self.root(file_id); 194 let module_tree = self.module_tree(file_id)?;
165 let module_tree = root.db().module_tree()?;
166 195
167 let res = module_tree.modules_for_file(file_id) 196 let res = module_tree.modules_for_file(file_id)
168 .into_iter() 197 .into_iter()
169 .filter_map(|module_id| { 198 .filter_map(|module_id| {
170 let link = module_id.parent_link(&module_tree)?; 199 let link = module_id.parent_link(&module_tree)?;
171 let file_id = link.owner(&module_tree).file_id(&module_tree); 200 let file_id = link.owner(&module_tree).file_id(&module_tree);
172 let syntax = root.db().file_syntax(file_id); 201 let syntax = self.db.file_syntax(file_id);
173 let decl = link.bind_source(&module_tree, syntax.ast()); 202 let decl = link.bind_source(&module_tree, syntax.ast());
174 203
175 let sym = FileSymbol { 204 let sym = FileSymbol {
@@ -183,8 +212,8 @@ impl AnalysisImpl {
183 Ok(res) 212 Ok(res)
184 } 213 }
185 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 214 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
186 let module_tree = self.root(file_id).db().module_tree()?; 215 let module_tree = self.module_tree(file_id)?;
187 let crate_graph = &self.data.crate_graph; 216 let crate_graph = self.db.crate_graph();
188 let res = module_tree.modules_for_file(file_id) 217 let res = module_tree.modules_for_file(file_id)
189 .into_iter() 218 .into_iter()
190 .map(|it| it.root(&module_tree)) 219 .map(|it| it.root(&module_tree))
@@ -195,7 +224,7 @@ impl AnalysisImpl {
195 Ok(res) 224 Ok(res)
196 } 225 }
197 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 226 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
198 self.data.crate_graph.crate_roots[&crate_id] 227 self.db.crate_graph().crate_roots[&crate_id]
199 } 228 }
200 pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { 229 pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
201 let mut res = Vec::new(); 230 let mut res = Vec::new();
@@ -205,8 +234,7 @@ impl AnalysisImpl {
205 res.extend(scope_based); 234 res.extend(scope_based);
206 has_completions = true; 235 has_completions = true;
207 } 236 }
208 let root = self.root(file_id); 237 if let Some(scope_based) = crate::completion::resolve_based_completion(&self.db, file_id, offset)? {
209 if let Some(scope_based) = crate::completion::resolve_based_completion(root.db(), file_id, offset)? {
210 res.extend(scope_based); 238 res.extend(scope_based);
211 has_completions = true; 239 has_completions = true;
212 } 240 }
@@ -222,9 +250,8 @@ impl AnalysisImpl {
222 file_id: FileId, 250 file_id: FileId,
223 offset: TextUnit, 251 offset: TextUnit,
224 ) -> Cancelable<Vec<(FileId, FileSymbol)>> { 252 ) -> Cancelable<Vec<(FileId, FileSymbol)>> {
225 let root = self.root(file_id); 253 let module_tree = self.module_tree(file_id)?;
226 let module_tree = root.db().module_tree()?; 254 let file = self.db.file_syntax(file_id);
227 let file = root.db().file_syntax(file_id);
228 let syntax = file.syntax(); 255 let syntax = file.syntax();
229 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { 256 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
230 // First try to resolve the symbol locally 257 // First try to resolve the symbol locally
@@ -273,8 +300,7 @@ impl AnalysisImpl {
273 } 300 }
274 301
275 pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit) -> Vec<(FileId, TextRange)> { 302 pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit) -> Vec<(FileId, TextRange)> {
276 let root = self.root(file_id); 303 let file = self.db.file_syntax(file_id);
277 let file = root.db().file_syntax(file_id);
278 let syntax = file.syntax(); 304 let syntax = file.syntax();
279 305
280 let mut ret = vec![]; 306 let mut ret = vec![];
@@ -305,9 +331,8 @@ impl AnalysisImpl {
305 } 331 }
306 332
307 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 333 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
308 let root = self.root(file_id); 334 let module_tree = self.module_tree(file_id)?;
309 let module_tree = root.db().module_tree()?; 335 let syntax = self.db.file_syntax(file_id);
310 let syntax = root.db().file_syntax(file_id);
311 336
312 let mut res = ra_editor::diagnostics(&syntax) 337 let mut res = ra_editor::diagnostics(&syntax)
313 .into_iter() 338 .into_iter()
@@ -396,8 +421,7 @@ impl AnalysisImpl {
396 file_id: FileId, 421 file_id: FileId,
397 offset: TextUnit, 422 offset: TextUnit,
398 ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { 423 ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> {
399 let root = self.root(file_id); 424 let file = self.db.file_syntax(file_id);
400 let file = root.db().file_syntax(file_id);
401 let syntax = file.syntax(); 425 let syntax = file.syntax();
402 426
403 // Find the calling expression and it's NameRef 427 // Find the calling expression and it's NameRef
@@ -491,13 +515,6 @@ impl AnalysisImpl {
491 } 515 }
492} 516}
493 517
494#[derive(Default, Clone, Debug)]
495struct WorldData {
496 crate_graph: CrateGraph,
497 root: WritableSourceRoot,
498 libs: Vec<ReadonlySourceRoot>,
499}
500
501impl SourceChange { 518impl SourceChange {
502 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange { 519 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange {
503 let file_edit = SourceFileEdit { 520 let file_edit = SourceFileEdit {
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 7078e2d31..4a1ae3b64 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -9,17 +9,23 @@ extern crate salsa;
9mod db; 9mod db;
10mod descriptors; 10mod descriptors;
11mod imp; 11mod imp;
12mod roots;
13mod symbol_index; 12mod symbol_index;
14mod completion; 13mod completion;
15 14
16use std::{fmt::Debug, sync::Arc}; 15use std::{
16 fmt::Debug,
17 sync::Arc,
18 collections::BTreeMap,
19};
17 20
18use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; 21use ra_syntax::{AtomEdit, File, TextRange, TextUnit};
19use relative_path::{RelativePath, RelativePathBuf}; 22use relative_path::{RelativePath, RelativePathBuf};
20use rustc_hash::FxHashMap; 23use rayon::prelude::*;
21 24
22use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}; 25use crate::{
26 imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp},
27 symbol_index::SymbolIndex,
28};
23 29
24pub use crate::{ 30pub use crate::{
25 descriptors::FnDescriptor, 31 descriptors::FnDescriptor,
@@ -49,9 +55,9 @@ pub struct FileId(pub u32);
49#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 55#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
50pub struct CrateId(pub u32); 56pub struct CrateId(pub u32);
51 57
52#[derive(Debug, Clone, Default)] 58#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
53pub struct CrateGraph { 59pub struct CrateGraph {
54 pub crate_roots: FxHashMap<CrateId, FileId>, 60 pub crate_roots: BTreeMap<CrateId, FileId>,
55} 61}
56 62
57pub trait FileResolver: Debug + Send + Sync + 'static { 63pub trait FileResolver: Debug + Send + Sync + 'static {
@@ -59,6 +65,41 @@ pub trait FileResolver: Debug + Send + Sync + 'static {
59 fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId>; 65 fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId>;
60} 66}
61 67
68#[derive(Debug, Default)]
69pub struct AnalysisChange {
70 files_added: Vec<(FileId, String)>,
71 files_changed: Vec<(FileId, String)>,
72 files_removed: Vec<(FileId)>,
73 libraries_added: Vec<LibraryData>,
74 crate_graph: Option<CrateGraph>,
75 file_resolver: Option<FileResolverImp>,
76}
77
78
79impl AnalysisChange {
80 pub fn new() -> AnalysisChange {
81 AnalysisChange::default()
82 }
83 pub fn add_file(&mut self, file_id: FileId, text: String) {
84 self.files_added.push((file_id, text))
85 }
86 pub fn change_file(&mut self, file_id: FileId, new_text: String) {
87 self.files_changed.push((file_id, new_text))
88 }
89 pub fn remove_file(&mut self, file_id: FileId) {
90 self.files_removed.push(file_id)
91 }
92 pub fn add_library(&mut self, data: LibraryData) {
93 self.libraries_added.push(data)
94 }
95 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
96 self.crate_graph = Some(graph);
97 }
98 pub fn set_file_resolver(&mut self, file_resolver: Arc<FileResolver>) {
99 self.file_resolver = Some(FileResolverImp::new(file_resolver));
100 }
101}
102
62#[derive(Debug)] 103#[derive(Debug)]
63pub struct AnalysisHost { 104pub struct AnalysisHost {
64 imp: AnalysisHostImpl, 105 imp: AnalysisHostImpl,
@@ -75,20 +116,8 @@ impl AnalysisHost {
75 imp: self.imp.analysis(), 116 imp: self.imp.analysis(),
76 } 117 }
77 } 118 }
78 pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { 119 pub fn apply_change(&mut self, change: AnalysisChange) {
79 self.change_files(::std::iter::once((file_id, text))); 120 self.imp.apply_change(change)
80 }
81 pub fn change_files(&mut self, mut changes: impl Iterator<Item = (FileId, Option<String>)>) {
82 self.imp.change_files(&mut changes)
83 }
84 pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) {
85 self.imp.set_file_resolver(FileResolverImp::new(resolver));
86 }
87 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
88 self.imp.set_crate_graph(graph)
89 }
90 pub fn add_library(&mut self, data: LibraryData) {
91 self.imp.add_library(data.root)
92 } 121 }
93} 122}
94 123
@@ -266,14 +295,18 @@ impl Analysis {
266 295
267#[derive(Debug)] 296#[derive(Debug)]
268pub struct LibraryData { 297pub struct LibraryData {
269 root: roots::ReadonlySourceRoot, 298 files: Vec<(FileId, String)>,
299 file_resolver: FileResolverImp,
300 symbol_index: SymbolIndex,
270} 301}
271 302
272impl LibraryData { 303impl LibraryData {
273 pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData { 304 pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData {
274 let file_resolver = FileResolverImp::new(file_resolver); 305 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, text)| {
275 let root = roots::ReadonlySourceRoot::new(files, file_resolver); 306 let file = File::parse(text);
276 LibraryData { root } 307 (*file_id, file)
308 }));
309 LibraryData { files, file_resolver: FileResolverImp::new(file_resolver), symbol_index }
277 } 310 }
278} 311}
279 312
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index e5c8d8870..5f302cbda 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -13,7 +13,7 @@ use rayon::prelude::*;
13 13
14use crate::{FileId, Query}; 14use crate::{FileId, Query};
15 15
16#[derive(Debug)] 16#[derive(Default, Debug)]
17pub(crate) struct SymbolIndex { 17pub(crate) struct SymbolIndex {
18 symbols: Vec<(FileId, FileSymbol)>, 18 symbols: Vec<(FileId, FileSymbol)>,
19 map: fst::Map, 19 map: fst::Map,
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index 52fae71ae..198d6a263 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -5,15 +5,17 @@ extern crate relative_path;
5extern crate rustc_hash; 5extern crate rustc_hash;
6extern crate test_utils; 6extern crate test_utils;
7 7
8use std::sync::Arc; 8use std::{
9 sync::Arc,
10 collections::BTreeMap,
11};
9 12
10use ra_syntax::TextRange; 13use ra_syntax::TextRange;
11use relative_path::{RelativePath, RelativePathBuf}; 14use relative_path::{RelativePath, RelativePathBuf};
12use rustc_hash::FxHashMap;
13use test_utils::{assert_eq_dbg, extract_offset}; 15use test_utils::{assert_eq_dbg, extract_offset};
14 16
15use ra_analysis::{ 17use ra_analysis::{
16 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, 18 AnalysisChange, Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor,
17}; 19};
18 20
19#[derive(Debug)] 21#[derive(Debug)]
@@ -45,14 +47,16 @@ impl FileResolver for FileMap {
45fn analysis_host(files: &[(&str, &str)]) -> AnalysisHost { 47fn analysis_host(files: &[(&str, &str)]) -> AnalysisHost {
46 let mut host = AnalysisHost::new(); 48 let mut host = AnalysisHost::new();
47 let mut file_map = Vec::new(); 49 let mut file_map = Vec::new();
50 let mut change = AnalysisChange::new();
48 for (id, &(path, contents)) in files.iter().enumerate() { 51 for (id, &(path, contents)) in files.iter().enumerate() {
49 let file_id = FileId((id + 1) as u32); 52 let file_id = FileId((id + 1) as u32);
50 assert!(path.starts_with('/')); 53 assert!(path.starts_with('/'));
51 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 54 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
52 host.change_file(file_id, Some(contents.to_string())); 55 change.add_file(file_id, contents.to_string());
53 file_map.push((file_id, path)); 56 file_map.push((file_id, path));
54 } 57 }
55 host.set_file_resolver(Arc::new(FileMap(file_map))); 58 change.set_file_resolver(Arc::new(FileMap(file_map)));
59 host.apply_change(change);
56 host 60 host
57} 61}
58 62
@@ -128,12 +132,14 @@ fn test_resolve_crate_root() {
128 132
129 let crate_graph = CrateGraph { 133 let crate_graph = CrateGraph {
130 crate_roots: { 134 crate_roots: {
131 let mut m = FxHashMap::default(); 135 let mut m = BTreeMap::default();
132 m.insert(CrateId(1), FileId(1)); 136 m.insert(CrateId(1), FileId(1));
133 m 137 m
134 }, 138 },
135 }; 139 };
136 host.set_crate_graph(crate_graph); 140 let mut change = AnalysisChange::new();
141 change.set_crate_graph(crate_graph);
142 host.apply_change(change);
137 let snap = host.analysis(); 143 let snap = host.analysis();
138 144
139 assert_eq!(snap.crate_for(FileId(2)).unwrap(), vec![CrateId(1)],); 145 assert_eq!(snap.crate_for(FileId(2)).unwrap(), vec![CrateId(1)],);