aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/base_db/src/change.rs97
-rw-r--r--crates/base_db/src/lib.rs2
-rw-r--r--crates/ide/src/lib.rs7
-rw-r--r--crates/ide/src/mock_analysis.rs6
-rw-r--r--crates/ide/src/parent_module.rs4
-rw-r--r--crates/ide_db/src/apply_change.rs (renamed from crates/ide_db/src/change.rs)78
-rw-r--r--crates/ide_db/src/lib.rs2
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs7
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs4
-rw-r--r--crates/rust-analyzer/src/reload.rs4
11 files changed, 122 insertions, 93 deletions
diff --git a/crates/base_db/src/change.rs b/crates/base_db/src/change.rs
new file mode 100644
index 000000000..043e03bba
--- /dev/null
+++ b/crates/base_db/src/change.rs
@@ -0,0 +1,97 @@
1//! Defines a unit of change that can applied to the database to get the next
2//! state. Changes are transactional.
3
4use std::{fmt, sync::Arc};
5
6use rustc_hash::FxHashSet;
7use salsa::Durability;
8use vfs::FileId;
9
10use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId};
11
12/// Encapsulate a bunch of raw `.set` calls on the database.
13#[derive(Default)]
14pub struct Change {
15 pub roots: Option<Vec<SourceRoot>>,
16 pub files_changed: Vec<(FileId, Option<Arc<String>>)>,
17 pub crate_graph: Option<CrateGraph>,
18}
19
20impl fmt::Debug for Change {
21 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
22 let mut d = fmt.debug_struct("AnalysisChange");
23 if let Some(roots) = &self.roots {
24 d.field("roots", roots);
25 }
26 if !self.files_changed.is_empty() {
27 d.field("files_changed", &self.files_changed.len());
28 }
29 if self.crate_graph.is_some() {
30 d.field("crate_graph", &self.crate_graph);
31 }
32 d.finish()
33 }
34}
35
36impl Change {
37 pub fn new() -> Change {
38 Change::default()
39 }
40
41 pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
42 self.roots = Some(roots);
43 }
44
45 pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
46 self.files_changed.push((file_id, new_text))
47 }
48
49 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
50 self.crate_graph = Some(graph);
51 }
52
53 pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
54 let _p = profile::span("RootDatabase::apply_change");
55 // db.request_cancellation();
56 // log::info!("apply_change {:?}", change);
57 if let Some(roots) = self.roots {
58 let mut local_roots = FxHashSet::default();
59 let mut library_roots = FxHashSet::default();
60 for (idx, root) in roots.into_iter().enumerate() {
61 let root_id = SourceRootId(idx as u32);
62 let durability = durability(&root);
63 if root.is_library {
64 library_roots.insert(root_id);
65 } else {
66 local_roots.insert(root_id);
67 }
68 for file_id in root.iter() {
69 db.set_file_source_root_with_durability(file_id, root_id, durability);
70 }
71 db.set_source_root_with_durability(root_id, Arc::new(root), durability);
72 }
73 // db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
74 // db.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
75 }
76
77 for (file_id, text) in self.files_changed {
78 let source_root_id = db.file_source_root(file_id);
79 let source_root = db.source_root(source_root_id);
80 let durability = durability(&source_root);
81 // XXX: can't actually remove the file, just reset the text
82 let text = text.unwrap_or_default();
83 db.set_file_text_with_durability(file_id, text, durability)
84 }
85 if let Some(crate_graph) = self.crate_graph {
86 db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
87 }
88 }
89}
90
91fn durability(source_root: &SourceRoot) -> Durability {
92 if source_root.is_library {
93 Durability::HIGH
94 } else {
95 Durability::LOW
96 }
97}
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index ee3415850..e38aa7257 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -1,6 +1,7 @@
1//! base_db defines basic database traits. The concrete DB is defined by ide. 1//! base_db defines basic database traits. The concrete DB is defined by ide.
2mod cancellation; 2mod cancellation;
3mod input; 3mod input;
4mod change;
4pub mod fixture; 5pub mod fixture;
5 6
6use std::{panic, sync::Arc}; 7use std::{panic, sync::Arc};
@@ -10,6 +11,7 @@ use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
10 11
11pub use crate::{ 12pub use crate::{
12 cancellation::Canceled, 13 cancellation::Canceled,
14 change::Change,
13 input::{ 15 input::{
14 CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId, 16 CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId,
15 SourceRoot, SourceRootId, 17 SourceRoot, SourceRootId,
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index bab3ec1ff..073b766a5 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -87,12 +87,11 @@ pub use assists::{
87 utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist, 87 utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
88}; 88};
89pub use base_db::{ 89pub use base_db::{
90 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, 90 Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
91 SourceRootId, 91 SourceRootId,
92}; 92};
93pub use hir::{Documentation, Semantics}; 93pub use hir::{Documentation, Semantics};
94pub use ide_db::{ 94pub use ide_db::{
95 change::AnalysisChange,
96 label::Label, 95 label::Label,
97 line_index::{LineCol, LineIndex}, 96 line_index::{LineCol, LineIndex},
98 search::SearchScope, 97 search::SearchScope,
@@ -141,7 +140,7 @@ impl AnalysisHost {
141 140
142 /// Applies changes to the current state of the world. If there are 141 /// Applies changes to the current state of the world. If there are
143 /// outstanding snapshots, they will be canceled. 142 /// outstanding snapshots, they will be canceled.
144 pub fn apply_change(&mut self, change: AnalysisChange) { 143 pub fn apply_change(&mut self, change: Change) {
145 self.db.apply_change(change) 144 self.db.apply_change(change)
146 } 145 }
147 146
@@ -195,7 +194,7 @@ impl Analysis {
195 file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string())); 194 file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string()));
196 let source_root = SourceRoot::new_local(file_set); 195 let source_root = SourceRoot::new_local(file_set);
197 196
198 let mut change = AnalysisChange::new(); 197 let mut change = Change::new();
199 change.set_roots(vec![source_root]); 198 change.set_roots(vec![source_root]);
200 let mut crate_graph = CrateGraph::default(); 199 let mut crate_graph = CrateGraph::default();
201 // FIXME: cfg options 200 // FIXME: cfg options
diff --git a/crates/ide/src/mock_analysis.rs b/crates/ide/src/mock_analysis.rs
index 327cdf91e..6812db9b9 100644
--- a/crates/ide/src/mock_analysis.rs
+++ b/crates/ide/src/mock_analysis.rs
@@ -7,9 +7,7 @@ use test_utils::{
7 extract_annotations, extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, 7 extract_annotations, extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER,
8}; 8};
9 9
10use crate::{ 10use crate::{Analysis, AnalysisHost, Change, CrateGraph, Edition, FileId, FilePosition, FileRange};
11 Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange,
12};
13 11
14/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 12/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
15/// from a set of in-memory files. 13/// from a set of in-memory files.
@@ -95,7 +93,7 @@ impl MockAnalysis {
95 } 93 }
96 pub(crate) fn analysis_host(self) -> AnalysisHost { 94 pub(crate) fn analysis_host(self) -> AnalysisHost {
97 let mut host = AnalysisHost::default(); 95 let mut host = AnalysisHost::default();
98 let mut change = AnalysisChange::new(); 96 let mut change = Change::new();
99 let mut file_set = FileSet::default(); 97 let mut file_set = FileSet::default();
100 let mut crate_graph = CrateGraph::default(); 98 let mut crate_graph = CrateGraph::default();
101 let mut root_crate = None; 99 let mut root_crate = None;
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index 59ed2967c..68b107901 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -69,7 +69,7 @@ mod tests {
69 69
70 use crate::{ 70 use crate::{
71 mock_analysis::{analysis_and_position, MockAnalysis}, 71 mock_analysis::{analysis_and_position, MockAnalysis},
72 AnalysisChange, CrateGraph, 72 Change, CrateGraph,
73 Edition::Edition2018, 73 Edition::Edition2018,
74 }; 74 };
75 75
@@ -146,7 +146,7 @@ mod foo;
146 Env::default(), 146 Env::default(),
147 Default::default(), 147 Default::default(),
148 ); 148 );
149 let mut change = AnalysisChange::new(); 149 let mut change = Change::new();
150 change.set_crate_graph(crate_graph); 150 change.set_crate_graph(crate_graph);
151 host.apply_change(change); 151 host.apply_change(change);
152 152
diff --git a/crates/ide_db/src/change.rs b/crates/ide_db/src/apply_change.rs
index 7f98111c4..da16fa21d 100644
--- a/crates/ide_db/src/change.rs
+++ b/crates/ide_db/src/apply_change.rs
@@ -1,58 +1,16 @@
1//! Defines a unit of change that can applied to a state of IDE to get the next 1//! Applies changes to the IDE state transactionally.
2//! state. Changes are transactional.
3 2
4use std::{fmt, sync::Arc}; 3use std::{fmt, sync::Arc};
5 4
6use base_db::{ 5use base_db::{
7 salsa::{Database, Durability, SweepStrategy}, 6 salsa::{Database, Durability, SweepStrategy},
8 CrateGraph, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, 7 Change, FileId, SourceRootId,
9}; 8};
10use profile::{memory_usage, Bytes}; 9use profile::{memory_usage, Bytes};
11use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
12 11
13use crate::{symbol_index::SymbolsDatabase, RootDatabase}; 12use crate::{symbol_index::SymbolsDatabase, RootDatabase};
14 13
15#[derive(Default)]
16pub struct AnalysisChange {
17 roots: Option<Vec<SourceRoot>>,
18 files_changed: Vec<(FileId, Option<Arc<String>>)>,
19 crate_graph: Option<CrateGraph>,
20}
21
22impl fmt::Debug for AnalysisChange {
23 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
24 let mut d = fmt.debug_struct("AnalysisChange");
25 if let Some(roots) = &self.roots {
26 d.field("roots", roots);
27 }
28 if !self.files_changed.is_empty() {
29 d.field("files_changed", &self.files_changed.len());
30 }
31 if self.crate_graph.is_some() {
32 d.field("crate_graph", &self.crate_graph);
33 }
34 d.finish()
35 }
36}
37
38impl AnalysisChange {
39 pub fn new() -> AnalysisChange {
40 AnalysisChange::default()
41 }
42
43 pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
44 self.roots = Some(roots);
45 }
46
47 pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
48 self.files_changed.push((file_id, new_text))
49 }
50
51 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
52 self.crate_graph = Some(graph);
53 }
54}
55
56#[derive(Debug)] 14#[derive(Debug)]
57struct AddFile { 15struct AddFile {
58 file_id: FileId, 16 file_id: FileId,
@@ -87,41 +45,25 @@ impl RootDatabase {
87 self.salsa_runtime_mut().synthetic_write(Durability::LOW); 45 self.salsa_runtime_mut().synthetic_write(Durability::LOW);
88 } 46 }
89 47
90 pub fn apply_change(&mut self, change: AnalysisChange) { 48 pub fn apply_change(&mut self, change: Change) {
91 let _p = profile::span("RootDatabase::apply_change"); 49 let _p = profile::span("RootDatabase::apply_change");
92 self.request_cancellation(); 50 self.request_cancellation();
93 log::info!("apply_change {:?}", change); 51 log::info!("apply_change {:?}", change);
94 if let Some(roots) = change.roots { 52 if let Some(roots) = &change.roots {
95 let mut local_roots = FxHashSet::default(); 53 let mut local_roots = FxHashSet::default();
96 let mut library_roots = FxHashSet::default(); 54 let mut library_roots = FxHashSet::default();
97 for (idx, root) in roots.into_iter().enumerate() { 55 for (idx, root) in roots.iter().enumerate() {
98 let root_id = SourceRootId(idx as u32); 56 let root_id = SourceRootId(idx as u32);
99 let durability = durability(&root);
100 if root.is_library { 57 if root.is_library {
101 library_roots.insert(root_id); 58 library_roots.insert(root_id);
102 } else { 59 } else {
103 local_roots.insert(root_id); 60 local_roots.insert(root_id);
104 } 61 }
105 for file_id in root.iter() {
106 self.set_file_source_root_with_durability(file_id, root_id, durability);
107 }
108 self.set_source_root_with_durability(root_id, Arc::new(root), durability);
109 } 62 }
110 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); 63 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
111 self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH); 64 self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
112 } 65 }
113 66 change.apply(self);
114 for (file_id, text) in change.files_changed {
115 let source_root_id = self.file_source_root(file_id);
116 let source_root = self.source_root(source_root_id);
117 let durability = durability(&source_root);
118 // XXX: can't actually remove the file, just reset the text
119 let text = text.unwrap_or_default();
120 self.set_file_text_with_durability(file_id, text, durability)
121 }
122 if let Some(crate_graph) = change.crate_graph {
123 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
124 }
125 } 67 }
126 68
127 pub fn collect_garbage(&mut self) { 69 pub fn collect_garbage(&mut self) {
@@ -295,11 +237,3 @@ impl RootDatabase {
295 acc 237 acc
296 } 238 }
297} 239}
298
299fn durability(source_root: &SourceRoot) -> Durability {
300 if source_root.is_library {
301 Durability::HIGH
302 } else {
303 Durability::LOW
304 }
305}
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index 0d209c6ec..7eff247c7 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -2,10 +2,10 @@
2//! 2//!
3//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. 3//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
4 4
5mod apply_change;
5pub mod label; 6pub mod label;
6pub mod line_index; 7pub mod line_index;
7pub mod symbol_index; 8pub mod symbol_index;
8pub mod change;
9pub mod defs; 9pub mod defs;
10pub mod search; 10pub mod search;
11pub mod imports_locator; 11pub mod imports_locator;
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index c312e0a2e..d1c095ba5 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -8,8 +8,7 @@ use base_db::{
8 FileId, 8 FileId,
9}; 9};
10use ide::{ 10use ide::{
11 Analysis, AnalysisChange, AnalysisHost, CompletionConfig, DiagnosticsConfig, FilePosition, 11 Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
12 LineCol,
13}; 12};
14use vfs::AbsPathBuf; 13use vfs::AbsPathBuf;
15 14
@@ -143,7 +142,7 @@ fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, w
143 { 142 {
144 let mut text = host.analysis().file_text(file_id).unwrap().to_string(); 143 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
145 text.push_str("\n/* Hello world */\n"); 144 text.push_str("\n/* Hello world */\n");
146 let mut change = AnalysisChange::new(); 145 let mut change = Change::new();
147 change.change_file(file_id, Some(Arc::new(text))); 146 change.change_file(file_id, Some(Arc::new(text)));
148 host.apply_change(change); 147 host.apply_change(change);
149 } 148 }
@@ -156,7 +155,7 @@ fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, w
156 { 155 {
157 let mut text = host.analysis().file_text(file_id).unwrap().to_string(); 156 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
158 text.push_str("\npub fn _dummy() {}\n"); 157 text.push_str("\npub fn _dummy() {}\n");
159 let mut change = AnalysisChange::new(); 158 let mut change = Change::new();
160 change.change_file(file_id, Some(Arc::new(text))); 159 change.change_file(file_id, Some(Arc::new(text)));
161 host.apply_change(change); 160 host.apply_change(change);
162 } 161 }
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index c47cf6ef3..7ae1c9055 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -5,7 +5,7 @@ use std::{path::Path, sync::Arc};
5use anyhow::Result; 5use anyhow::Result;
6use base_db::CrateGraph; 6use base_db::CrateGraph;
7use crossbeam_channel::{unbounded, Receiver}; 7use crossbeam_channel::{unbounded, Receiver};
8use ide::{AnalysisChange, AnalysisHost}; 8use ide::{AnalysisHost, Change};
9use project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace}; 9use project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace};
10use vfs::{loader::Handle, AbsPath, AbsPathBuf}; 10use vfs::{loader::Handle, AbsPath, AbsPathBuf};
11 11
@@ -62,7 +62,7 @@ fn load(
62) -> AnalysisHost { 62) -> AnalysisHost {
63 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok()); 63 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
64 let mut host = AnalysisHost::new(lru_cap); 64 let mut host = AnalysisHost::new(lru_cap);
65 let mut analysis_change = AnalysisChange::new(); 65 let mut analysis_change = Change::new();
66 66
67 // wait until Vfs has loaded all roots 67 // wait until Vfs has loaded all roots
68 for task in receiver { 68 for task in receiver {
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 96313aaec..dafab6a6a 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -8,7 +8,7 @@ use std::{sync::Arc, time::Instant};
8use base_db::{CrateId, VfsPath}; 8use base_db::{CrateId, VfsPath};
9use crossbeam_channel::{unbounded, Receiver, Sender}; 9use crossbeam_channel::{unbounded, Receiver, Sender};
10use flycheck::FlycheckHandle; 10use flycheck::FlycheckHandle;
11use ide::{Analysis, AnalysisChange, AnalysisHost, FileId}; 11use ide::{Analysis, AnalysisHost, Change, FileId};
12use lsp_types::{SemanticTokens, Url}; 12use lsp_types::{SemanticTokens, Url};
13use parking_lot::{Mutex, RwLock}; 13use parking_lot::{Mutex, RwLock};
14use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; 14use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
@@ -139,7 +139,7 @@ impl GlobalState {
139 let mut has_fs_changes = false; 139 let mut has_fs_changes = false;
140 140
141 let change = { 141 let change = {
142 let mut change = AnalysisChange::new(); 142 let mut change = Change::new();
143 let (vfs, line_endings_map) = &mut *self.vfs.write(); 143 let (vfs, line_endings_map) = &mut *self.vfs.write();
144 let changed_files = vfs.take_changes(); 144 let changed_files = vfs.take_changes();
145 if changed_files.is_empty() { 145 if changed_files.is_empty() {
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index de0dbcad4..f7215f129 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -3,7 +3,7 @@ use std::{mem, sync::Arc};
3 3
4use base_db::{CrateGraph, SourceRoot, VfsPath}; 4use base_db::{CrateGraph, SourceRoot, VfsPath};
5use flycheck::{FlycheckConfig, FlycheckHandle}; 5use flycheck::{FlycheckConfig, FlycheckHandle};
6use ide::AnalysisChange; 6use ide::Change;
7use project_model::{ProcMacroClient, ProjectWorkspace}; 7use project_model::{ProcMacroClient, ProjectWorkspace};
8use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; 8use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
9 9
@@ -171,7 +171,7 @@ impl GlobalState {
171 ); 171 );
172 } 172 }
173 173
174 let mut change = AnalysisChange::new(); 174 let mut change = Change::new();
175 175
176 let project_folders = ProjectFolders::new(&workspaces); 176 let project_folders = ProjectFolders::new(&workspaces);
177 177