diff options
-rw-r--r-- | Cargo.lock | 3 | ||||
-rw-r--r-- | crates/ra_db/src/input.rs | 19 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/server_world.rs | 85 | ||||
-rw-r--r-- | crates/ra_project_model/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 88 |
5 files changed, 116 insertions, 83 deletions
diff --git a/Cargo.lock b/Cargo.lock index 2f6a132a5..3f0334f95 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1052,7 +1052,10 @@ dependencies = [ | |||
1052 | "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | 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)", | 1053 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", |
1054 | "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | 1054 | "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", |
1055 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||
1055 | "ra_arena 0.1.0", | 1056 | "ra_arena 0.1.0", |
1057 | "ra_db 0.1.0", | ||
1058 | "ra_vfs 0.1.0", | ||
1056 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1059 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1057 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | 1060 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", |
1058 | "test_utils 0.1.0", | 1061 | "test_utils 0.1.0", |
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/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 02f2a37a8..23270d0aa 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,10 @@ 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 | for ws in workspaces.iter() { | 61 | for ws in workspaces.iter() { |
62 | // First, load std | 62 | crate_graph.extend(ws.to_crate_graph(&mut vfs)); |
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 | } | 63 | } |
143 | change.set_crate_graph(crate_graph); | 64 | change.set_crate_graph(crate_graph); |
144 | 65 | ||
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 5215e5232..f65aabad7 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml | |||
@@ -7,7 +7,7 @@ authors = ["Aleksey Kladov <[email protected]>"] | |||
7 | [dependencies] | 7 | [dependencies] |
8 | # itertools = "0.8.0" | 8 | # itertools = "0.8.0" |
9 | # join_to_string = "0.1.3" | 9 | # join_to_string = "0.1.3" |
10 | # log = "0.4.5" | 10 | log = "0.4.5" |
11 | # relative-path = "0.4.0" | 11 | # relative-path = "0.4.0" |
12 | # rayon = "1.0.2" | 12 | # rayon = "1.0.2" |
13 | # fst = "0.3.1" | 13 | # fst = "0.3.1" |
@@ -25,6 +25,8 @@ walkdir = "2.2.7" | |||
25 | cargo_metadata = "0.7.0" | 25 | cargo_metadata = "0.7.0" |
26 | 26 | ||
27 | ra_arena = { path = "../ra_arena" } | 27 | ra_arena = { path = "../ra_arena" } |
28 | ra_db = { path = "../ra_db" } | ||
29 | ra_vfs = { path = "../ra_vfs" } | ||
28 | 30 | ||
29 | [dev-dependencies] | 31 | [dev-dependencies] |
30 | test_utils = { path = "../test_utils" } | 32 | test_utils = { path = "../test_utils" } |
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 3a7bbace7..30612ac84 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -4,6 +4,10 @@ mod sysroot; | |||
4 | use std::path::{Path, PathBuf}; | 4 | use std::path::{Path, PathBuf}; |
5 | 5 | ||
6 | use failure::bail; | 6 | use failure::bail; |
7 | use rustc_hash::FxHashMap; | ||
8 | |||
9 | use ra_db::{CrateGraph, FileId}; | ||
10 | use ra_vfs::Vfs; | ||
7 | 11 | ||
8 | pub use crate::{ | 12 | pub use crate::{ |
9 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, | 13 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, |
@@ -27,6 +31,90 @@ impl ProjectWorkspace { | |||
27 | let res = ProjectWorkspace { cargo, sysroot }; | 31 | let res = ProjectWorkspace { cargo, sysroot }; |
28 | Ok(res) | 32 | Ok(res) |
29 | } | 33 | } |
34 | |||
35 | pub fn to_crate_graph(&self, vfs: &mut Vfs) -> CrateGraph { | ||
36 | let mut crate_graph = CrateGraph::default(); | ||
37 | let mut sysroot_crates = FxHashMap::default(); | ||
38 | for krate in self.sysroot.crates() { | ||
39 | if let Some(file_id) = vfs.load(krate.root(&self.sysroot)) { | ||
40 | let file_id = FileId(file_id.0.into()); | ||
41 | sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); | ||
42 | } | ||
43 | } | ||
44 | for from in self.sysroot.crates() { | ||
45 | for to in from.deps(&self.sysroot) { | ||
46 | let name = to.name(&self.sysroot); | ||
47 | if let (Some(&from), Some(&to)) = | ||
48 | (sysroot_crates.get(&from), sysroot_crates.get(&to)) | ||
49 | { | ||
50 | if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { | ||
51 | log::error!("cyclic dependency between sysroot crates") | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | |||
57 | let libstd = self.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it)); | ||
58 | |||
59 | let mut pkg_to_lib_crate = FxHashMap::default(); | ||
60 | let mut pkg_crates = FxHashMap::default(); | ||
61 | // Next, create crates for each package, target pair | ||
62 | for pkg in self.cargo.packages() { | ||
63 | let mut lib_tgt = None; | ||
64 | for tgt in pkg.targets(&self.cargo) { | ||
65 | let root = tgt.root(&self.cargo); | ||
66 | if let Some(file_id) = vfs.load(root) { | ||
67 | let file_id = FileId(file_id.0.into()); | ||
68 | let crate_id = crate_graph.add_crate_root(file_id); | ||
69 | if tgt.kind(&self.cargo) == TargetKind::Lib { | ||
70 | lib_tgt = Some(crate_id); | ||
71 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
72 | } | ||
73 | pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | // Set deps to the std and to the lib target of the current package | ||
78 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
79 | if let Some(to) = lib_tgt { | ||
80 | if to != from { | ||
81 | if let Err(_) = crate_graph.add_dep(from, pkg.name(&self.cargo).into(), to) | ||
82 | { | ||
83 | log::error!( | ||
84 | "cyclic dependency between targets of {}", | ||
85 | pkg.name(&self.cargo) | ||
86 | ) | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | if let Some(std) = libstd { | ||
91 | if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { | ||
92 | log::error!("cyclic dependency on std for {}", pkg.name(&self.cargo)) | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | |||
98 | // Now add a dep ednge from all targets of upstream to the lib | ||
99 | // target of downstream. | ||
100 | for pkg in self.cargo.packages() { | ||
101 | for dep in pkg.dependencies(&self.cargo) { | ||
102 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | ||
103 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
104 | if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) { | ||
105 | log::error!( | ||
106 | "cyclic dependency {} -> {}", | ||
107 | pkg.name(&self.cargo), | ||
108 | dep.pkg.name(&self.cargo) | ||
109 | ) | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | crate_graph | ||
117 | } | ||
30 | } | 118 | } |
31 | 119 | ||
32 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { | 120 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { |