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:
		
							parent
							
								
									b20bcbde4f
								
							
						
					
					
						commit
						8df464d1cf
					
				|  | @ -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) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue