Skip to content

Commit 0aa747b

Browse files
committed
fix: use warning mechanism for duplicate deps warning
Signed-off-by: Sachin Beniwal <s474996633@gmail.com>
1 parent b4e845a commit 0aa747b

4 files changed

Lines changed: 327 additions & 3 deletions

File tree

src/dune_lang/package.ml

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
1624
type 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
5564
let set_inside_opam_dir t ~dir = { t with opam_file = Name.file t.id.name ~dir }
5665
let set_version_and_info t ~version ~info = { t with version; info }
5766
let exclusive_dir t = t.exclusive_dir
67+
let duplicate_dep_warnings t = t.duplicate_dep_warnings
5868

5969
let 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
;;

src/dune_lang/package.mli

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,13 @@ val create
7474
-> t
7575

7676
val original_opam_file : t -> original_opam_file option
77+
78+
module Duplicate_dep_warning : sig
79+
type t =
80+
{ loc : Loc.t
81+
; dep_string : string
82+
; field_name : string
83+
}
84+
end
85+
86+
val duplicate_dep_warnings : t -> Duplicate_dep_warning.t list

src/dune_rules/gen_rules.ml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,11 @@ let missing_project_name =
335335
~since:(3, 11)
336336
;;
337337

338+
(* Warn about duplicate dependencies in package definitions *)
339+
let duplicate_deps =
340+
Warning.make ~default:(fun _ -> `Enabled) ~name:"duplicate_deps" ~since:(3, 18)
341+
;;
342+
338343
(* To be called once per project, when we are generating the rules for the root
339344
directory of the project *)
340345
let gen_project_rules =
@@ -386,6 +391,28 @@ let gen_project_rules =
386391
to your dune-project file to make sure that $ dune subst works in \
387392
release or pinned builds"
388393
]))
394+
and+ () =
395+
(* Emit warnings for duplicate dependencies in packages *)
396+
let packages = Dune_project.packages project in
397+
Dune_lang.Package.Name.Map.values packages
398+
|> Memo.parallel_iter ~f:(fun pkg ->
399+
Dune_lang.Package.duplicate_dep_warnings pkg
400+
|> Memo.parallel_iter
401+
~f:(fun (warning : Dune_lang.Package.Duplicate_dep_warning.t) ->
402+
Warning_emit.emit
403+
duplicate_deps
404+
(Warning_emit.Context.project project)
405+
(fun () ->
406+
Memo.return
407+
(User_message.make
408+
~loc:warning.loc
409+
[ Pp.textf
410+
"Duplicate dependency on package %s in '%s' field. If you \
411+
want to specify multiple constraints, combine them using \
412+
(and ...)."
413+
warning.dep_string
414+
warning.field_name
415+
]))))
389416
in
390417
()
391418
in

0 commit comments

Comments
 (0)