Skip to content

Commit 673e1dd

Browse files
bors[bot]matklad
andauthored
Merge #6123
6123: Reduce duplication in fixtures r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents a360832 + b062596 commit 673e1dd

38 files changed

+567
-672
lines changed

crates/base_db/src/change.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
4+
use std::{fmt, sync::Arc};
5+
6+
use rustc_hash::FxHashSet;
7+
use salsa::Durability;
8+
use vfs::FileId;
9+
10+
use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId};
11+
12+
/// Encapsulate a bunch of raw `.set` calls on the database.
13+
#[derive(Default)]
14+
pub 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+
20+
impl 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+
36+
impl 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+
91+
fn durability(source_root: &SourceRoot) -> Durability {
92+
if source_root.is_library {
93+
Durability::HIGH
94+
} else {
95+
Durability::LOW
96+
}
97+
}

crates/base_db/src/fixture.rs

Lines changed: 92 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -65,24 +65,26 @@ use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}
6565
use vfs::{file_set::FileSet, VfsPath};
6666

6767
use crate::{
68-
input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, SourceDatabaseExt,
69-
SourceRoot, SourceRootId,
68+
input::CrateName, Change, CrateGraph, CrateId, Edition, Env, FileId, FilePosition,
69+
SourceDatabaseExt, SourceRoot, SourceRootId,
7070
};
7171

7272
pub const WORKSPACE: SourceRootId = SourceRootId(0);
7373

7474
pub trait WithFixture: Default + SourceDatabaseExt + 'static {
7575
fn with_single_file(text: &str) -> (Self, FileId) {
76+
let fixture = ChangeFixture::parse(text);
7677
let mut db = Self::default();
77-
let (_, files) = with_files(&mut db, text);
78-
assert_eq!(files.len(), 1);
79-
(db, files[0])
78+
fixture.change.apply(&mut db);
79+
assert_eq!(fixture.files.len(), 1);
80+
(db, fixture.files[0])
8081
}
8182

8283
fn with_files(ra_fixture: &str) -> Self {
84+
let fixture = ChangeFixture::parse(ra_fixture);
8385
let mut db = Self::default();
84-
let (pos, _) = with_files(&mut db, ra_fixture);
85-
assert!(pos.is_none());
86+
fixture.change.apply(&mut db);
87+
assert!(fixture.file_position.is_none());
8688
db
8789
}
8890

@@ -96,9 +98,10 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
9698
}
9799

98100
fn with_range_or_offset(ra_fixture: &str) -> (Self, FileId, RangeOrOffset) {
101+
let fixture = ChangeFixture::parse(ra_fixture);
99102
let mut db = Self::default();
100-
let (pos, _) = with_files(&mut db, ra_fixture);
101-
let (file_id, range_or_offset) = pos.unwrap();
103+
fixture.change.apply(&mut db);
104+
let (file_id, range_or_offset) = fixture.file_position.unwrap();
102105
(db, file_id, range_or_offset)
103106
}
104107

@@ -113,89 +116,95 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
113116

114117
impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {}
115118

