1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2000-2013. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: -module(otp_SUITE). 21: 22: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, 23: init_per_suite/1,end_per_suite/1]). 24: -export([undefined_functions/1,deprecated_not_in_obsolete/1, 25: obsolete_but_not_deprecated/1,call_to_deprecated/1, 26: call_to_size_1/1,strong_components/1]). 27: 28: -include_lib("test_server/include/test_server.hrl"). 29: 30: -import(lists, [filter/2,foldl/3,foreach/2]). 31: 32: suite() -> [{ct_hooks,[ts_install_cth]}]. 33: 34: all() -> 35: [undefined_functions, deprecated_not_in_obsolete, 36: obsolete_but_not_deprecated, call_to_deprecated, 37: call_to_size_1, strong_components]. 38: 39: groups() -> 40: []. 41: 42: init_per_group(_GroupName, Config) -> 43: Config. 44: 45: end_per_group(_GroupName, Config) -> 46: Config. 47: 48: 49: init_per_suite(Config) -> 50: Dog = test_server:timetrap(?t:minutes(10)), 51: Root = code:root_dir(), 52: Server = daily_xref, 53: ?line xref:start(Server), 54: ?line xref:set_default(Server, [{verbose,false}, 55: {warnings,false}, 56: {builtins,true}]), 57: ?line {ok,_Relname} = xref:add_release(Server, Root, {name,otp}), 58: 59: %% If we are running the tests in the source tree, the ERTS application 60: %% is not in the code path. We must add it explicitly. 61: case code:lib_dir(erts) of 62: {error,bad_name} -> 63: Erts = filename:join([code:root_dir(),"erts","preloaded","ebin"]), 64: ?line {ok,_} = xref:add_directory(Server, Erts, []); 65: _ -> 66: ok 67: end, 68: 69: ?line ?t:timetrap_cancel(Dog), 70: [{xref_server,Server}|Config]. 71: 72: end_per_suite(Config) -> 73: Server = ?config(xref_server, Config), 74: catch xref:stop(Server), 75: Config. 76: 77: undefined_functions(Config) when is_list(Config) -> 78: Server = ?config(xref_server, Config), 79: 80: %% Exclude calls from generated modules in the SSL application. 81: ExcludeFrom = "SSL-PKIX|PKIX.*|ssl_pkix_oid", 82: ?line UndefS = xref_base:analysis(undefined_function_calls), 83: ?line Q = io_lib:format("Undef = ~s," 84: "ExcludedFrom = ~p:_/_," 85: "Undef - Undef | ExcludedFrom", 86: [UndefS,ExcludeFrom]), 87: {ok,Undef0} = xref:q(Server, lists:flatten(Q)), 88: Undef1 = hipe_filter(Undef0), 89: Undef2 = ssl_crypto_filter(Undef1), 90: Undef3 = edoc_filter(Undef2), 91: Undef4 = eunit_filter(Undef3), 92: Undef5 = dialyzer_filter(Undef4), 93: Undef6 = wx_filter(Undef5), 94: Undef = gs_filter(Undef6), 95: 96: case Undef of 97: [] -> ok; 98: _ -> 99: Fd = open_log(Config, "undefined_functions"), 100: foreach(fun ({MFA1,MFA2}) -> 101: io:format("~s calls undefined ~s", 102: [format_mfa(Server, MFA1), 103: format_mfa(MFA2)]), 104: io:format(Fd, "~s ~s\n", 105: [format_mfa(Server, MFA1), 106: format_mfa(MFA2)]) 107: end, Undef), 108: close_log(Fd), 109: ?line ?t:fail({length(Undef),undefined_functions_in_otp}) 110: end. 111: 112: hipe_filter(Undef) -> 113: case erlang:system_info(hipe_architecture) of 114: undefined -> 115: filter(fun ({_,{hipe_bifs,_,_}}) -> false; 116: ({_,{hipe,_,_}}) -> false; 117: ({_,{hipe_consttab,_,_}}) -> false; 118: ({_,{hipe_converters,_,_}}) -> false; 119: ({{code,_,_},{Mod,_,_}}) -> 120: not is_hipe_module(Mod); 121: ({{code_server,_,_},{Mod,_,_}}) -> 122: not is_hipe_module(Mod); 123: ({{compile,_,_},{Mod,_,_}}) -> 124: not is_hipe_module(Mod); 125: ({{hipe,_,_},{Mod,_,_}}) -> 126: %% See comment for the next clause. 127: not is_hipe_module(Mod); 128: ({{cerl_to_icode,translate_flags1,2}, 129: {hipe_rtl_arch,endianess,0}}) -> 130: false; 131: ({{Caller,_,_},{Callee,_,_}}) -> 132: %% Part of the hipe application is here 133: %% for the sake of Dialyzer. There are many 134: %% undefined calls within the hipe application. 135: not is_hipe_module(Caller) orelse 136: not is_hipe_module(Callee); 137: (_) -> true 138: end, Undef); 139: _Arch -> 140: filter(fun ({{Mod,_,_},{hipe_bifs,write_u64,2}}) -> 141: %% Unavailable except in 64 bit AMD. Ignore it. 142: not is_hipe_module(Mod); 143: (_) -> true 144: end, Undef) 145: end. 146: 147: is_hipe_module(Mod) -> 148: case atom_to_list(Mod) of 149: "hipe_"++_ -> true; 150: _ -> false 151: end. 152: 153: ssl_crypto_filter(Undef) -> 154: case {app_exists(crypto),app_exists(ssl)} of 155: {false,false} -> 156: filter(fun({_,{ssl,_,_}}) -> false; 157: ({_,{crypto,_,_}}) -> false; 158: ({_,{ssh,_,_}}) -> false; 159: ({_,{ssh_connection,_,_}}) -> false; 160: ({_,{ssh_sftp,_,_}}) -> false; 161: (_) -> true 162: end, Undef); 163: {_,_} -> Undef 164: end. 165: 166: edoc_filter(Undef) -> 167: %% Filter away function call that is catched. 168: filter(fun({{edoc_lib,uri_get_http,1},{http,request_sync,2}}) -> false; 169: (_) -> true 170: end, Undef). 171: 172: eunit_filter(Undef) -> 173: filter(fun({{eunit_test,wrapper_test_exported_,0}, 174: {eunit_test,nonexisting_function,0}}) -> false; 175: (_) -> true 176: end, Undef). 177: 178: dialyzer_filter(Undef) -> 179: case app_exists(dialyzer) of 180: false -> 181: filter(fun({_,{dialyzer_callgraph,_,_}}) -> false; 182: ({_,{dialyzer_codeserver,_,_}}) -> false; 183: ({_,{dialyzer_contracts,_,_}}) -> false; 184: ({_,{dialyzer_cl_parse,_,_}}) -> false; 185: ({_,{dialyzer_timing,_,_}}) -> false; 186: ({_,{dialyzer_plt,_,_}}) -> false; 187: ({_,{dialyzer_succ_typings,_,_}}) -> false; 188: ({_,{dialyzer_utils,_,_}}) -> false; 189: (_) -> true 190: end, Undef); 191: _ -> Undef 192: end. 193: 194: wx_filter(Undef) -> 195: case app_exists(wx) of 196: false -> 197: filter(fun({_,{MaybeWxModule,_,_}}) -> 198: case atom_to_list(MaybeWxModule) of 199: "wx"++_ -> false; 200: _ -> true 201: end 202: end, Undef); 203: _ -> Undef 204: end. 205: 206: gs_filter(Undef) -> 207: case code:lib_dir(gs) of 208: {error,bad_name} -> 209: filter(fun({_,{gs,_,_}}) -> false; 210: ({_,{gse,_,_}}) -> false; 211: ({_,{tool_utils,_,_}}) -> false; 212: (_) -> true 213: end, Undef); 214: _ -> Undef 215: end. 216: 217: deprecated_not_in_obsolete(Config) when is_list(Config) -> 218: ?line Server = ?config(xref_server, Config), 219: ?line {ok,DeprecatedFunctions} = xref:q(Server, "DF"), 220: 221: ?line L = foldl(fun({M,F,A}=MFA, Acc) -> 222: case otp_internal:obsolete(M, F, A) of 223: no -> [MFA|Acc]; 224: _ -> Acc 225: end 226: end, [], DeprecatedFunctions), 227: case L of 228: [] -> ok; 229: _ -> 230: io:put_chars("The following functions have -deprecated() attributes,\n" 231: "but are not listed in otp_internal:obsolete/3.\n"), 232: print_mfas(group_leader(), Server, L), 233: Fd = open_log(Config, "deprecated_not_obsolete"), 234: print_mfas(Fd, Server, L), 235: close_log(Fd), 236: ?line ?t:fail({length(L),deprecated_but_not_obsolete}) 237: end. 238: 239: obsolete_but_not_deprecated(Config) when is_list(Config) -> 240: ?line Server = ?config(xref_server, Config), 241: ?line {ok,NotDeprecated} = xref:q(Server, "X - DF"), 242: 243: ?line L = foldl(fun({M,F,A}=MFA, Acc) -> 244: case otp_internal:obsolete(M, F, A) of 245: no -> Acc; 246: _ -> [MFA|Acc] 247: end 248: end, [], NotDeprecated), 249: 250: case L of 251: [] -> ok; 252: _ -> 253: io:put_chars("The following functions are listed " 254: "in otp_internal:obsolete/3,\n" 255: "but don't have -deprecated() attributes.\n"), 256: print_mfas(group_leader(), Server, L), 257: Fd = open_log(Config, "obsolete_not_deprecated"), 258: print_mfas(Fd, Server, L), 259: close_log(Fd), 260: ?line ?t:fail({length(L),obsolete_but_not_deprecated}) 261: end. 262: 263: call_to_deprecated(Config) when is_list(Config) -> 264: Server = ?config(xref_server, Config), 265: ?line {ok,DeprecatedCalls} = xref:q(Server, "strict(E || DF)"), 266: foreach(fun ({MFA1,MFA2}) -> 267: io:format("~s calls deprecated ~s", 268: [format_mfa(MFA1),format_mfa(MFA2)]) 269: end, DeprecatedCalls), 270: {comment,integer_to_list(length(DeprecatedCalls))++" calls to deprecated functions"}. 271: 272: call_to_size_1(Config) when is_list(Config) -> 273: Server = ?config(xref_server, Config), 274: 275: %% Applications that do not call erlang:size/1: 276: Apps = [asn1,compiler,debugger,kernel,observer,parsetools, 277: runtime_tools,stdlib,tools,webtool], 278: 279: Fs = [{erlang,size,1}], 280: 281: Q1 = io_lib:format("E || ~p : Fun", [Fs]), 282: ?line {ok,AllCallsToSize1} = xref:q(Server, lists:flatten(Q1)), 283: 284: Q2 = io_lib:format("E | ~p : App || ~p : Fun", [Apps,Fs]), 285: ?line {ok,CallsToSize1} = xref:q(Server, lists:flatten(Q2)), 286: 287: case CallsToSize1 of 288: [] -> 289: ok; 290: _ -> 291: io:format("These calls cause an error:~n"), 292: foreach(fun ({MFA1,MFA2}) -> 293: io:format("~s calls soon to be deprecated ~s", 294: [format_mfa(MFA1),format_mfa(MFA2)]) 295: end, CallsToSize1) 296: end, 297: 298: %% Enumerate calls to erlang:size/1 from other applications than 299: %% the ones known not to call erlang:size/1: 300: case AllCallsToSize1--CallsToSize1 of 301: [] -> 302: ok; 303: Calls -> 304: io:format("~n~nThese calls do not cause an error (yet):~n"), 305: foreach(fun ({MFA1,MFA2}) -> 306: io:format("~s calls soon to be deprecated ~s", 307: [format_mfa(MFA1),format_mfa(MFA2)]) 308: end, Calls) 309: end, 310: case CallsToSize1 of 311: [] -> 312: ok; 313: _ -> 314: ?line ?t:fail({length(CallsToSize1),calls_to_size_1}) 315: end. 316: 317: strong_components(Config) when is_list(Config) -> 318: Server = ?config(xref_server, Config), 319: ?line {ok,Cs} = xref:q(Server, "components AE"), 320: io:format("\n\nStrong components:\n\n~p\n", [Cs]), 321: ok. 322: 323: %%% 324: %%% Common help functions. 325: %%% 326: 327: print_mfas(Fd, Server, MFAs) -> 328: [io:format(Fd, "~s\n", [format_mfa(Server, MFA)]) || MFA <- MFAs], 329: ok. 330: 331: format_mfa({M,F,A}) -> 332: lists:flatten(io_lib:format("~s:~s/~p", [M,F,A])). 333: 334: format_mfa(Server, MFA) -> 335: MFAString = format_mfa(MFA), 336: AQ = "(App)" ++ MFAString, 337: AppPrefix = case xref:q(Server, AQ) of 338: {ok,[App]} -> "[" ++ atom_to_list(App) ++ "]"; 339: _ -> "" 340: end, 341: AppPrefix ++ MFAString. 342: 343: open_log(Config, Name) -> 344: PrivDir = ?config(priv_dir, Config), 345: RunDir = filename:dirname(filename:dirname(PrivDir)), 346: Path = filename:join(RunDir, "system_"++Name++".log"), 347: {ok,Fd} = file:open(Path, [write]), 348: Fd. 349: 350: close_log(Fd) -> 351: ok = file:close(Fd). 352: 353: app_exists(AppAtom) -> 354: case code:lib_dir(AppAtom) of 355: {error,bad_name} -> 356: false; 357: Path -> 358: case file:read_file_info(filename:join(Path,"ebin")) of 359: {ok,_} -> 360: true; 361: _ -> 362: false 363: end 364: end.