Current section
Files
Jump to
Current section
Files
lib/rule/no_explicit_min_reduce.ex
defmodule Credence.Rule.NoExplicitMinReduce do
@moduledoc "Flags explicit min-reduction patterns inside Enum.reduce/3."
@behaviour Credence.Rule
alias Credence.Issue
@impl true
def check(ast, _opts) do
{_ast, issues} =
Macro.prewalk(ast, [], fn
{{:., _, _}, meta, args} = node, issues ->
if reduce_call?(node) and min_reduce_body?(args) do
issue = %Issue{
rule: :no_explicit_min_reduce,
severity: :warning,
message: "Explicit min-reduction detected. Prefer Enum.min/1 or Enum.min_by/2.",
meta: %{line: Keyword.get(meta, :line)}
}
{node, [issue | issues]}
else
{node, issues}
end
node, issues ->
{node, issues}
end)
Enum.reverse(issues)
end
defp reduce_call?({{:., _, [{:__aliases__, _, [:Enum]}, :reduce]}, _, _}), do: true
defp reduce_call?({{:., _, [:Enum, :reduce]}, _, _}), do: true
defp reduce_call?(_), do: false
defp min_reduce_body?([_enum, _acc, {:fn, _, [{:->, _, [_args, body]}]}]) do
explicit_min?(body)
end
defp min_reduce_body?(_), do: false
defp explicit_min?({:__block__, _, [body]}), do: explicit_min?(body)
defp explicit_min?({:min, _, [_, _]}), do: true
defp explicit_min?({:if, _, [{:<, _, [_, _]}, _opts]}), do: true
defp explicit_min?({:if, _, [{:<=, _, [_, _]}, _opts]}), do: true
defp explicit_min?(_), do: false
end