diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-12-22 14:48:18 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-12-22 14:48:18 +0000 |
commit | d77520fde3c953968beb09a3da80a0e7b17bbc04 (patch) | |
tree | d9dbc6bca589fec7ffe19fcc502eb9712d0866ed /crates/ra_db/src | |
parent | 8fed875c90796b2390f5b966c3f1eca536661af1 (diff) | |
parent | c0add813e9005a3356c7a8062c9a9c8f8bca6895 (diff) |
Merge #310
310: When constructing a crate graph, detect and forbid cycles. r=matklad a=gfreezy
fixed #300
Co-authored-by: gfreezy <[email protected]>
Diffstat (limited to 'crates/ra_db/src')
-rw-r--r-- | crates/ra_db/src/input.rs | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index ead8dfe48..7c3dd9296 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -7,11 +7,13 @@ | |||
7 | /// actual IO is done and lowered to input. | 7 | /// actual IO is done and lowered to input. |
8 | use std::sync::Arc; | 8 | use std::sync::Arc; |
9 | 9 | ||
10 | use rustc_hash::{FxHashMap}; | ||
11 | use relative_path::RelativePathBuf; | 10 | use relative_path::RelativePathBuf; |
12 | use ra_syntax::SmolStr; | 11 | use rustc_hash::FxHashMap; |
13 | use salsa; | 12 | use salsa; |
14 | 13 | ||
14 | use ra_syntax::SmolStr; | ||
15 | use rustc_hash::FxHashSet; | ||
16 | |||
15 | /// `FileId` is an integer which uniquely identifies a file. File paths are | 17 | /// `FileId` is an integer which uniquely identifies a file. File paths are |
16 | /// messy and system-dependent, so most of the code should work directly with | 18 | /// messy and system-dependent, so most of the code should work directly with |
17 | /// `FileId`, without inspecting the path. The mapping between `FileId` and path | 19 | /// `FileId`, without inspecting the path. The mapping between `FileId` and path |
@@ -92,10 +94,11 @@ impl CrateGraph { | |||
92 | assert!(prev.is_none()); | 94 | assert!(prev.is_none()); |
93 | crate_id | 95 | crate_id |
94 | } | 96 | } |
95 | // FIXME: check that we don't have cycles here. | ||
96 | // Just a simple depth first search from `to` should work, | ||
97 | // the graph is small. | ||
98 | pub fn add_dep(&mut self, from: CrateId, name: SmolStr, to: CrateId) { | 97 | pub fn add_dep(&mut self, from: CrateId, name: SmolStr, to: CrateId) { |
98 | let mut visited = FxHashSet::default(); | ||
99 | if self.dfs_find(from, to, &mut visited) { | ||
100 | panic!("Cycle dependencies found.") | ||
101 | } | ||
99 | self.arena.get_mut(&from).unwrap().add_dep(name, to) | 102 | self.arena.get_mut(&from).unwrap().add_dep(name, to) |
100 | } | 103 | } |
101 | pub fn is_empty(&self) -> bool { | 104 | pub fn is_empty(&self) -> bool { |
@@ -117,6 +120,52 @@ impl CrateGraph { | |||
117 | ) -> impl Iterator<Item = &'a Dependency> + 'a { | 120 | ) -> impl Iterator<Item = &'a Dependency> + 'a { |
118 | self.arena[&crate_id].dependencies.iter() | 121 | self.arena[&crate_id].dependencies.iter() |
119 | } | 122 | } |
123 | fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool { | ||
124 | if !visited.insert(from) { | ||
125 | return false; | ||
126 | } | ||
127 | |||
128 | for dep in self.dependencies(from) { | ||
129 | let crate_id = dep.crate_id(); | ||
130 | if crate_id == target { | ||
131 | return true; | ||
132 | } | ||
133 | |||
134 | if self.dfs_find(target, crate_id, visited) { | ||
135 | return true; | ||
136 | } | ||
137 | } | ||
138 | return false; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | #[cfg(test)] | ||
143 | mod tests { | ||
144 | use super::{CrateGraph, FxHashMap, FileId, SmolStr}; | ||
145 | |||
146 | #[test] | ||
147 | #[should_panic] | ||
148 | fn it_should_painc_because_of_cycle_dependencies() { | ||
149 | let mut graph = CrateGraph::default(); | ||
150 | let crate1 = graph.add_crate_root(FileId(1u32)); | ||
151 | let crate2 = graph.add_crate_root(FileId(2u32)); | ||
152 | let crate3 = graph.add_crate_root(FileId(3u32)); | ||
153 | graph.add_dep(crate1, SmolStr::new("crate2"), crate2); | ||
154 | graph.add_dep(crate2, SmolStr::new("crate3"), crate3); | ||
155 | graph.add_dep(crate3, SmolStr::new("crate1"), crate1); | ||
156 | } | ||
157 | |||
158 | #[test] | ||
159 | fn it_works() { | ||
160 | let mut graph = CrateGraph { | ||
161 | arena: FxHashMap::default(), | ||
162 | }; | ||
163 | let crate1 = graph.add_crate_root(FileId(1u32)); | ||
164 | let crate2 = graph.add_crate_root(FileId(2u32)); | ||
165 | let crate3 = graph.add_crate_root(FileId(3u32)); | ||
166 | graph.add_dep(crate1, SmolStr::new("crate2"), crate2); | ||
167 | graph.add_dep(crate2, SmolStr::new("crate3"), crate3); | ||
168 | } | ||
120 | } | 169 | } |
121 | 170 | ||
122 | salsa::query_group! { | 171 | salsa::query_group! { |