Warn if duplicate key is found in struct (#9452)

Warning is the preferable solution for this, if we raise instead then it
is likely that there are some existing libraries that use duplicate
struct keys that will break.
This commit is contained in:
Gary Rennie
2019-10-28 20:01:31 -05:00
committed by Andrea Leopardi
parent a570d919da
commit 6a8fa2c7ef
2 changed files with 28 additions and 0 deletions
+16
View File
@@ -94,6 +94,9 @@ defmodule Kernel.Utils do
fields = :lists.map(mapper, fields)
enforce_keys = List.wrap(Module.get_attribute(module, :enforce_keys))
# TODO: Make it raise on v2.0
warn_on_duplicate_struct_key(:lists.keysort(1, fields))
foreach = fn
key when is_atom(key) ->
:ok
@@ -108,6 +111,19 @@ defmodule Kernel.Utils do
{struct, enforce_keys, Module.get_attribute(module, :derive)}
end
defp warn_on_duplicate_struct_key([]) do
:ok
end
defp warn_on_duplicate_struct_key([{key, _} | [{key, _} | _] = rest]) do
IO.warn("duplicate key #{inspect(key)} found in struct")
warn_on_duplicate_struct_key(rest)
end
defp warn_on_duplicate_struct_key([_ | rest]) do
warn_on_duplicate_struct_key(rest)
end
@doc """
Announcing callback for defstruct.
"""
@@ -1770,6 +1770,18 @@ defmodule Kernel.WarningTest do
end
end
test "defstruct warns with duplicate keys" do
assert capture_err(fn ->
Code.eval_string("""
defmodule TestMod do
defstruct [:foo, :foo, :bar]
end
""")
end) =~ "duplicate key :foo found in struct"
after
purge(TestMod)
end
defp purge(list) when is_list(list) do
Enum.each(list, &purge/1)
end