Skip to content

Commit afe122a

Browse files
committed
Detect file dependency cycles
1 parent fe7eca9 commit afe122a

2 files changed

Lines changed: 33 additions & 11 deletions

File tree

lib/ModuleName.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
let separator = "."
2-
let of_filepath = Fun.compose Filename.basename Filename.chop_extension
2+
let of_filepath = Fun.compose Filename.basename Filename.remove_extension

lib/Preprocessor.ml

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,36 @@ module DependencyGraph = struct
215215

216216
type expansion_result = expansion_state Error.attempt
217217

218+
(** Returns true if l depends on r in the given fully expanded graph, false
219+
otherwise *)
220+
let depends expanded_graph l r =
221+
match BatMap.String.find_opt l expanded_graph with
222+
| None -> false
223+
| Some deps -> BatSet.String.mem (ModuleName.of_filepath r) deps
224+
225+
let no_cycles graph =
226+
let module Map = BatMap.String in
227+
if
228+
BatEnum.fold
229+
(fun has_cycle k ->
230+
if depends graph k k then (
231+
Logger.simply_error @@ "File " ^ k ^ " depends on itself";
232+
true)
233+
else has_cycle)
234+
false
235+
@@ Map.keys graph
236+
then exit 1;
237+
graph
238+
218239
let expand graph : t Error.attempt =
219240
let module FT = BatFingerTree in
220241
let module Set = BatSet.String in
221242
let module Map = BatMap.String in
243+
let atom_to_filepath =
244+
Map.of_enum
245+
@@ BatEnum.map (fun k -> (ModuleName.of_filepath k, k))
246+
@@ Map.keys graph
247+
in
222248
let bridge_ancestor relatives node graph =
223249
if Set.is_empty relatives then graph
224250
else Map.modify_def Set.empty node (Set.union relatives) graph
@@ -230,9 +256,12 @@ module DependencyGraph = struct
230256
| Some (more, current) when Set.mem current visited ->
231257
go @@ ok { visited; forward; next = more; backward }
232258
| Some (more, current) -> (
233-
(* TODO: check for cycles *)
234259
let visited = Set.add current visited in
235-
match Map.find_opt current forward with
260+
match
261+
Map.find_opt
262+
(Map.find_default current current atom_to_filepath)
263+
forward
264+
with
236265
| None -> go @@ ok { visited; forward; next = more; backward }
237266
| Some children ->
238267
let parents =
@@ -257,7 +286,7 @@ module DependencyGraph = struct
257286
})
258287
| None -> Ok { visited; forward; next; backward }
259288
in
260-
Error.map (fun { forward; _ } -> forward)
289+
Error.map (fun { forward; _ } -> no_cycles forward)
261290
@@ go
262291
@@ Error.ok
263292
{
@@ -267,13 +296,6 @@ module DependencyGraph = struct
267296
next = BatFingerTree.of_enum (BatMap.String.keys graph);
268297
}
269298

270-
(** Returns true if l depends on r in the given fully expanded graph, false
271-
otherwise *)
272-
let depends expanded_graph l r =
273-
match BatMap.String.find_opt l expanded_graph with
274-
| None -> false
275-
| Some deps -> BatSet.String.mem (ModuleName.of_filepath r) deps
276-
277299
let sort (expanded_graph : t) (files : string list) =
278300
let compare_files l r =
279301
if depends expanded_graph l r then 1

0 commit comments

Comments
 (0)