aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-09 10:21:13 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-09 10:21:13 +0000
commitd0a32627a741826502692f2c3de71512b7ec23cf (patch)
treeee3cef56bd9738f5c3b98caae9b8ce1b8dbf401f
parent34398a8756b56c323d3b4b2ef32fbca32d88a105 (diff)
parente91a46eb0c4a355af25656d77dead55c2e29258e (diff)
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]>
-rw-r--r--Cargo.lock16
-rw-r--r--crates/ra_db/src/input.rs19
-rw-r--r--crates/ra_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/project_model.rs42
-rw-r--r--crates/ra_lsp_server/src/server_world.rs89
-rw-r--r--crates/ra_project_model/Cargo.toml21
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs (renamed from crates/ra_lsp_server/src/project_model/cargo_workspace.rs)13
-rw-r--r--crates/ra_project_model/src/lib.rs130
-rw-r--r--crates/ra_project_model/src/sysroot.rs (renamed from crates/ra_lsp_server/src/project_model/sysroot.rs)17
-rw-r--r--crates/ra_syntax/Cargo.toml2
10 files changed, 212 insertions, 139 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9c65b39f7..56acb9a30 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1008,7 +1008,6 @@ dependencies = [
1008name = "ra_lsp_server" 1008name = "ra_lsp_server"
1009version = "0.1.0" 1009version = "0.1.0"
1010dependencies = [ 1010dependencies = [
1011 "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1012 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1011 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1013 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 1012 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
1014 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1021,6 +1020,7 @@ dependencies = [
1021 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1020 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1022 "ra_arena 0.1.0", 1021 "ra_arena 0.1.0",
1023 "ra_ide_api 0.1.0", 1022 "ra_ide_api 0.1.0",
1023 "ra_project_model 0.1.0",
1024 "ra_syntax 0.1.0", 1024 "ra_syntax 0.1.0",
1025 "ra_text_edit 0.1.0", 1025 "ra_text_edit 0.1.0",
1026 "ra_vfs 0.1.0", 1026 "ra_vfs 0.1.0",
@@ -1046,6 +1046,20 @@ dependencies = [
1046] 1046]
1047 1047
1048[[package]] 1048[[package]]
1049name = "ra_project_model"
1050version = "0.1.0"
1051dependencies = [
1052 "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1053 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1054 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1055 "ra_arena 0.1.0",
1056 "ra_db 0.1.0",
1057 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1058 "test_utils 0.1.0",
1059 "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
1060]
1061
1062[[package]]
1049name = "ra_syntax" 1063name = "ra_syntax"
1050version = "0.1.0" 1064version = "0.1.0"
1051dependencies = [ 1065dependencies = [
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 614325a0f..405634fe0 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -91,6 +91,7 @@ impl CrateGraph {
91 assert!(prev.is_none()); 91 assert!(prev.is_none());
92 crate_id 92 crate_id
93 } 93 }
94
94 pub fn add_dep( 95 pub fn add_dep(
95 &mut self, 96 &mut self,
96 from: CrateId, 97 from: CrateId,
@@ -102,22 +103,40 @@ impl CrateGraph {
102 } 103 }
103 Ok(self.arena.get_mut(&from).unwrap().add_dep(name, to)) 104 Ok(self.arena.get_mut(&from).unwrap().add_dep(name, to))
104 } 105 }
106
105 pub fn is_empty(&self) -> bool { 107 pub fn is_empty(&self) -> bool {
106 self.arena.is_empty() 108 self.arena.is_empty()
107 } 109 }
110
108 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 111 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
109 self.arena[&crate_id].file_id 112 self.arena[&crate_id].file_id
110 } 113 }
114
111 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 115 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
112 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; 116 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;
113 Some(crate_id) 117 Some(crate_id)
114 } 118 }
119
115 pub fn dependencies<'a>( 120 pub fn dependencies<'a>(
116 &'a self, 121 &'a self,
117 crate_id: CrateId, 122 crate_id: CrateId,
118 ) -> impl Iterator<Item = &'a Dependency> + 'a { 123 ) -> impl Iterator<Item = &'a Dependency> + 'a {
119 self.arena[&crate_id].dependencies.iter() 124 self.arena[&crate_id].dependencies.iter()
120 } 125 }
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
121 fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool { 140 fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool {
122 if !visited.insert(from) { 141 if !visited.insert(from) {
123 return false; 142 return false;
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index bb92747f2..f46d77893 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -19,7 +19,6 @@ url_serde = "0.2.0"
19lsp-types = "0.55.0" 19lsp-types = "0.55.0"
20walkdir = "2.2.7" 20walkdir = "2.2.7"
21im = "12.0.0" 21im = "12.0.0"
22cargo_metadata = "0.7.0"
23rustc-hash = "1.0" 22rustc-hash = "1.0"
24parking_lot = "0.7.0" 23parking_lot = "0.7.0"
25 24
@@ -30,6 +29,7 @@ ra_ide_api = { path = "../ra_ide_api" }
30ra_arena = { path = "../ra_arena" } 29ra_arena = { path = "../ra_arena" }
31gen_lsp_server = { path = "../gen_lsp_server" } 30gen_lsp_server = { path = "../gen_lsp_server" }
32ra_vfs = { path = "../ra_vfs" } 31ra_vfs = { path = "../ra_vfs" }
32ra_project_model = { path = "../ra_project_model" }
33 33
34[dev-dependencies] 34[dev-dependencies]
35tempfile = "3" 35tempfile = "3"
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs
index fd5875a0a..6800eb138 100644
--- a/crates/ra_lsp_server/src/project_model.rs
+++ b/crates/ra_lsp_server/src/project_model.rs
@@ -1,34 +1,13 @@
1mod cargo_workspace; 1use std::path::PathBuf;
2mod sysroot;
3 2
4use std::path::{Path, PathBuf};
5
6use failure::bail;
7use thread_worker::{WorkerHandle, Worker}; 3use thread_worker::{WorkerHandle, Worker};
8 4
9use crate::Result; 5use crate::Result;
10 6
11pub use crate::project_model::{ 7pub use ra_project_model::{
12 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, 8 ProjectWorkspace, CargoWorkspace, Package, Target, TargetKind, Sysroot,
13 sysroot::Sysroot,
14}; 9};
15 10
16#[derive(Debug, Clone)]
17pub struct ProjectWorkspace {
18 pub(crate) cargo: CargoWorkspace,
19 pub(crate) sysroot: Sysroot,
20}
21
22impl 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
32pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) { 11pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) {
33 thread_worker::spawn::<PathBuf, Result<ProjectWorkspace>, _>( 12 thread_worker::spawn::<PathBuf, Result<ProjectWorkspace>, _>(
34 "workspace loader", 13 "workspace loader",
@@ -42,18 +21,3 @@ pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerH
42 }, 21 },
43 ) 22 )
44} 23}
45
46fn 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}
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs
index 02f2a37a8..f97d240fa 100644
--- a/crates/ra_lsp_server/src/server_world.rs
+++ b/crates/ra_lsp_server/src/server_world.rs
@@ -9,13 +9,12 @@ use ra_ide_api::{
9 SourceRootId 9 SourceRootId
10}; 10};
11use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; 11use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot};
12use rustc_hash::FxHashMap;
13use relative_path::RelativePathBuf; 12use relative_path::RelativePathBuf;
14use parking_lot::RwLock; 13use parking_lot::RwLock;
15use failure::format_err; 14use failure::format_err;
16 15
17use crate::{ 16use crate::{
18 project_model::{ProjectWorkspace, TargetKind}, 17 project_model::ProjectWorkspace,
19 Result, 18 Result,
20}; 19};
21 20
@@ -57,88 +56,14 @@ impl ServerWorldState {
57 change.add_root(SourceRootId(r.0.into()), is_local); 56 change.add_root(SourceRootId(r.0.into()), is_local);
58 } 57 }
59 58
59 // Create crate graph from all the workspaces
60 let mut crate_graph = CrateGraph::default(); 60 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 };
61 for ws in workspaces.iter() { 65 for ws in workspaces.iter() {
62 // First, load std 66 crate_graph.extend(ws.to_crate_graph(&mut load));
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 }
142 } 67 }
143 change.set_crate_graph(crate_graph); 68 change.set_crate_graph(crate_graph);
144 69
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
new file mode 100644
index 000000000..90f8b8398
--- /dev/null
+++ b/crates/ra_project_model/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2018"
3name = "ra_project_model"
4version = "0.1.0"
5authors = ["Aleksey Kladov <[email protected]>"]
6
7[dependencies]
8log = "0.4.5"
9rustc-hash = "1.0"
10
11failure = "0.1.4"
12
13walkdir = "2.2.7"
14
15cargo_metadata = "0.7.0"
16
17ra_arena = { path = "../ra_arena" }
18ra_db = { path = "../ra_db" }
19
20[dev-dependencies]
21test_utils = { path = "../test_utils" }
diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 3b76389d2..8adf463a6 100644
--- a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -1,17 +1,16 @@
1use std::path::{Path, PathBuf}; 1use std::path::{Path, PathBuf};
2 2
3use cargo_metadata::{MetadataCommand, CargoOpt}; 3use cargo_metadata::{MetadataCommand, CargoOpt};
4use ra_syntax::SmolStr;
5use ra_arena::{Arena, RawId, impl_arena_id}; 4use ra_arena::{Arena, RawId, impl_arena_id};
6use rustc_hash::FxHashMap; 5use rustc_hash::FxHashMap;
7use failure::format_err; 6use failure::format_err;
8 7
9use crate::Result; 8use crate::Result;
10 9
11/// `CargoWorksapce` represents the logical structure of, well, a Cargo 10/// `CargoWorkspace` represents the logical structure of, well, a Cargo
12/// workspace. It pretty closely mirrors `cargo metadata` output. 11/// workspace. It pretty closely mirrors `cargo metadata` output.
13/// 12///
14/// Note that internally, rust analyzer uses a differnet structure: 13/// Note that internally, rust analyzer uses a different structure:
15/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, 14/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
16/// while this knows about `Pacakges` & `Targets`: purely cargo-related 15/// while this knows about `Pacakges` & `Targets`: purely cargo-related
17/// concepts. 16/// concepts.
@@ -31,7 +30,7 @@ impl_arena_id!(Target);
31 30
32#[derive(Debug, Clone)] 31#[derive(Debug, Clone)]
33struct PackageData { 32struct PackageData {
34 name: SmolStr, 33 name: String,
35 manifest: PathBuf, 34 manifest: PathBuf,
36 targets: Vec<Target>, 35 targets: Vec<Target>,
37 is_member: bool, 36 is_member: bool,
@@ -41,13 +40,13 @@ struct PackageData {
41#[derive(Debug, Clone)] 40#[derive(Debug, Clone)]
42pub struct PackageDependency { 41pub struct PackageDependency {
43 pub pkg: Package, 42 pub pkg: Package,
44 pub name: SmolStr, 43 pub name: String,
45} 44}
46 45
47#[derive(Debug, Clone)] 46#[derive(Debug, Clone)]
48struct TargetData { 47struct TargetData {
49 pkg: Package, 48 pkg: Package,
50 name: SmolStr, 49 name: String,
51 root: PathBuf, 50 root: PathBuf,
52 kind: TargetKind, 51 kind: TargetKind,
53} 52}
@@ -162,9 +161,11 @@ impl CargoWorkspace {
162 161
163 Ok(CargoWorkspace { packages, targets }) 162 Ok(CargoWorkspace { packages, targets })
164 } 163 }
164
165 pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a { 165 pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a {
166 self.packages.iter().map(|(id, _pkg)| id) 166 self.packages.iter().map(|(id, _pkg)| id)
167 } 167 }
168
168 pub fn target_by_root(&self, root: &Path) -> Option<Target> { 169 pub fn target_by_root(&self, root: &Path) -> Option<Target> {
169 self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next() 170 self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next()
170 } 171 }
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
new file mode 100644
index 000000000..3b1e07149
--- /dev/null
+++ b/crates/ra_project_model/src/lib.rs
@@ -0,0 +1,130 @@
1mod cargo_workspace;
2mod sysroot;
3
4use std::path::{Path, PathBuf};
5
6use failure::bail;
7use rustc_hash::FxHashMap;
8
9use ra_db::{CrateGraph, FileId};
10
11pub use crate::{
12 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind},
13 sysroot::Sysroot,
14};
15
16// TODO use proper error enum
17pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
18
19#[derive(Debug, Clone)]
20pub struct ProjectWorkspace {
21 pub cargo: CargoWorkspace,
22 pub sysroot: Sysroot,
23}
24
25impl ProjectWorkspace {
26 pub fn discover(path: &Path) -> Result<ProjectWorkspace> {
27 let cargo_toml = find_cargo_toml(path)?;
28 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?;
29 let sysroot = Sysroot::discover(&cargo_toml)?;
30 let res = ProjectWorkspace { cargo, sysroot };
31 Ok(res)
32 }
33
34 pub fn to_crate_graph(&self, load: &mut dyn FnMut(&Path) -> Option<FileId>) -> CrateGraph {
35 let mut crate_graph = CrateGraph::default();
36 let mut sysroot_crates = FxHashMap::default();
37 for krate in self.sysroot.crates() {
38 if let Some(file_id) = load(krate.root(&self.sysroot)) {
39 sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id));
40 }
41 }
42 for from in self.sysroot.crates() {
43 for to in from.deps(&self.sysroot) {
44 let name = to.name(&self.sysroot);
45 if let (Some(&from), Some(&to)) =
46 (sysroot_crates.get(&from), sysroot_crates.get(&to))
47 {
48 if let Err(_) = crate_graph.add_dep(from, name.into(), to) {
49 log::error!("cyclic dependency between sysroot crates")
50 }
51 }
52 }
53 }
54
55 let libstd = self.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it));
56
57 let mut pkg_to_lib_crate = FxHashMap::default();
58 let mut pkg_crates = FxHashMap::default();
59 // Next, create crates for each package, target pair
60 for pkg in self.cargo.packages() {
61 let mut lib_tgt = None;
62 for tgt in pkg.targets(&self.cargo) {
63 let root = tgt.root(&self.cargo);
64 if let Some(file_id) = load(root) {
65 let crate_id = crate_graph.add_crate_root(file_id);
66 if tgt.kind(&self.cargo) == TargetKind::Lib {
67 lib_tgt = Some(crate_id);
68 pkg_to_lib_crate.insert(pkg, crate_id);
69 }
70 pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
71 }
72 }
73
74 // Set deps to the std and to the lib target of the current package
75 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
76 if let Some(to) = lib_tgt {
77 if to != from {
78 if let Err(_) = crate_graph.add_dep(from, pkg.name(&self.cargo).into(), to)
79 {
80 log::error!(
81 "cyclic dependency between targets of {}",
82 pkg.name(&self.cargo)
83 )
84 }
85 }
86 }
87 if let Some(std) = libstd {
88 if let Err(_) = crate_graph.add_dep(from, "std".into(), std) {
89 log::error!("cyclic dependency on std for {}", pkg.name(&self.cargo))
90 }
91 }
92 }
93 }
94
95 // Now add a dep ednge from all targets of upstream to the lib
96 // target of downstream.
97 for pkg in self.cargo.packages() {
98 for dep in pkg.dependencies(&self.cargo) {
99 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
100 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
101 if let Err(_) = crate_graph.add_dep(from, dep.name.clone().into(), to) {
102 log::error!(
103 "cyclic dependency {} -> {}",
104 pkg.name(&self.cargo),
105 dep.pkg.name(&self.cargo)
106 )
107 }
108 }
109 }
110 }
111 }
112
113 crate_graph
114 }
115}
116
117fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
118 if path.ends_with("Cargo.toml") {
119 return Ok(path.to_path_buf());
120 }
121 let mut curr = Some(path);
122 while let Some(path) = curr {
123 let candidate = path.join("Cargo.toml");
124 if candidate.exists() {
125 return Ok(candidate);
126 }
127 curr = path.parent();
128 }
129 bail!("can't find Cargo.toml at {}", path.display())
130}
diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_project_model/src/sysroot.rs
index 49210ac7a..8b87aa7bd 100644
--- a/crates/ra_lsp_server/src/project_model/sysroot.rs
+++ b/crates/ra_project_model/src/sysroot.rs
@@ -3,7 +3,6 @@ use std::{
3 process::Command, 3 process::Command,
4}; 4};
5 5
6use ra_syntax::SmolStr;
7use ra_arena::{Arena, RawId, impl_arena_id}; 6use ra_arena::{Arena, RawId, impl_arena_id};
8 7
9use crate::Result; 8use crate::Result;
@@ -19,21 +18,21 @@ impl_arena_id!(SysrootCrate);
19 18
20#[derive(Debug, Clone)] 19#[derive(Debug, Clone)]
21struct SysrootCrateData { 20struct SysrootCrateData {
22 name: SmolStr, 21 name: String,
23 root: PathBuf, 22 root: PathBuf,
24 deps: Vec<SysrootCrate>, 23 deps: Vec<SysrootCrate>,
25} 24}
26 25
27impl Sysroot { 26impl Sysroot {
28 pub(crate) fn std(&self) -> Option<SysrootCrate> { 27 pub fn std(&self) -> Option<SysrootCrate> {
29 self.by_name("std") 28 self.by_name("std")
30 } 29 }
31 30
32 pub(crate) fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a { 31 pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a {
33 self.crates.iter().map(|(id, _data)| id) 32 self.crates.iter().map(|(id, _data)| id)
34 } 33 }
35 34
36 pub(super) fn discover(cargo_toml: &Path) -> Result<Sysroot> { 35 pub fn discover(cargo_toml: &Path) -> Result<Sysroot> {
37 let rustc_output = Command::new("rustc") 36 let rustc_output = Command::new("rustc")
38 .current_dir(cargo_toml.parent().unwrap()) 37 .current_dir(cargo_toml.parent().unwrap())
39 .args(&["--print", "sysroot"]) 38 .args(&["--print", "sysroot"])
@@ -80,16 +79,16 @@ impl Sysroot {
80} 79}
81 80
82impl SysrootCrate { 81impl SysrootCrate {
83 pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr { 82 pub fn name(self, sysroot: &Sysroot) -> &str {
84 &sysroot.crates[self].name 83 &sysroot.crates[self].name
85 } 84 }
86 pub(crate) fn root(self, sysroot: &Sysroot) -> &Path { 85 pub fn root(self, sysroot: &Sysroot) -> &Path {
87 sysroot.crates[self].root.as_path() 86 sysroot.crates[self].root.as_path()
88 } 87 }
89 pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path { 88 pub fn root_dir(self, sysroot: &Sysroot) -> &Path {
90 self.root(sysroot).parent().unwrap() 89 self.root(sysroot).parent().unwrap()
91 } 90 }
92 pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator<Item = SysrootCrate> + 'a { 91 pub fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator<Item = SysrootCrate> + 'a {
93 sysroot.crates[self].deps.iter().map(|&it| it) 92 sysroot.crates[self].deps.iter().map(|&it| it)
94 } 93 }
95} 94}
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 0ec8492aa..7c7a85a75 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -15,7 +15,7 @@ drop_bomb = "0.1.4"
15parking_lot = "0.7.0" 15parking_lot = "0.7.0"
16rowan = "0.3.3" 16rowan = "0.3.3"
17 17
18# ideally, `serde` should be enabled by `ra_lsp_serder`, but we enable it here 18# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
19# to reduce number of compilations 19# to reduce number of compilations
20text_unit = { version = "0.1.6", features = ["serde"] } 20text_unit = { version = "0.1.6", features = ["serde"] }
21smol_str = { version = "0.1.9", features = ["serde"] } 21smol_str = { version = "0.1.9", features = ["serde"] }