defmodule Credo.Code.Parameters do @moduledoc """ This module provides helper functions to analyse the parameters taken by a function. """ @def_ops [:def, :defp, :defmacro] @doc "Returns the parameter count for the given function's AST" def count(nil), do: 0 for op <- @def_ops do def count({unquote(op), _, arguments}) when is_list(arguments) do case List.first(arguments) do {_atom, _meta, nil} -> 0 {_atom, _meta, list} -> Enum.count(list) _ -> 0 end end end @doc "Returns the names of all parameters for the given function's AST" def names(nil), do: nil for op <- @def_ops do def names({unquote(op), _meta, arguments}) when is_list(arguments) do arguments |> List.first() |> get_param_names end end defp get_param_names({:when, _meta, arguments}) do arguments |> List.first() |> get_param_names end defp get_param_names(arguments) when is_tuple(arguments) do arguments |> Tuple.to_list() |> List.last() |> Enum.map(&get_param_name/1) |> Enum.reject(&is_nil/1) end defp get_param_name({:::, _, [var, _type]}) do get_param_name(var) end defp get_param_name({:<<>>, _, arguments}) do arguments |> Enum.map(&get_param_name/1) |> Enum.reject(&is_nil/1) end defp get_param_name({:=, _, arguments}) do arguments |> Enum.map(&get_param_name/1) |> Enum.reject(&is_nil/1) end defp get_param_name({:%, _, [{:__aliases__, _meta, _mod_list}, {:%{}, _meta2, arguments}]}) do get_param_name(arguments) end defp get_param_name({:%{}, _, arguments}) do get_param_name(arguments) end defp get_param_name({:\\, _, arguments}) do Enum.find_value(arguments, &get_param_name/1) end defp get_param_name(list) when is_list(list) do list |> Enum.map(fn {atom, tuple} when is_atom(atom) and is_tuple(tuple) -> get_param_name(tuple) end) |> Enum.reject(&is_nil/1) end defp get_param_name({name, _, nil}) when is_atom(name), do: name defp get_param_name(_) do nil end end