code_version: Handle `-dialyzer` attributes

They can mention functions which we are removing or renaming. Therefore
we need to apply the same changes to the `-dialyzer` attribute(s).

[#154054286]
This commit is contained in:
Jean-Sébastien Pédron 2018-01-29 12:10:21 +01:00
parent b20bcbde4f
commit 8df464d1cf
1 changed files with 95 additions and 3 deletions

View File

@ -97,7 +97,7 @@ unload(Module) ->
code:delete(Module).
compile_forms(Forms) ->
case compile:forms(Forms, [debug_info]) of
case compile:forms(Forms, [debug_info, return_errors]) of
{ok, _ModName, Code} ->
Code;
{ok, _ModName, Code, _Warnings} ->
@ -212,9 +212,11 @@ replace_version_forms(IsPost, AbsCode, VersionSupport) ->
ToName = get_name_pairs(IsPost, VersionSupport),
%% Rename versioned functions with their final name
RenameFun = rename_abstract_functions(ToRename, ToName),
AbsCode1 = replace_function_forms(AbsCode0, RenameFun),
%% Adjust `-dialyzer` attribute.
AbsCode2 = fix_dialyzer_attribute(AbsCode1, ToDelete, ToName),
%% Remove exports of all versioned functions
remove_exports(replace_function_forms(AbsCode0, RenameFun),
ToDelete ++ ToRename).
remove_exports(AbsCode2, ToDelete ++ ToRename).
replace_function_forms(AbsCode, Fun) ->
ReplaceFunction =
@ -230,6 +232,96 @@ replace_function_forms(AbsCode, Fun) ->
end,
fold_syntax_tree(Filter, AbsCode).
fix_dialyzer_attribute(AbsCode, ToDelete, ToName) ->
FixDialyzer =
fun(Tree) ->
case erl_syntax_lib:analyze_attribute(Tree) of
{dialyzer, {_, Value}} ->
FixedValue = fix_dialyzer_attribute_value(Value,
ToDelete,
ToName),
rebuild_dialyzer({dialyzer, FixedValue});
_ ->
Tree
end
end,
Filter = fun(Tree) ->
case erl_syntax:type(Tree) of
attribute -> FixDialyzer(Tree);
_ -> Tree
end
end,
fold_syntax_tree(Filter, AbsCode).
fix_dialyzer_attribute_value(Info, ToDelete, ToName)
when is_list(Info) ->
lists:map(
fun(I) ->
fix_dialyzer_attribute_value(I, ToDelete, ToName)
end,
Info);
fix_dialyzer_attribute_value({Warn, FunList}, ToDelete, ToName) ->
FixedFunList = fix_dialyzer_attribute_funlist(FunList, ToDelete, ToName),
{Warn, FixedFunList};
fix_dialyzer_attribute_value(Info, _, _)
when is_atom(Info) ->
Info.
fix_dialyzer_attribute_funlist(FunList, ToDelete, ToName)
when is_list(FunList) ->
lists:filtermap(
fun(I) ->
case fix_dialyzer_attribute_funlist(I, ToDelete, ToName) of
[] -> false;
R -> {true, R}
end
end,
FunList);
fix_dialyzer_attribute_funlist({FunName, Arity} = Fun,
ToDelete, ToName)
when is_atom(FunName) andalso is_integer(Arity) andalso Arity >= 0 ->
remove_or_rename(Fun, ToDelete, ToName);
fix_dialyzer_attribute_funlist(FunList, _, _) ->
FunList.
remove_or_rename(Fun, ToDelete, ToName) ->
case lists:member(Fun, ToDelete) of
true ->
[];
false ->
case proplists:get_value(Fun, ToName) of
undefined -> Fun;
NewName -> setelement(1, Fun, NewName)
end
end.
rebuild_dialyzer({dialyzer, Value}) ->
erl_syntax:attribute(
erl_syntax:atom(dialyzer),
[rebuild_dialyzer_value(Value)]).
rebuild_dialyzer_value(Value) when is_list(Value) ->
erl_syntax:list(
[rebuild_dialyzer_value(V) || V <- Value]);
rebuild_dialyzer_value({Warn, FunList}) ->
erl_syntax:tuple(
[rebuild_dialyzer_warn(Warn),
rebuild_dialyzer_funlist(FunList)]);
rebuild_dialyzer_value(Warn) when is_atom(Warn) ->
rebuild_dialyzer_warn(Warn).
rebuild_dialyzer_warn(Warn) when is_list(Warn) ->
erl_syntax:list(
[rebuild_dialyzer_warn(W) || W <- Warn]);
rebuild_dialyzer_warn(Warn) when is_atom(Warn) ->
erl_syntax:atom(Warn).
rebuild_dialyzer_funlist(FunList) when is_list(FunList) ->
erl_syntax:list(
[rebuild_dialyzer_funlist({N, A}) || {N, A} <- FunList]);
rebuild_dialyzer_funlist({FunName, Arity}) ->
erl_syntax:tuple([erl_syntax:atom(FunName), erl_syntax:integer(Arity)]).
filter_export_pairs(Info, ToDelete) ->
lists:filter(fun(Pair) ->
not lists:member(Pair, ToDelete)