Skip to content

Commit d0a3262

Browse files
bors[bot]flodiebold
andcommitted
Merge #767
767: Extract project model to separate crate r=matklad a=flodiebold I'm looking into creating a separate crate that would allow getting a HIR db for a project for 'batch' analyses, and this seems to be an obvious first step. We'd probably want to change the error handling to not rely on failure, though, right? Co-authored-by: Florian Diebold <[email protected]>
2 parents 34398a8 + e91a46e commit d0a3262

File tree

10 files changed

+212
-139
lines changed

10 files changed

+212
-139
lines changed

Cargo.lock

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_db/src/input.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ impl CrateGraph {
9191
assert!(prev.is_none());
9292
crate_id
9393
}
94+
9495
pub fn add_dep(
9596
&mut self,
9697
from: CrateId,
@@ -102,22 +103,40 @@ impl CrateGraph {
102103
}
103104
Ok(self.arena.get_mut(&from).unwrap().add_dep(name, to))
104105
}
106+
105107
pub fn is_empty(&self) -> bool {
106108
self.arena.is_empty()
107109
}
110+
108111
pub fn crate_root(&self, crate_id: CrateId) -> FileId {
109112
self.arena[&crate_id].file_id
110113
}
114+
111115
pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
112116
let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;
113117
Some(crate_id)
114118
}
119+
115120
pub fn dependencies<'a>(
116121
&'a self,
117122
crate_id: CrateId,
118123
) -> impl Iterator<Item = &'a Dependency> + 'a {
119124
self.arena[&crate_id].dependencies.iter()
120125
}
126+
127+
/// Extends this crate graph by adding a complete disjoint second crate
128+
/// graph.
129+
pub fn extend(&mut self, other: CrateGraph) {
130+
let start = self.arena.len() as u32;
131+
self.arena.extend(other.arena.into_iter().map(|(id, mut data)| {
132+
let new_id = CrateId(id.0 + start);
133+
for dep in &mut data.dependencies {
134+
dep.crate_id = CrateId(dep.crate_id.0 + start);
135+
}
136+
(new_id, data)
137+
}));
138+
}
139+
121140
fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool {
122141
if !visited.insert(from) {
123142
return false;

crates/ra_lsp_server/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ url_serde = "0.2.0"
1919
lsp-types = "0.55.0"
2020
walkdir = "2.2.7"
2121
im = "12.0.0"
22-
cargo_metadata = "0.7.0"
2322
rustc-hash = "1.0"
2423
parking_lot = "0.7.0"
2524

@@ -30,6 +29,7 @@ ra_ide_api = { path = "../ra_ide_api" }
3029
ra_arena = { path = "../ra_arena" }
3130
gen_lsp_server = { path = "../gen_lsp_server" }
3231
ra_vfs = { path = "../ra_vfs" }
32+
ra_project_model = { path = "../ra_project_model" }
3333

3434
[dev-dependencies]
3535
tempfile = "3"
Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,13 @@
1-
mod cargo_workspace;
2-
mod sysroot;
1+
use std::path::PathBuf;
32

4-
use std::path::{Path, PathBuf};
5-
6-
use failure::bail;
73
use thread_worker::{WorkerHandle, Worker};
84

95
use crate::Result;
106

11-
pub use crate::project_model::{
12-
cargo_workspace::{CargoWorkspace, Package, Target, TargetKind},
13-
sysroot::Sysroot,
7+
pub use ra_project_model::{
8+
ProjectWorkspace, CargoWorkspace, Package, Target, TargetKind, Sysroot,
149
};
1510

16-
#[derive(Debug, Clone)]
17-
pub struct ProjectWorkspace {
18-
pub(crate) cargo: CargoWorkspace,
19-
pub(crate) sysroot: Sysroot,
20-
}
21-
22-
impl ProjectWorkspace {
23-
pub fn discover(path: &Path) -> Result<ProjectWorkspace> {
24-
let cargo_toml = find_cargo_toml(path)?;
25-
let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?;
26-
let sysroot = Sysroot::discover(&cargo_toml)?;
27-
let res = ProjectWorkspace { cargo, sysroot };
28-
Ok(res)
29-
}
30-
}
31-
3211
pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) {
3312
thread_worker::spawn::<PathBuf, Result<ProjectWorkspace>, _>(
3413
"workspace loader",
@@ -42,18 +21,3 @@ pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerH
4221
},
4322
)
4423
}
45-
46-
fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
47-
if path.ends_with("Cargo.toml") {
48-
return Ok(path.to_path_buf());
49-
}
50-
let mut curr = Some(path);
51-
while let Some(path) = curr {
52-
let candidate = path.join("Cargo.toml");
53-
if candidate.exists() {
54-
return Ok(candidate);
55-
}
56-
curr = path.parent();
57-
}
58-
bail!("can't find Cargo.toml at {}", path.display())
59-
}

crates/ra_lsp_server/src/server_world.rs

Lines changed: 7 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ use ra_ide_api::{
99
SourceRootId
1010
};
1111
use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot};
12-
use rustc_hash::FxHashMap;
1312
use relative_path::RelativePathBuf;
1413
use parking_lot::RwLock;
1514
use failure::format_err;
1615

1716
use crate::{
18-
project_model::{ProjectWorkspace, TargetKind},
17+
project_model::ProjectWorkspace,
1918
Result,
2019
};
2120

@@ -57,88 +56,14 @@ impl ServerWorldState {
5756
change.add_root(SourceRootId(r.0.into()), is_local);
5857
}
5958

59+
// Create crate graph from all the workspaces
6060
let mut crate_graph = CrateGraph::default();
61+
let mut load = |path: &std::path::Path| {
62+
let vfs_file = vfs.load(path);
63+
vfs_file.map(|f| FileId(f.0.into()))
64+
};
6165
for ws in workspaces.iter() {
62-
// First, load std
63-
let mut sysroot_crates = FxHashMap::default();
64-
for krate in ws.sysroot.crates() {
65-
if let Some(file_id) = vfs.load(krate.root(&ws.sysroot)) {
66-
let file_id = FileId(file_id.0.into());
67-
sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id));
68-
}
69-
}
70-
for from in ws.sysroot.crates() {
71-
for to in from.deps(&ws.sysroot) {
72-
let name = to.name(&ws.sysroot);
73-
if let (Some(&from), Some(&to)) =
74-
(sysroot_crates.get(&from), sysroot_crates.get(&to))
75-
{
76-
if let Err(_) = crate_graph.add_dep(from, name.clone(), to) {
77-
log::error!("cyclic dependency between sysroot crates")
78-
}
79-
}
80-
}
81-
}
82-
83-
let libstd = ws.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it));
84-
85-
let mut pkg_to_lib_crate = FxHashMap::default();
86-
let mut pkg_crates = FxHashMap::default();
87-
// Next, create crates for each package, target pair
88-
for pkg in ws.cargo.packages() {
89-
let mut lib_tgt = None;
90-
for tgt in pkg.targets(&ws.cargo) {
91-
let root = tgt.root(&ws.cargo);
92-
if let Some(file_id) = vfs.load(root) {
93-
let file_id = FileId(file_id.0.into());
94-
let crate_id = crate_graph.add_crate_root(file_id);
95-
if tgt.kind(&ws.cargo) == TargetKind::Lib {
96-
lib_tgt = Some(crate_id);
97-
pkg_to_lib_crate.insert(pkg, crate_id);
98-
}
99-
pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
100-
}
101-
}
102-
103-
// Set deps to the std and to the lib target of the current package
104-
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
105-
if let Some(to) = lib_tgt {
106-
if to != from {
107-
if let Err(_) =
108-
crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to)
109-
{
110-
log::error!(
111-
"cyclic dependency between targets of {}",
112-
pkg.name(&ws.cargo)
113-
)
114-
}
115-
}
116-
}
117-
if let Some(std) = libstd {
118-
if let Err(_) = crate_graph.add_dep(from, "std".into(), std) {
119-
log::error!("cyclic dependency on std for {}", pkg.name(&ws.cargo))
120-
}
121-
}
122-
}
123-
}
124-
125-
// Now add a dep ednge from all targets of upstream to the lib
126-
// target of downstream.
127-
for pkg in ws.cargo.packages() {
128-
for dep in pkg.dependencies(&ws.cargo) {
129-
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
130-
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
131-
if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) {
132-
log::error!(
133-
"cyclic dependency {} -> {}",
134-
pkg.name(&ws.cargo),
135-
dep.pkg.name(&ws.cargo)
136-
)
137-
}
138-
}
139-
}
140-
}
141-
}
66+
crate_graph.extend(ws.to_crate_graph(&mut load));
14267
}
14368
change.set_crate_graph(crate_graph);
14469

crates/ra_project_model/Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
edition = "2018"
3+
name = "ra_project_model"
4+
version = "0.1.0"
5+
authors = ["Aleksey Kladov <[email protected]>"]
6+
7+
[dependencies]
8+
log = "0.4.5"
9+
rustc-hash = "1.0"
10+
11+
failure = "0.1.4"
12+
13+
walkdir = "2.2.7"
14+
15+
cargo_metadata = "0.7.0"
16+
17+
ra_arena = { path = "../ra_arena" }
18+
ra_db = { path = "../ra_db" }
19+
20+
[dev-dependencies]
21+
test_utils = { path = "../test_utils" }

crates/ra_lsp_server/src/project_model/cargo_workspace.rs renamed to crates/ra_project_model/src/cargo_workspace.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
use std::path::{Path, PathBuf};
22

33
use cargo_metadata::{MetadataCommand, CargoOpt};
4-
use ra_syntax::SmolStr;
54
use ra_arena::{Arena, RawId, impl_arena_id};
65
use rustc_hash::FxHashMap;
76
use failure::format_err;
87

98
use crate::Result;
109

11-
/// `CargoWorksapce` represents the logical structure of, well, a Cargo
10+
/// `CargoWorkspace` represents the logical structure of, well, a Cargo
1211
/// workspace. It pretty closely mirrors `cargo metadata` output.
1312
///
14-
/// Note that internally, rust analyzer uses a differnet structure:
13+
/// Note that internally, rust analyzer uses a different structure:
1514
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
1615
/// while this knows about `Pacakges` & `Targets`: purely cargo-related
1716
/// concepts.
@@ -31,7 +30,7 @@ impl_arena_id!(Target);
3130

3231
#[derive(Debug, Clone)]
3332
struct PackageData {
34-
name: SmolStr,
33+
name: String,
3534
manifest: PathBuf,
3635
targets: Vec<Target>,
3736
is_member: bool,
@@ -41,13 +40,13 @@ struct PackageData {
4140
#[derive(Debug, Clone)]
4241
pub struct PackageDependency {
4342
pub pkg: Package,
44-
pub name: SmolStr,
43+
pub name: String,
4544
}
4645

4746
#[derive(Debug, Clone)]
4847
struct TargetData {
4948
pkg: Package,
50-
name: SmolStr,
49+
name: String,
5150
root: PathBuf,
5251
kind: TargetKind,
5352
}
@@ -162,9 +161,11 @@ impl CargoWorkspace {
162161

163162
Ok(CargoWorkspace { packages, targets })
164163
}
164+
165165
pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a {
166166
self.packages.iter().map(|(id, _pkg)| id)
167167
}
168+
168169
pub fn target_by_root(&self, root: &Path) -> Option<Target> {
169170
self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next()
170171
}

0 commit comments

Comments
 (0)