aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-02-06 21:54:33 +0000
committerFlorian Diebold <[email protected]>2019-02-09 10:15:25 +0000
commitddbf43b630fa8159ab2ea5e959393bff44e0c73b (patch)
treef5ee2104b2990086a3ba7a51847be912ce293a7d /crates
parentfcd615e4b76264b4fff7b5be454787bb6a4252ea (diff)
Move crate graph generation to ra_project_model
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_db/src/input.rs19
-rw-r--r--crates/ra_lsp_server/src/server_world.rs85
-rw-r--r--crates/ra_project_model/Cargo.toml4
-rw-r--r--crates/ra_project_model/src/lib.rs88
4 files changed, 113 insertions, 83 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/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};
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,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" 10log = "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"
25cargo_metadata = "0.7.0" 25cargo_metadata = "0.7.0"
26 26
27ra_arena = { path = "../ra_arena" } 27ra_arena = { path = "../ra_arena" }
28ra_db = { path = "../ra_db" }
29ra_vfs = { path = "../ra_vfs" }
28 30
29[dev-dependencies] 31[dev-dependencies]
30test_utils = { path = "../test_utils" } 32test_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;
4use std::path::{Path, PathBuf}; 4use std::path::{Path, PathBuf};
5 5
6use failure::bail; 6use failure::bail;
7use rustc_hash::FxHashMap;
8
9use ra_db::{CrateGraph, FileId};
10use ra_vfs::Vfs;
7 11
8pub use crate::{ 12pub 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
32fn find_cargo_toml(path: &Path) -> Result<PathBuf> { 120fn find_cargo_toml(path: &Path) -> Result<PathBuf> {