@@ -13,6 +13,14 @@ type original_opam_file =
1313 ; contents : string
1414 }
1515
16+ module Duplicate_dep_warning = struct
17+ type t =
18+ { loc : Loc .t
19+ ; dep_string : string
20+ ; field_name : string
21+ }
22+ end
23+
1624type t =
1725 { id : Id .t
1826 ; opam_file : Path.Source .t
@@ -31,6 +39,7 @@ type t =
3139 ; allow_empty : bool
3240 ; original_opam_file : original_opam_file option
3341 ; exclusive_dir : (Loc .t * Path.Source .t ) option
42+ ; duplicate_dep_warnings : Duplicate_dep_warning .t list
3443 }
3544
3645(* Package name are globally unique, so we can reasonably expect that there will
@@ -55,6 +64,7 @@ let original_opam_file t = t.original_opam_file
5564let set_inside_opam_dir t ~dir = { t with opam_file = Name. file t.id.name ~dir }
5665let set_version_and_info t ~version ~info = { t with version; info }
5766let exclusive_dir t = t.exclusive_dir
67+ let duplicate_dep_warnings t = t.duplicate_dep_warnings
5868
5969let encode
6070 (name : Name.t )
@@ -75,6 +85,7 @@ let encode
7585 ; opam_file = _
7686 ; original_opam_file = _
7787 ; exclusive_dir
88+ ; duplicate_dep_warnings = _
7889 }
7990 =
8091 let open Encoder in
@@ -121,6 +132,25 @@ let decode =
121132 ; Pp. textf " - %s" (print_value loc2)
122133 ]
123134 in
135+ let collect_duplicate_deps deps field_name =
136+ let warnings, _ =
137+ List. fold_left deps ~init: ([] , [] ) ~f: (fun (warnings , seen ) (loc , dep ) ->
138+ let is_duplicate =
139+ List. exists seen ~f: (fun (_ , seen_dep ) ->
140+ Package_name. equal
141+ dep.Package_dependency. name
142+ seen_dep.Package_dependency. name)
143+ in
144+ if is_duplicate
145+ then (
146+ let dep_sexp = Package_dependency. encode dep in
147+ let dep_string = Dune_sexp. to_string dep_sexp in
148+ let warning = { Duplicate_dep_warning. loc; dep_string; field_name } in
149+ warning :: warnings, (loc, dep) :: seen)
150+ else warnings, (loc, dep) :: seen)
151+ in
152+ warnings
153+ in
124154 fun ~dir ->
125155 fields
126156 @@ let * version = Syntax. get_exn Stanza. syntax in
@@ -130,9 +160,12 @@ let decode =
130160 and + description = field_o " description" string
131161 and + version =
132162 field_o " version" (Syntax. since Stanza. syntax (2 , 5 ) >>> Package_version. decode)
133- and + depends = field ~default: [] " depends" (repeat Package_dependency. decode)
134- and + conflicts = field ~default: [] " conflicts" (repeat Package_dependency. decode)
135- and + depopts = field ~default: [] " depopts" (repeat Package_dependency. decode)
163+ and + depends_with_locs =
164+ field ~default: [] " depends" (repeat (located Package_dependency. decode))
165+ and + conflicts_with_locs =
166+ field ~default: [] " conflicts" (repeat (located Package_dependency. decode))
167+ and + depopts_with_locs =
168+ field ~default: [] " depopts" (repeat (located Package_dependency. decode))
136169 and + info = Package_info. decode ~since: (2 , 0 ) ()
137170 and + tags = field " tags" (enter (repeat string )) ~default: []
138171 and + exclusive_dir =
@@ -161,6 +194,16 @@ let decode =
161194 and + allow_empty = field_b " allow_empty" ~check: (Syntax. since Stanza. syntax (3 , 0 ))
162195 and + lang_version = Syntax. get_exn Stanza. syntax in
163196 let allow_empty = lang_version < (3 , 0 ) || allow_empty in
197+ let duplicate_dep_warnings =
198+ List. concat
199+ [ collect_duplicate_deps depends_with_locs " depends"
200+ ; collect_duplicate_deps conflicts_with_locs " conflicts"
201+ ; collect_duplicate_deps depopts_with_locs " depopts"
202+ ]
203+ in
204+ let depends = List. map ~f: snd depends_with_locs in
205+ let conflicts = List. map ~f: snd conflicts_with_locs in
206+ let depopts = List. map ~f: snd depopts_with_locs in
164207 let id = Id. create ~name ~dir in
165208 let opam_file = Name. file id.name ~dir: id.dir in
166209 { id
@@ -180,6 +223,7 @@ let decode =
180223 ; opam_file
181224 ; original_opam_file = None
182225 ; exclusive_dir
226+ ; duplicate_dep_warnings
183227 }
184228;;
185229
@@ -208,6 +252,7 @@ let to_dyn
208252 ; opam_file = _
209253 ; original_opam_file = _
210254 ; exclusive_dir = _
255+ ; duplicate_dep_warnings = _
211256 }
212257 =
213258 let open Dyn in
@@ -272,5 +317,6 @@ let create
272317 ; original_opam_file
273318 ; exclusive_dir =
274319 Option. map contents_basename ~f: (fun (loc , s ) -> loc, Path.Source. relative dir s)
320+ ; duplicate_dep_warnings = []
275321 }
276322;;
0 commit comments