aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/db.rs10
-rw-r--r--crates/ra_analysis/src/imp.rs139
-rw-r--r--crates/ra_analysis/src/lib.rs104
-rw-r--r--crates/ra_analysis/src/mock_analysis.rs10
4 files changed, 164 insertions, 99 deletions
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index b8d774eb5..3d0f13f34 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -30,11 +30,11 @@ impl Default for RootDatabase {
30 runtime: salsa::Runtime::default(), 30 runtime: salsa::Runtime::default(),
31 id_maps: Default::default(), 31 id_maps: Default::default(),
32 }; 32 };
33 db.query_mut(ra_db::SourceRootQuery)
34 .set(ra_db::WORKSPACE, Default::default());
35 db.query_mut(ra_db::CrateGraphQuery) 33 db.query_mut(ra_db::CrateGraphQuery)
36 .set((), Default::default()); 34 .set((), Default::default());
37 db.query_mut(ra_db::LibrariesQuery) 35 db.query_mut(ra_db::LocalRootsQuery)
36 .set((), Default::default());
37 db.query_mut(ra_db::LibraryRootsQuery)
38 .set((), Default::default()); 38 .set((), Default::default());
39 db 39 db
40 } 40 }
@@ -61,9 +61,11 @@ salsa::database_storage! {
61 pub(crate) struct RootDatabaseStorage for RootDatabase { 61 pub(crate) struct RootDatabaseStorage for RootDatabase {
62 impl ra_db::FilesDatabase { 62 impl ra_db::FilesDatabase {
63 fn file_text() for ra_db::FileTextQuery; 63 fn file_text() for ra_db::FileTextQuery;
64 fn file_relative_path() for ra_db::FileRelativePathQuery;
64 fn file_source_root() for ra_db::FileSourceRootQuery; 65 fn file_source_root() for ra_db::FileSourceRootQuery;
65 fn source_root() for ra_db::SourceRootQuery; 66 fn source_root() for ra_db::SourceRootQuery;
66 fn libraries() for ra_db::LibrariesQuery; 67 fn local_roots() for ra_db::LocalRootsQuery;
68 fn library_roots() for ra_db::LibraryRootsQuery;
67 fn crate_graph() for ra_db::CrateGraphQuery; 69 fn crate_graph() for ra_db::CrateGraphQuery;
68 } 70 }
69 impl ra_db::SyntaxDatabase { 71 impl ra_db::SyntaxDatabase {
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 0de0e2645..c4291885a 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -10,9 +10,8 @@ use ra_syntax::{
10 SyntaxKind::*, 10 SyntaxKind::*,
11 SyntaxNodeRef, TextRange, TextUnit, 11 SyntaxNodeRef, TextRange, TextUnit,
12}; 12};
13use ra_db::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE, SyntaxDatabase}; 13use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
14use rayon::prelude::*; 14use rayon::prelude::*;
15use rustc_hash::FxHashSet;
16use salsa::{Database, ParallelDatabase}; 15use salsa::{Database, ParallelDatabase};
17use hir::{ 16use hir::{
18 self, 17 self,
@@ -24,8 +23,8 @@ use hir::{
24use crate::{ 23use crate::{
25 completion::{completions, CompletionItem}, 24 completion::{completions, CompletionItem},
26 db, 25 db,
27 symbol_index::{SymbolIndex, SymbolsDatabase}, 26 symbol_index::{SymbolIndex, SymbolsDatabase, LibrarySymbolsQuery},
28 AnalysisChange, Cancelable, CrateId, Diagnostic, FileId, 27 AnalysisChange, RootChange, Cancelable, CrateId, Diagnostic, FileId,
29 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, 28 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
30 ReferenceResolution, 29 ReferenceResolution,
31}; 30};
@@ -44,70 +43,41 @@ impl AnalysisHostImpl {
44 pub fn apply_change(&mut self, change: AnalysisChange) { 43 pub fn apply_change(&mut self, change: AnalysisChange) {
45 log::info!("apply_change {:?}", change); 44 log::info!("apply_change {:?}", change);
46 // self.gc_syntax_trees(); 45 // self.gc_syntax_trees();
47 46 if !change.new_roots.is_empty() {
48 for (file_id, text) in change.files_changed { 47 let mut local_roots = Vec::clone(&self.db.local_roots());
49 self.db 48 for (root_id, is_local) in change.new_roots {
50 .query_mut(ra_db::FileTextQuery)
51 .set(file_id, Arc::new(text))
52 }
53 if !(change.files_added.is_empty() && change.files_removed.is_empty()) {
54 let file_resolver = change
55 .file_resolver
56 .expect("change resolver when changing set of files");
57 let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE));
58 for (file_id, text) in change.files_added {
59 self.db 49 self.db
60 .query_mut(ra_db::FileTextQuery) 50 .query_mut(ra_db::SourceRootQuery)
61 .set(file_id, Arc::new(text)); 51 .set(root_id, Default::default());
62 self.db 52 if is_local {
63 .query_mut(ra_db::FileSourceRootQuery) 53 local_roots.push(root_id);
64 .set(file_id, ra_db::WORKSPACE); 54 }
65 source_root.files.insert(file_id);
66 }
67 for file_id in change.files_removed {
68 self.db
69 .query_mut(ra_db::FileTextQuery)
70 .set(file_id, Arc::new(String::new()));
71 source_root.files.remove(&file_id);
72 } 55 }
73 source_root.file_resolver = file_resolver;
74 self.db 56 self.db
75 .query_mut(ra_db::SourceRootQuery) 57 .query_mut(ra_db::LocalRootsQuery)
76 .set(WORKSPACE, Arc::new(source_root)) 58 .set((), Arc::new(local_roots));
59 }
60
61 for (root_id, root_change) in change.roots_changed {
62 self.apply_root_change(root_id, root_change);
63 }
64 for (file_id, text) in change.files_changed {
65 self.db.query_mut(ra_db::FileTextQuery).set(file_id, text)
77 } 66 }
78 if !change.libraries_added.is_empty() { 67 if !change.libraries_added.is_empty() {
79 let mut libraries = Vec::clone(&self.db.libraries()); 68 let mut libraries = Vec::clone(&self.db.library_roots());
80 for library in change.libraries_added { 69 for library in change.libraries_added {
81 let source_root_id = SourceRootId(1 + libraries.len() as u32); 70 libraries.push(library.root_id);
82 libraries.push(source_root_id);
83 let mut files = FxHashSet::default();
84 for (file_id, text) in library.files {
85 files.insert(file_id);
86 log::debug!(
87 "library file: {:?} {:?}",
88 file_id,
89 library.file_resolver.debug_path(file_id)
90 );
91 self.db
92 .query_mut(ra_db::FileSourceRootQuery)
93 .set_constant(file_id, source_root_id);
94 self.db
95 .query_mut(ra_db::FileTextQuery)
96 .set_constant(file_id, Arc::new(text));
97 }
98 let source_root = SourceRoot {
99 files,
100 file_resolver: library.file_resolver,
101 };
102 self.db 71 self.db
103 .query_mut(ra_db::SourceRootQuery) 72 .query_mut(ra_db::SourceRootQuery)
104 .set(source_root_id, Arc::new(source_root)); 73 .set(library.root_id, Default::default());
105 self.db 74 self.db
106 .query_mut(crate::symbol_index::LibrarySymbolsQuery) 75 .query_mut(LibrarySymbolsQuery)
107 .set(source_root_id, Arc::new(library.symbol_index)); 76 .set_constant(library.root_id, Arc::new(library.symbol_index));
77 self.apply_root_change(library.root_id, library.root_change);
108 } 78 }
109 self.db 79 self.db
110 .query_mut(ra_db::LibrariesQuery) 80 .query_mut(ra_db::LibraryRootsQuery)
111 .set((), Arc::new(libraries)); 81 .set((), Arc::new(libraries));
112 } 82 }
113 if let Some(crate_graph) = change.crate_graph { 83 if let Some(crate_graph) = change.crate_graph {
@@ -117,6 +87,34 @@ impl AnalysisHostImpl {
117 } 87 }
118 } 88 }
119 89
90 fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
91 let mut source_root = SourceRoot::clone(&self.db.source_root(root_id));
92 for add_file in root_change.added {
93 self.db
94 .query_mut(ra_db::FileTextQuery)
95 .set(add_file.file_id, add_file.text);
96 self.db
97 .query_mut(ra_db::FileRelativePathQuery)
98 .set(add_file.file_id, add_file.path.clone());
99 self.db
100 .query_mut(ra_db::FileSourceRootQuery)
101 .set(add_file.file_id, root_id);
102 source_root.files.insert(add_file.path, add_file.file_id);
103 }
104 for remove_file in root_change.removed {
105 self.db
106 .query_mut(ra_db::FileTextQuery)
107 .set(remove_file.file_id, Default::default());
108 self.db
109 .query_mut(ra_db::FileRelativePathQuery)
110 .set(remove_file.file_id, Default::default());
111 source_root.files.remove(&remove_file.path);
112 }
113 self.db
114 .query_mut(ra_db::SourceRootQuery)
115 .set(root_id, Arc::new(source_root));
116 }
117
120 #[allow(unused)] 118 #[allow(unused)]
121 /// Ideally, we should call this function from time to time to collect heavy 119 /// Ideally, we should call this function from time to time to collect heavy
122 /// syntax trees. However, if we actually do that, everything is recomputed 120 /// syntax trees. However, if we actually do that, everything is recomputed
@@ -156,21 +154,26 @@ impl AnalysisImpl {
156 self.db.file_lines(file_id) 154 self.db.file_lines(file_id)
157 } 155 }
158 pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> { 156 pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> {
157 /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
158 struct Snap(salsa::Snapshot<db::RootDatabase>);
159 impl Clone for Snap {
160 fn clone(&self) -> Snap {
161 Snap(self.0.snapshot())
162 }
163 }
164
159 let buf: Vec<Arc<SymbolIndex>> = if query.libs { 165 let buf: Vec<Arc<SymbolIndex>> = if query.libs {
166 let snap = Snap(self.db.snapshot());
160 self.db 167 self.db
161 .libraries() 168 .library_roots()
162 .iter() 169 .par_iter()
163 .map(|&lib_id| self.db.library_symbols(lib_id)) 170 .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id))
164 .collect() 171 .collect()
165 } else { 172 } else {
166 let files = &self.db.source_root(WORKSPACE).files; 173 let mut files = Vec::new();
167 174 for &root in self.db.local_roots().iter() {
168 /// Need to wrap Snapshot to provide `Clone` impl for `map_with` 175 let sr = self.db.source_root(root);
169 struct Snap(salsa::Snapshot<db::RootDatabase>); 176 files.extend(sr.files.values().map(|&it| it))
170 impl Clone for Snap {
171 fn clone(&self) -> Snap {
172 Snap(self.0.snapshot())
173 }
174 } 177 }
175 178
176 let snap = Snap(self.db.snapshot()); 179 let snap = Snap(self.db.snapshot());
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 22fff71ab..a1d462528 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -18,9 +18,9 @@ pub mod mock_analysis;
18 18
19use std::{fmt, sync::Arc}; 19use std::{fmt, sync::Arc};
20 20
21use rustc_hash::FxHashMap;
21use ra_syntax::{SourceFileNode, TextRange, TextUnit}; 22use ra_syntax::{SourceFileNode, TextRange, TextUnit};
22use ra_text_edit::AtomTextEdit; 23use ra_text_edit::AtomTextEdit;
23use ra_db::FileResolverImp;
24use rayon::prelude::*; 24use rayon::prelude::*;
25use relative_path::RelativePathBuf; 25use relative_path::RelativePathBuf;
26 26
@@ -39,28 +39,54 @@ pub use hir::FnSignatureInfo;
39 39
40pub use ra_db::{ 40pub use ra_db::{
41 Canceled, Cancelable, FilePosition, 41 Canceled, Cancelable, FilePosition,
42 CrateGraph, CrateId, FileId, FileResolver 42 CrateGraph, CrateId, SourceRootId, FileId
43}; 43};
44 44
45#[derive(Default)] 45#[derive(Default)]
46pub struct AnalysisChange { 46pub struct AnalysisChange {
47 files_added: Vec<(FileId, String)>, 47 new_roots: Vec<(SourceRootId, bool)>,
48 files_changed: Vec<(FileId, String)>, 48 roots_changed: FxHashMap<SourceRootId, RootChange>,
49 files_removed: Vec<(FileId)>, 49 files_changed: Vec<(FileId, Arc<String>)>,
50 libraries_added: Vec<LibraryData>, 50 libraries_added: Vec<LibraryData>,
51 crate_graph: Option<CrateGraph>, 51 crate_graph: Option<CrateGraph>,
52 file_resolver: Option<FileResolverImp>, 52}
53
54#[derive(Default)]
55struct RootChange {
56 added: Vec<AddFile>,
57 removed: Vec<RemoveFile>,
58}
59
60#[derive(Debug)]
61struct AddFile {
62 file_id: FileId,
63 path: RelativePathBuf,
64 text: Arc<String>,
65}
66
67#[derive(Debug)]
68struct RemoveFile {
69 file_id: FileId,
70 path: RelativePathBuf,
53} 71}
54 72
55impl fmt::Debug for AnalysisChange { 73impl fmt::Debug for AnalysisChange {
56 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 74 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
57 fmt.debug_struct("AnalysisChange") 75 fmt.debug_struct("AnalysisChange")
58 .field("files_added", &self.files_added.len()) 76 .field("new_roots", &self.new_roots)
77 .field("roots_changed", &self.roots_changed)
59 .field("files_changed", &self.files_changed.len()) 78 .field("files_changed", &self.files_changed.len())
60 .field("files_removed", &self.files_removed.len())
61 .field("libraries_added", &self.libraries_added.len()) 79 .field("libraries_added", &self.libraries_added.len())
62 .field("crate_graph", &self.crate_graph) 80 .field("crate_graph", &self.crate_graph)
63 .field("file_resolver", &self.file_resolver) 81 .finish()
82 }
83}
84
85impl fmt::Debug for RootChange {
86 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
87 fmt.debug_struct("AnalysisChange")
88 .field("added", &self.added.len())
89 .field("removed", &self.removed.len())
64 .finish() 90 .finish()
65 } 91 }
66} 92}
@@ -69,14 +95,37 @@ impl AnalysisChange {
69 pub fn new() -> AnalysisChange { 95 pub fn new() -> AnalysisChange {
70 AnalysisChange::default() 96 AnalysisChange::default()
71 } 97 }
72 pub fn add_file(&mut self, file_id: FileId, text: String) { 98 pub fn add_root(&mut self, root_id: SourceRootId, is_local: bool) {
73 self.files_added.push((file_id, text)) 99 self.new_roots.push((root_id, is_local));
74 } 100 }
75 pub fn change_file(&mut self, file_id: FileId, new_text: String) { 101 pub fn add_file(
102 &mut self,
103 root_id: SourceRootId,
104 file_id: FileId,
105 path: RelativePathBuf,
106 text: Arc<String>,
107 ) {
108 let file = AddFile {
109 file_id,
110 path,
111 text,
112 };
113 self.roots_changed
114 .entry(root_id)
115 .or_default()
116 .added
117 .push(file);
118 }
119 pub fn change_file(&mut self, file_id: FileId, new_text: Arc<String>) {
76 self.files_changed.push((file_id, new_text)) 120 self.files_changed.push((file_id, new_text))
77 } 121 }
78 pub fn remove_file(&mut self, file_id: FileId) { 122 pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
79 self.files_removed.push(file_id) 123 let file = RemoveFile { file_id, path };
124 self.roots_changed
125 .entry(root_id)
126 .or_default()
127 .removed
128 .push(file);
80 } 129 }
81 pub fn add_library(&mut self, data: LibraryData) { 130 pub fn add_library(&mut self, data: LibraryData) {
82 self.libraries_added.push(data) 131 self.libraries_added.push(data)
@@ -84,9 +133,6 @@ impl AnalysisChange {
84 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 133 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
85 self.crate_graph = Some(graph); 134 self.crate_graph = Some(graph);
86 } 135 }
87 pub fn set_file_resolver(&mut self, file_resolver: Arc<FileResolver>) {
88 self.file_resolver = Some(FileResolverImp::new(file_resolver));
89 }
90} 136}
91 137
92/// `AnalysisHost` stores the current state of the world. 138/// `AnalysisHost` stores the current state of the world.
@@ -313,20 +359,32 @@ impl Analysis {
313 359
314#[derive(Debug)] 360#[derive(Debug)]
315pub struct LibraryData { 361pub struct LibraryData {
316 files: Vec<(FileId, String)>, 362 root_id: SourceRootId,
317 file_resolver: FileResolverImp, 363 root_change: RootChange,
318 symbol_index: SymbolIndex, 364 symbol_index: SymbolIndex,
319} 365}
320 366
321impl LibraryData { 367impl LibraryData {
322 pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData { 368 pub fn prepare(
323 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, text)| { 369 root_id: SourceRootId,
370 files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
371 ) -> LibraryData {
372 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, _, text)| {
324 let file = SourceFileNode::parse(text); 373 let file = SourceFileNode::parse(text);
325 (*file_id, file) 374 (*file_id, file)
326 })); 375 }));
376 let mut root_change = RootChange::default();
377 root_change.added = files
378 .into_iter()
379 .map(|(file_id, path, text)| AddFile {
380 file_id,
381 path,
382 text,
383 })
384 .collect();
327 LibraryData { 385 LibraryData {
328 files, 386 root_id,
329 file_resolver: FileResolverImp::new(file_resolver), 387 root_change,
330 symbol_index, 388 symbol_index,
331 } 389 }
332 } 390 }
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs
index 0d9a7a147..7cbdfb953 100644
--- a/crates/ra_analysis/src/mock_analysis.rs
+++ b/crates/ra_analysis/src/mock_analysis.rs
@@ -4,7 +4,7 @@ use relative_path::{RelativePathBuf};
4use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
5use ra_db::mock::FileMap; 5use ra_db::mock::FileMap;
6 6
7use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition}; 7use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, SourceRootId};
8 8
9/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 9/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
10/// from a set of in-memory files. 10/// from a set of in-memory files.
@@ -78,14 +78,16 @@ impl MockAnalysis {
78 pub fn analysis_host(self) -> AnalysisHost { 78 pub fn analysis_host(self) -> AnalysisHost {
79 let mut host = AnalysisHost::default(); 79 let mut host = AnalysisHost::default();
80 let mut file_map = FileMap::default(); 80 let mut file_map = FileMap::default();
81 let source_root = SourceRootId(0);
81 let mut change = AnalysisChange::new(); 82 let mut change = AnalysisChange::new();
83 change.add_root(source_root, true);
82 for (path, contents) in self.files.into_iter() { 84 for (path, contents) in self.files.into_iter() {
83 assert!(path.starts_with('/')); 85 assert!(path.starts_with('/'));
84 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 86 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
85 let file_id = file_map.add(path); 87 let file_id = file_map.add(path.clone());
86 change.add_file(file_id, contents); 88 change.add_file(source_root, file_id, path, Arc::new(contents));
87 } 89 }
88 change.set_file_resolver(Arc::new(file_map)); 90 // change.set_file_resolver(Arc::new(file_map));
89 host.apply_change(change); 91 host.apply_change(change);
90 host 92 host
91 } 93 }