Current section

Files

Jump to
ides src ides_static_beam.erl
Raw

src/ides_static_beam.erl

-module(ides_static_beam).
-export([load_beams/1, is_supervisor/1]).
-type beam_info() :: #{
module := module(),
attributes := [{atom(), [term()]}],
exports := [{atom(), arity()}],
abstract_code => abstr()
}.
-type abstr() :: [term()].
-export_type([beam_info/0]).
-doc "Return true if the module declares `-behaviour(supervisor)`.".
-spec is_supervisor(beam_info()) -> boolean().
is_supervisor(#{attributes := Attrs}) ->
lists:any(
fun
({behaviour, Behaviours}) ->
lists:member(supervisor, Behaviours);
(_) ->
false
end,
Attrs
).
-doc "Load BEAM files and return metadata indexed by module name.".
-spec load_beams([file:filename()]) -> {ok, #{module() => beam_info()}}.
load_beams(Paths) ->
Results = lists:foldl(fun load_beam/2, #{}, Paths),
{ok, Results}.
load_beam(Path, Acc) ->
case beam_lib:chunks(Path, [attributes, exports, abstract_code, debug_info]) of
{ok, {Module, Chunks}} ->
Attrs = proplists:get_value(attributes, Chunks, []),
Exports = proplists:get_value(exports, Chunks, []),
Info = #{
module => Module,
attributes => Attrs,
exports => Exports
},
Info2 =
case extract_abstract_code(Chunks) of
{ok, Code} -> Info#{abstract_code => Code};
error -> Info
end,
Acc#{Module => Info2};
_ ->
Acc
end.
extract_abstract_code(Chunks) ->
case proplists:get_value(abstract_code, Chunks) of
{raw_abstract_v1, Code} ->
{ok, Code};
Code when is_list(Code) ->
{ok, Code};
_ ->
case proplists:get_value(debug_info, Chunks) of
{erl_abstract_code, Forms} when is_list(Forms) ->
{ok, Forms};
{Backend, Metadata} when is_atom(Backend) ->
get_raw_abstract_code(Metadata);
{_Backend, _Backend2, Metadata} ->
get_raw_abstract_code(Metadata);
_ ->
error
end
end.
get_raw_abstract_code(Metadata) ->
case proplists:get_value(abstract_code, Metadata) of
{raw_abstract_v1, Code} -> {ok, Code};
_ -> error
end.