Skip to content

Commit 9798463

Browse files
committed
reproduce incremental bug
1 parent c1e10a2 commit 9798463

File tree

4 files changed

+263
-254
lines changed

4 files changed

+263
-254
lines changed

crates/ra_ide_api/src/change.rs

+255
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
use std::{
2+
fmt, time,
3+
sync::Arc,
4+
};
5+
6+
use rustc_hash::FxHashMap;
7+
use ra_db::{
8+
SourceRootId, FileId, CrateGraph, SourceDatabase, SourceRoot,
9+
salsa::{Database, SweepStrategy},
10+
};
11+
use ra_syntax::SourceFile;
12+
use relative_path::RelativePathBuf;
13+
use rayon::prelude::*;
14+
15+
use crate::{
16+
db::RootDatabase,
17+
symbol_index::{SymbolIndex, SymbolsDatabase},
18+
status::syntax_tree_stats,
19+
};
20+
21+
#[derive(Default)]
22+
pub struct AnalysisChange {
23+
new_roots: Vec<(SourceRootId, bool)>,
24+
roots_changed: FxHashMap<SourceRootId, RootChange>,
25+
files_changed: Vec<(FileId, Arc<String>)>,
26+
libraries_added: Vec<LibraryData>,
27+
crate_graph: Option<CrateGraph>,
28+
}
29+
30+
#[derive(Default)]
31+
struct RootChange {
32+
added: Vec<AddFile>,
33+
removed: Vec<RemoveFile>,
34+
}
35+
36+
#[derive(Debug)]
37+
struct AddFile {
38+
file_id: FileId,
39+
path: RelativePathBuf,
40+
text: Arc<String>,
41+
}
42+
43+
#[derive(Debug)]
44+
struct RemoveFile {
45+
file_id: FileId,
46+
path: RelativePathBuf,
47+
}
48+
49+
impl fmt::Debug for AnalysisChange {
50+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
51+
let mut d = fmt.debug_struct("AnalysisChange");
52+
if !self.new_roots.is_empty() {
53+
d.field("new_roots", &self.new_roots);
54+
}
55+
if !self.roots_changed.is_empty() {
56+
d.field("roots_changed", &self.roots_changed);
57+
}
58+
if !self.files_changed.is_empty() {
59+
d.field("files_changed", &self.files_changed.len());
60+
}
61+
if !self.libraries_added.is_empty() {
62+
d.field("libraries_added", &self.libraries_added.len());
63+
}
64+
if !self.crate_graph.is_some() {
65+
d.field("crate_graph", &self.crate_graph);
66+
}
67+
d.finish()
68+
}
69+
}
70+
71+
impl fmt::Debug for RootChange {
72+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
73+
fmt.debug_struct("AnalysisChange")
74+
.field("added", &self.added.len())
75+
.field("removed", &self.removed.len())
76+
.finish()
77+
}
78+
}
79+
80+
impl AnalysisChange {
81+
pub fn new() -> AnalysisChange {
82+
AnalysisChange::default()
83+
}
84+
85+
pub fn add_root(&mut self, root_id: SourceRootId, is_local: bool) {
86+
self.new_roots.push((root_id, is_local));
87+
}
88+
89+
pub fn add_file(
90+
&mut self,
91+
root_id: SourceRootId,
92+
file_id: FileId,
93+
path: RelativePathBuf,
94+
text: Arc<String>,
95+
) {
96+
let file = AddFile {
97+
file_id,
98+
path,
99+
text,
100+
};
101+
self.roots_changed
102+
.entry(root_id)
103+
.or_default()
104+
.added
105+
.push(file);
106+
}
107+
108+
pub fn change_file(&mut self, file_id: FileId, new_text: Arc<String>) {
109+
self.files_changed.push((file_id, new_text))
110+
}
111+
112+
pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
113+
let file = RemoveFile { file_id, path };
114+
self.roots_changed
115+
.entry(root_id)
116+
.or_default()
117+
.removed
118+
.push(file);
119+
}
120+
121+
pub fn add_library(&mut self, data: LibraryData) {
122+
self.libraries_added.push(data)
123+
}
124+
125+
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
126+
self.crate_graph = Some(graph);
127+
}
128+
}
129+
130+
pub struct LibraryData {
131+
root_id: SourceRootId,
132+
root_change: RootChange,
133+
symbol_index: SymbolIndex,
134+
}
135+
136+
impl fmt::Debug for LibraryData {
137+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138+
f.debug_struct("LibraryData")
139+
.field("root_id", &self.root_id)
140+
.field("root_change", &self.root_change)
141+
.field("n_symbols", &self.symbol_index.len())
142+
.finish()
143+
}
144+
}
145+
146+
impl LibraryData {
147+
pub fn prepare(
148+
root_id: SourceRootId,
149+
files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
150+
) -> LibraryData {
151+
let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, _, text)| {
152+
let file = SourceFile::parse(text);
153+
(*file_id, file)
154+
}));
155+
let mut root_change = RootChange::default();
156+
root_change.added = files
157+
.into_iter()
158+
.map(|(file_id, path, text)| AddFile {
159+
file_id,
160+
path,
161+
text,
162+
})
163+
.collect();
164+
LibraryData {
165+
root_id,
166+
root_change,
167+
symbol_index,
168+
}
169+
}
170+
}
171+
172+
const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
173+
174+
impl RootDatabase {
175+
pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
176+
log::info!("apply_change {:?}", change);
177+
if !change.new_roots.is_empty() {
178+
let mut local_roots = Vec::clone(&self.local_roots());
179+
for (root_id, is_local) in change.new_roots {
180+
self.set_source_root(root_id, Default::default());
181+
if is_local {
182+
local_roots.push(root_id);
183+
}
184+
}
185+
self.set_local_roots(Arc::new(local_roots));
186+
}
187+
188+
for (root_id, root_change) in change.roots_changed {
189+
self.apply_root_change(root_id, root_change);
190+
}
191+
for (file_id, text) in change.files_changed {
192+
self.set_file_text(file_id, text)
193+
}
194+
if !change.libraries_added.is_empty() {
195+
let mut libraries = Vec::clone(&self.library_roots());
196+
for library in change.libraries_added {
197+
libraries.push(library.root_id);
198+
self.set_source_root(library.root_id, Default::default());
199+
self.set_constant_library_symbols(library.root_id, Arc::new(library.symbol_index));
200+
self.apply_root_change(library.root_id, library.root_change);
201+
}
202+
self.set_library_roots(Arc::new(libraries));
203+
}
204+
if let Some(crate_graph) = change.crate_graph {
205+
self.set_crate_graph(Arc::new(crate_graph))
206+
}
207+
}
208+
209+
fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
210+
let mut source_root = SourceRoot::clone(&self.source_root(root_id));
211+
for add_file in root_change.added {
212+
self.set_file_text(add_file.file_id, add_file.text);
213+
self.set_file_relative_path(add_file.file_id, add_file.path.clone());
214+
self.set_file_source_root(add_file.file_id, root_id);
215+
source_root.files.insert(add_file.path, add_file.file_id);
216+
}
217+
for remove_file in root_change.removed {
218+
self.set_file_text(remove_file.file_id, Default::default());
219+
source_root.files.remove(&remove_file.path);
220+
}
221+
self.set_source_root(root_id, Arc::new(source_root));
222+
}
223+
224+
pub(crate) fn maybe_collect_garbage(&mut self) {
225+
if self.last_gc_check.elapsed() > GC_COOLDOWN {
226+
self.last_gc_check = time::Instant::now();
227+
let retained_trees = syntax_tree_stats(self).retained;
228+
if retained_trees > 100 {
229+
log::info!(
230+
"automatic garbadge collection, {} retained trees",
231+
retained_trees
232+
);
233+
self.collect_garbage();
234+
}
235+
}
236+
}
237+
238+
pub(crate) fn collect_garbage(&mut self) {
239+
self.last_gc = time::Instant::now();
240+
241+
let sweep = SweepStrategy::default()
242+
.discard_values()
243+
.sweep_all_revisions();
244+
245+
self.query(ra_db::ParseQuery).sweep(sweep);
246+
247+
self.query(hir::db::HirParseQuery).sweep(sweep);
248+
self.query(hir::db::FileItemsQuery).sweep(sweep);
249+
self.query(hir::db::FileItemQuery).sweep(sweep);
250+
251+
self.query(hir::db::LowerModuleQuery).sweep(sweep);
252+
self.query(hir::db::LowerModuleSourceMapQuery).sweep(sweep);
253+
self.query(hir::db::BodySyntaxMappingQuery).sweep(sweep);
254+
}
255+
}

