Skip to content

Commit 9da4ca0

Browse files
committed
Do not generate conflicting helpers in router
1 parent 95d4c8a commit 9da4ca0

File tree

2 files changed

+36
-15
lines changed

2 files changed

+36
-15
lines changed

lib/phoenix/router.ex

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,11 @@ defmodule Phoenix.Router do
433433

434434
# @anno is used here to avoid warnings if forwarding to root path
435435
match_404 =
436-
quote @anno do
437-
def __match_route__(_method, _path_info, _host) do
438-
:error
436+
unless Enum.any?(routes, &(&1.kind == :forward and &1.path == "/")) do
437+
quote @anno do
438+
def __match_route__(_method, _path_info, _host) do
439+
:error
440+
end
439441
end
440442
end
441443

lib/phoenix/router/helpers.ex

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,14 @@ defmodule Phoenix.Router.Helpers do
109109
end)
110110

111111
trailing_slash? = Enum.any?(routes, fn {route, _} -> route.trailing_slash? end)
112-
113112
groups = Enum.group_by(routes, fn {route, _exprs} -> route.helper end)
114113

115114
impls =
116-
for {_helper, group} <- groups,
117-
{route, exprs} <- Enum.sort_by(group, fn {_, exprs} -> length(exprs.binding) end),
115+
for {_helper, helper_routes} <- groups,
116+
{_, [{route, exprs} | _]} <-
117+
helper_routes
118+
|> Enum.group_by(fn {route, exprs} -> [length(exprs.binding) | route.plug_opts] end)
119+
|> Enum.sort(),
118120
do: defhelper(route, exprs)
119121

120122
catch_all = Enum.map(groups, &defhelper_catch_all/1)
@@ -143,8 +145,8 @@ defmodule Phoenix.Router.Helpers do
143145
end
144146

145147
defcatch_all = quote @anno do
146-
defcatch_all = fn helper, lengths, routes ->
147-
for length <- lengths do
148+
defcatch_all = fn helper, binding_lengths, params_lengths, routes ->
149+
for length <- binding_lengths do
148150
binding = List.duplicate({:_, [], nil}, length)
149151
arity = length + 2
150152

@@ -153,15 +155,20 @@ defmodule Phoenix.Router.Helpers do
153155
raise_route_error(unquote(helper), :path, unquote(arity), action, [])
154156
end
155157

156-
def unquote(:"#{helper}_path")(conn_or_endpoint, action, unquote_splicing(binding), params) do
157-
path(conn_or_endpoint, "/")
158-
raise_route_error(unquote(helper), :path, unquote(arity + 1), action, params)
159-
end
160-
161158
def unquote(:"#{helper}_url")(conn_or_endpoint, action, unquote_splicing(binding)) do
162159
url(conn_or_endpoint)
163160
raise_route_error(unquote(helper), :url, unquote(arity), action, [])
164161
end
162+
end
163+
164+
for length <- params_lengths do
165+
binding = List.duplicate({:_, [], nil}, length)
166+
arity = length + 2
167+
168+
def unquote(:"#{helper}_path")(conn_or_endpoint, action, unquote_splicing(binding), params) do
169+
path(conn_or_endpoint, "/")
170+
raise_route_error(unquote(helper), :path, unquote(arity + 1), action, params)
171+
end
165172

166173
def unquote(:"#{helper}_url")(conn_or_endpoint, action, unquote_splicing(binding), params) do
167174
url(conn_or_endpoint)
@@ -332,15 +339,27 @@ defmodule Phoenix.Router.Helpers do
332339
|> Enum.map(fn {routes, exprs} -> {routes.plug_opts, Enum.map(exprs.binding, &elem(&1, 0))} end)
333340
|> Enum.sort()
334341

335-
lengths =
342+
params_lengths =
336343
routes
337344
|> Enum.map(fn {_, bindings} -> length(bindings) end)
338345
|> Enum.uniq()
339346

347+
# Each helper defines catch alls like this:
348+
#
349+
# def helper_path(context, action, ...binding)
350+
# def helper_path(context, action, ...binding, params)
351+
#
352+
# Given the helpers are ordered by binding length, the additional
353+
# helper with param for a helper_path/n will always override the
354+
# binding for helper_path/n+1, so we skip those here to avoid warnings.
355+
binding_lengths =
356+
Enum.reject(params_lengths, &(&1 - 1 in params_lengths))
357+
340358
quote do
341359
defcatch_all.(
342360
unquote(helper),
343-
unquote(lengths),
361+
unquote(binding_lengths),
362+
unquote(params_lengths),
344363
unquote(Macro.escape(routes))
345364
)
346365
end

0 commit comments

Comments
 (0)