diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-09 10:21:13 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-09 10:21:13 +0000 |
commit | d0a32627a741826502692f2c3de71512b7ec23cf (patch) | |
tree | ee3cef56bd9738f5c3b98caae9b8ce1b8dbf401f /crates | |
parent | 34398a8756b56c323d3b4b2ef32fbca32d88a105 (diff) | |
parent | e91a46eb0c4a355af25656d77dead55c2e29258e (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]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_db/src/input.rs | 19 | ||||
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/project_model.rs | 42 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/server_world.rs | 89 | ||||
-rw-r--r-- | crates/ra_project_model/Cargo.toml | 21 | ||||
-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.rs | 130 | ||||
-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.toml | 2 |
9 files changed, 197 insertions, 138 deletions
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" | |||
19 | lsp-types = "0.55.0" | 19 | lsp-types = "0.55.0" |
20 | walkdir = "2.2.7" | 20 | walkdir = "2.2.7" |
21 | im = "12.0.0" | 21 | im = "12.0.0" |
22 | cargo_metadata = "0.7.0" | ||
23 | rustc-hash = "1.0" | 22 | rustc-hash = "1.0" |
24 | parking_lot = "0.7.0" | 23 | parking_lot = "0.7.0" |
25 | 24 | ||
@@ -30,6 +29,7 @@ ra_ide_api = { path = "../ra_ide_api" } | |||
30 | ra_arena = { path = "../ra_arena" } | 29 | ra_arena = { path = "../ra_arena" } |
31 | gen_lsp_server = { path = "../gen_lsp_server" } | 30 | gen_lsp_server = { path = "../gen_lsp_server" } |
32 | ra_vfs = { path = "../ra_vfs" } | 31 | ra_vfs = { path = "../ra_vfs" } |
32 | ra_project_model = { path = "../ra_project_model" } | ||
33 | 33 | ||
34 | [dev-dependencies] | 34 | [dev-dependencies] |
35 | tempfile = "3" | 35 | tempfile = "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 @@ | |||
1 | mod cargo_workspace; | 1 | use std::path::PathBuf; |
2 | mod sysroot; | ||
3 | 2 | ||
4 | use std::path::{Path, PathBuf}; | ||
5 | |||
6 | use failure::bail; | ||
7 | use thread_worker::{WorkerHandle, Worker}; | 3 | use thread_worker::{WorkerHandle, Worker}; |
8 | 4 | ||
9 | use crate::Result; | 5 | use crate::Result; |
10 | 6 | ||
11 | pub use crate::project_model::{ | 7 | pub 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)] | ||
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 | |||
32 | pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) { | 11 | pub 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 | |||
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 | } | ||
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 | }; |
11 | use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; | 11 | use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; |
12 | use rustc_hash::FxHashMap; | ||
13 | use relative_path::RelativePathBuf; | 12 | use relative_path::RelativePathBuf; |
14 | use parking_lot::RwLock; | 13 | use parking_lot::RwLock; |
15 | use failure::format_err; | 14 | use failure::format_err; |
16 | 15 | ||
17 | use crate::{ | 16 | use 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] | ||
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" } | ||
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 @@ | |||
1 | use std::path::{Path, PathBuf}; | 1 | use std::path::{Path, PathBuf}; |
2 | 2 | ||
3 | use cargo_metadata::{MetadataCommand, CargoOpt}; | 3 | use cargo_metadata::{MetadataCommand, CargoOpt}; |
4 | use ra_syntax::SmolStr; | ||
5 | use ra_arena::{Arena, RawId, impl_arena_id}; | 4 | use ra_arena::{Arena, RawId, impl_arena_id}; |
6 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
7 | use failure::format_err; | 6 | use failure::format_err; |
8 | 7 | ||
9 | use crate::Result; | 8 | use 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)] |
33 | struct PackageData { | 32 | struct 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)] |
42 | pub struct PackageDependency { | 41 | pub 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)] |
48 | struct TargetData { | 47 | struct 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 @@ | |||
1 | mod cargo_workspace; | ||
2 | mod sysroot; | ||
3 | |||
4 | use std::path::{Path, PathBuf}; | ||
5 | |||
6 | use failure::bail; | ||
7 | use rustc_hash::FxHashMap; | ||
8 | |||
9 | use ra_db::{CrateGraph, FileId}; | ||
10 | |||
11 | pub use crate::{ | ||
12 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, | ||
13 | sysroot::Sysroot, | ||
14 | }; | ||
15 | |||
16 | // TODO use proper error enum | ||
17 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | ||
18 | |||
19 | #[derive(Debug, Clone)] | ||
20 | pub struct ProjectWorkspace { | ||
21 | pub cargo: CargoWorkspace, | ||
22 | pub sysroot: Sysroot, | ||
23 | } | ||
24 | |||
25 | impl 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 | |||
117 | fn 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 | ||
6 | use ra_syntax::SmolStr; | ||
7 | use ra_arena::{Arena, RawId, impl_arena_id}; | 6 | use ra_arena::{Arena, RawId, impl_arena_id}; |
8 | 7 | ||
9 | use crate::Result; | 8 | use crate::Result; |
@@ -19,21 +18,21 @@ impl_arena_id!(SysrootCrate); | |||
19 | 18 | ||
20 | #[derive(Debug, Clone)] | 19 | #[derive(Debug, Clone)] |
21 | struct SysrootCrateData { | 20 | struct 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 | ||
27 | impl Sysroot { | 26 | impl 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 | ||
82 | impl SysrootCrate { | 81 | impl 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" | |||
15 | parking_lot = "0.7.0" | 15 | parking_lot = "0.7.0" |
16 | rowan = "0.3.3" | 16 | rowan = "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 |
20 | text_unit = { version = "0.1.6", features = ["serde"] } | 20 | text_unit = { version = "0.1.6", features = ["serde"] } |
21 | smol_str = { version = "0.1.9", features = ["serde"] } | 21 | smol_str = { version = "0.1.9", features = ["serde"] } |