116-
fn with_files(
117-
db: &mut dyn SourceDatabaseExt,
118-
fixture: &str,
119-
) -> (Option<(FileId, RangeOrOffset)>, Vec<FileId>) {
120-
let fixture = Fixture::parse(fixture);
121-
122-
let mut files = Vec::new();
123-
let mut crate_graph = CrateGraph::default();
124-
let mut crates = FxHashMap::default();
125-
let mut crate_deps = Vec::new();
126-
let mut default_crate_root: Option<FileId> = None;
127-
128-
let mut file_set = FileSet::default();
129-
let source_root_id = WORKSPACE;
130-
let source_root_prefix = "/".to_string();
131-
let mut file_id = FileId(0);
132-
133-
let mut file_position = None;
134-
135-
for entry in fixture {
136-
let text = if entry.text.contains(CURSOR_MARKER) {
137-
let (range_or_offset, text) = extract_range_or_offset(&entry.text);
138-
assert!(file_position.is_none());
139-
file_position = Some((file_id, range_or_offset));
140-
text.to_string()
141-
} else {
142-
entry.text.clone()
143-
};
119+
pub struct ChangeFixture {
120+
pub file_position: Option<(FileId, RangeOrOffset)>,
121+
pub files: Vec<FileId>,
122+
pub change: Change,
123+
}
144124

145-
let meta = FileMeta::from(entry);
146-
assert!(meta.path.starts_with(&source_root_prefix));
125+
impl ChangeFixture {
126+
pub fn parse(ra_fixture: &str) -> ChangeFixture {
127+
let fixture = Fixture::parse(ra_fixture);
128+
let mut change = Change::new();
129+
130+
let mut files = Vec::new();
131+
let mut crate_graph = CrateGraph::default();
132+
let mut crates = FxHashMap::default();
133+
let mut crate_deps = Vec::new();
134+
let mut default_crate_root: Option<FileId> = None;
135+
let mut default_cfg = CfgOptions::default();
136+
137+
let mut file_set = FileSet::default();
138+
let source_root_prefix = "/".to_string();
139+
let mut file_id = FileId(0);
140+
141+
let mut file_position = None;
142+
143+
for entry in fixture {
144+
let text = if entry.text.contains(CURSOR_MARKER) {
145+
let (range_or_offset, text) = extract_range_or_offset(&entry.text);
146+
assert!(file_position.is_none());
147+
file_position = Some((file_id, range_or_offset));
148+
text.to_string()
149+
} else {
150+
entry.text.clone()
151+
};
152+
153+
let meta = FileMeta::from(entry);
154+
assert!(meta.path.starts_with(&source_root_prefix));
155+
156+
if let Some(krate) = meta.krate {
157+
let crate_id = crate_graph.add_crate_root(
158+
file_id,
159+
meta.edition,
160+
Some(krate.clone()),
161+
meta.cfg,
162+
meta.env,
163+
Default::default(),
164+
);
165+
let crate_name = CrateName::new(&krate).unwrap();
166+
let prev = crates.insert(crate_name.clone(), crate_id);
167+
assert!(prev.is_none());
168+
for dep in meta.deps {
169+
let dep = CrateName::new(&dep).unwrap();
170+
crate_deps.push((crate_name.clone(), dep))
171+
}
172+
} else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
173+
assert!(default_crate_root.is_none());
174+
default_crate_root = Some(file_id);
175+
default_cfg = meta.cfg;
176+
}
177+
178+
change.change_file(file_id, Some(Arc::new(text)));
179+
let path = VfsPath::new_virtual_path(meta.path);
180+
file_set.insert(file_id, path.into());
181+
files.push(file_id);
182+
file_id.0 += 1;
183+
}
147184

148-
if let Some(krate) = meta.krate {
149-
let crate_id = crate_graph.add_crate_root(
150-
file_id,
151-
meta.edition,
152-
Some(krate.clone()),
153-
meta.cfg,
154-
meta.env,
185+
if crates.is_empty() {
186+
let crate_root = default_crate_root.unwrap();
187+
crate_graph.add_crate_root(
188+
crate_root,
189+
Edition::Edition2018,
190+
Some("test".to_string()),
191+
default_cfg,
192+
Env::default(),
155193
Default::default(),
156194
);
157-
let crate_name = CrateName::new(&krate).unwrap();
158-
let prev = crates.insert(crate_name.clone(), crate_id);
159-
assert!(prev.is_none());
160-
for dep in meta.deps {
161-
let dep = CrateName::new(&dep).unwrap();
162-
crate_deps.push((crate_name.clone(), dep))
195+
} else {
196+
for (from, to) in crate_deps {
197+
let from_id = crates[&from];
198+
let to_id = crates[&to];
199+
crate_graph.add_dep(from_id, CrateName::new(&to).unwrap(), to_id).unwrap();
163200
}
164-
} else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
165-
assert!(default_crate_root.is_none());
166-
default_crate_root = Some(file_id);
167201
}
168202

169-
db.set_file_text(file_id, Arc::new(text));
170-
db.set_file_source_root(file_id, source_root_id);
171-
let path = VfsPath::new_virtual_path(meta.path);
172-
file_set.insert(file_id, path.into());
173-
files.push(file_id);
174-
file_id.0 += 1;
175-
}
203+
change.set_roots(vec![SourceRoot::new_local(file_set)]);
204+
change.set_crate_graph(crate_graph);
176205

177-
if crates.is_empty() {
178-
let crate_root = default_crate_root.unwrap();
179-
crate_graph.add_crate_root(
180-
crate_root,
181-
Edition::Edition2018,
182-
None,
183-
CfgOptions::default(),
184-
Env::default(),
185-
Default::default(),
186-
);
187-
} else {
188-
for (from, to) in crate_deps {
189-
let from_id = crates[&from];
190-
let to_id = crates[&to];
191-
crate_graph.add_dep(from_id, CrateName::new(&to).unwrap(), to_id).unwrap();
192-
}
206+
ChangeFixture { file_position, files, change }
193207
}
194-
195-
db.set_source_root(source_root_id, Arc::new(SourceRoot::new_local(file_set)));
196-
db.set_crate_graph(Arc::new(crate_graph));
197-
198-
(file_position, files)
199208
}
200209

201210
struct FileMeta {

crates/base_db/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! base_db defines basic database traits. The concrete DB is defined by ide.
22
mod cancellation;
33
mod input;
4+
mod change;
45
pub mod fixture;
56

67
use std::{panic, sync::Arc};
@@ -10,6 +11,7 @@ use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
1011

1112
pub use crate::{
1213
cancellation::Canceled,
14+
change::Change,
1315
input::{
1416
CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId,
1517
SourceRoot, SourceRootId,

0 commit comments

Comments
 (0)