Current section
Files
Jump to
Current section
Files
lib/mix/tasks/holo/compiler/page_mfa_cascades.ex
defmodule Mix.Tasks.Holo.Compiler.PageMfaCascades do
@moduledoc """
Prints edges to module vertices in the given page's call graph, sorted by the number
of transitively reachable MFAs from each module vertex (biggest cascades first).
The call graph is prepared the same way as during compilation: manually ported MFAs
and runtime MFAs are removed first, so only page-specific cascades are shown.
## Examples
$ mix holo.compiler.page_mfa_cascades MyPageModule
Where `MyPageModule` is the name of the page module you want to analyze (without the `Elixir.` prefix).
"""
use Mix.Task
alias Hologram.Compiler
alias Hologram.Compiler.CallGraph
alias Hologram.Compiler.Digraph
@requirements ["app.config"]
@doc false
@impl Mix.Task
def run([page_module_name]) do
page_module = String.to_existing_atom("Elixir." <> page_module_name)
call_graph = Compiler.build_call_graph()
call_graph_for_runtime =
call_graph
|> CallGraph.clone()
|> CallGraph.remove_manually_ported_mfas()
runtime_mfas = CallGraph.list_runtime_mfas(call_graph_for_runtime)
call_graph_for_pages = CallGraph.remove_runtime_mfas!(call_graph_for_runtime, runtime_mfas)
graph = CallGraph.get_pruned_page_graph(call_graph_for_pages, page_module)
reachable =
graph
|> Digraph.reachable([page_module])
|> MapSet.new()
module_vertices =
reachable
|> Enum.filter(&is_atom/1)
|> MapSet.new()
cascades = CallGraph.compute_cascades(graph, module_vertices, reachable)
# credo:disable-for-lines:5 Credo.Check.Refactor.IoPuts
IO.puts("#{length(cascades)} edges to module vertices for #{inspect(page_module)}:\n")
Enum.each(cascades, fn {source, module, count} ->
IO.puts("#{inspect(source)} -> #{inspect(module)} (#{count} MFAs reachable)")
end)
:ok
end
end