crates/ra_ide_api/src/imp.rs

+3-98
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,20 @@
1-
use std::{
2-
sync::Arc,
3-
time,
4-
};
5-
61
use hir::{
72
self, Problem, source_binder
83
};
9-
use ra_db::{
10-
SourceDatabase, SourceRoot, SourceRootId,
11-
salsa::{Database, SweepStrategy},
12-
};
134
use ra_ide_api_light::{self, LocalEdit, Severity};
145
use ra_syntax::{
156
algo::find_node_at_offset, ast::{self, NameOwner}, AstNode,
167
SourceFile,
178
TextRange,
189
};
10+
use ra_db::SourceDatabase;
1911

2012
use crate::{
21-
AnalysisChange,
2213
CrateId, db, Diagnostic, FileId, FilePosition, FileSystemEdit,
23-
Query, RootChange, SourceChange, SourceFileEdit,
24-
symbol_index::{FileSymbol, SymbolsDatabase},
25-
status::syntax_tree_stats
14+
Query, SourceChange, SourceFileEdit,
15+
symbol_index::FileSymbol,
2616
};
2717

28-
const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
29-
30-
impl db::RootDatabase {
31-
pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
32-
log::info!("apply_change {:?}", change);
33-
if !change.new_roots.is_empty() {
34-
let mut local_roots = Vec::clone(&self.local_roots());
35-
for (root_id, is_local) in change.new_roots {
36-
self.set_source_root(root_id, Default::default());
37-
if is_local {
38-
local_roots.push(root_id);
39-
}
40-
}
41-
self.set_local_roots(Arc::new(local_roots));
42-
}
43-
44-
for (root_id, root_change) in change.roots_changed {
45-
self.apply_root_change(root_id, root_change);
46-
}
47-
for (file_id, text) in change.files_changed {
48-
self.set_file_text(file_id, text)
49-
}
50-
if !change.libraries_added.is_empty() {
51-
let mut libraries = Vec::clone(&self.library_roots());
52-
for library in change.libraries_added {
53-
libraries.push(library.root_id);
54-
self.set_source_root(library.root_id, Default::default());
55-
self.set_constant_library_symbols(library.root_id, Arc::new(library.symbol_index));
56-
self.apply_root_change(library.root_id, library.root_change);
57-
}
58-
self.set_library_roots(Arc::new(libraries));
59-
}
60-
if let Some(crate_graph) = change.crate_graph {
61-
self.set_crate_graph(Arc::new(crate_graph))
62-
}
63-
}
64-
65-
fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
66-
let mut source_root = SourceRoot::clone(&self.source_root(root_id));
67-
for add_file in root_change.added {
68-
self.set_file_text(add_file.file_id, add_file.text);
69-
self.set_file_relative_path(add_file.file_id, add_file.path.clone());
70-
self.set_file_source_root(add_file.file_id, root_id);
71-
source_root.files.insert(add_file.path, add_file.file_id);
72-
}
73-
for remove_file in root_change.removed {
74-
self.set_file_text(remove_file.file_id, Default::default());
75-
source_root.files.remove(&remove_file.path);
76-
}
77-
self.set_source_root(root_id, Arc::new(source_root));
78-
}
79-
80-
pub(crate) fn maybe_collect_garbage(&mut self) {
81-
if self.last_gc_check.elapsed() > GC_COOLDOWN {
82-
self.last_gc_check = time::Instant::now();
83-
let retained_trees = syntax_tree_stats(self).retained;
84-
if retained_trees > 100 {
85-
log::info!(
86-
"automatic garbadge collection, {} retained trees",
87-
retained_trees
88-
);
89-
self.collect_garbage();
90-
}
91-
}
92-
}
93-
94-
pub(crate) fn collect_garbage(&mut self) {
95-
self.last_gc = time::Instant::now();
96-
97-
let sweep = SweepStrategy::default()
98-
.discard_values()
99-
.sweep_all_revisions();
100-
101-
self.query(ra_db::ParseQuery).sweep(sweep);
102-
103-
self.query(hir::db::HirParseQuery).sweep(sweep);
104-
self.query(hir::db::FileItemsQuery).sweep(sweep);
105-
self.query(hir::db::FileItemQuery).sweep(sweep);
106-
107-
self.query(hir::db::LowerModuleQuery).sweep(sweep);
108-
self.query(hir::db::LowerModuleSourceMapQuery).sweep(sweep);
109-
self.query(hir::db::BodySyntaxMappingQuery).sweep(sweep);
110-
}
111-
}
112-
11318
impl db::RootDatabase {
11419
/// Returns `Vec` for the same reason as `parent_module`
11520
pub(crate) fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {

crates/ra_ide_api/src/impls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ra_db::{SourceDatabase};
1+
use ra_db::SourceDatabase;
22
use ra_syntax::{
33
AstNode, ast,
44
algo::find_node_at_offset,

0 commit comments

Comments
 (0)