1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2000-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19 20-module(xref_SUITE). 21 22%-define(debug, true). 23 24-ifdef(debug). 25-define(format(S, A), io:format(S, A)). 26-define(line, put(line, ?LINE), ). 27-define(config(X,Y), "./log_dir/"). 28-define(t,test_server). 29-define(datadir, "xref_SUITE_data"). 30-define(privdir, "xref_SUITE_priv"). 31-define(copydir, "xref_SUITE_priv/datacopy"). 32-else. 33-include_lib("common_test/include/ct.hrl"). 34-define(format(S, A), ok). 35-define(datadir, proplists:get_value(data_dir, Conf)). 36-define(privdir, proplists:get_value(priv_dir, Conf)). 37-define(copydir, proplists:get_value(copy_dir, Conf)). 38-endif. 39 40-export([all/0, suite/0, groups/0, 41 init_per_suite/1, end_per_suite/1]). 42 43-export([addrem/1, convert/1, intergraph/1, lines/1, loops/1, 44 no_data/1, modules/1]). 45 46-export([add/1, default/1, info/1, lib/1, read/1, read2/1, remove/1, 47 replace/1, update/1, deprecated/1, trycatch/1, 48 fun_mfa/1, fun_mfa_r14/1, 49 fun_mfa_vars/1, qlc/1]). 50 51-export([analyze/1, basic/1, md/1, q/1, variables/1, unused_locals/1, 52 behaviour/1]). 53 54-export([format_error/1, otp_7423/1, otp_7831/1, otp_10192/1, otp_13708/1, 55 otp_14464/1, otp_14344/1]). 56 57-import(lists, [append/2, flatten/1, keysearch/3, member/2, sort/1, usort/1]). 58 59-import(sofs, [converse/1, from_term/1, intersection/2, is_sofs_set/1, 60 range/1, relation_to_family/1, set/1, to_external/1, 61 union/2]). 62 63%% Checks some info counters of a server and some relations that should hold. 64-export([check_count/1, check_state/1]). 65 66-include_lib("kernel/include/file.hrl"). 67-include_lib("tools/src/xref.hrl"). 68 69suite() -> 70 [{ct_hooks,[ts_install_cth]}, 71 {timetrap,{minutes,2}}]. 72 73all() -> 74 [{group, xref}, {group, files}, {group, analyses}, 75 {group, misc}]. 76 77groups() -> 78 [{xref, [], 79 [addrem, convert, intergraph, lines, loops, no_data, 80 modules]}, 81 {files, [], 82 [add, default, info, lib, read, read2, remove, replace, 83 update, deprecated, trycatch, fun_mfa, 84 fun_mfa_r14, fun_mfa_vars, qlc]}, 85 {analyses, [], 86 87 [analyze, basic, md, q, variables, unused_locals, behaviour]}, 88 {misc, [], [format_error, otp_7423, otp_7831, otp_10192, otp_13708, 89 otp_14464, otp_14344]}]. 90 91 92init_per_suite(Conf) when is_list(Conf) -> 93 DataDir = ?datadir, 94 PrivDir = ?privdir, 95 CopyDir = fname(PrivDir, "datacopy"), 96 ok = file:make_dir(CopyDir), 97 TarFile = fname(PrivDir, "datacopy.tgz"), 98 ok = file:set_cwd(DataDir), 99 ok = erl_tar:create(TarFile, ["."], [compressed]), 100 ok = erl_tar:extract(TarFile, [compressed, {cwd,CopyDir}]), 101 ok = file:delete(TarFile), 102 [{copy_dir, CopyDir}|Conf]. 103 104end_per_suite(Conf) when is_list(Conf) -> 105 ok. 106 107%% Seems a bit short... 108%% Simple test of removing modules 109addrem(Conf) when is_list(Conf) -> 110 S0 = new(), 111 112 F1 = {m1,f1,1}, 113 F2 = {m2,f1,2}, 114 115 E1 = {F1,F2}, 116 E2 = {F2,F1}, 117 118 D1 = {F1,12}, 119 DefAt_m1 = [D1], 120 X_m1 = [F1], 121 % L_m1 = [], 122 XC_m1 = [E1], 123 LC_m1 = [], 124 LCallAt_m1 = [], 125 XCallAt_m1 = [{E1,13}], 126 Info1 = #xref_mod{name = m1, app_name = [a1]}, 127 S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, 128 XC_m1, LC_m1), 129 130 D2 = {F2,7}, 131 DefAt_m2 = [D2], 132 X_m2 = [F2], 133 % L_m2 = [], 134 XC_m2 = [E2], 135 LC_m2 = [], 136 LCallAt_m2 = [], 137 XCallAt_m2 = [{E2,96}], 138 Info2 = #xref_mod{name = m2, app_name = [a2]}, 139 S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, 140 XC_m2, LC_m2), 141 142 S5 = set_up(S2), 143 144 {ok, XMod1, S6} = remove_module(S5, m1), 145 [a1] = XMod1#xref_mod.app_name, 146 {ok, XMod2, S6a} = remove_module(S6, m2), 147 [a2] = XMod2#xref_mod.app_name, 148 S7 = set_up(S6a), 149 150 AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, 151 S9 = add_application(S7, AppInfo1), 152 S10 = set_up(S9), 153 AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, 154 _S11 = add_application(S10, AppInfo2), 155 ok. 156 157%% Coercion of data 158convert(Conf) when is_list(Conf) -> 159 S0 = new(), 160 161 F1 = {m1,f1,1}, 162 F6 = {m1,f2,6}, % X 163 F2 = {m2,f1,2}, 164 F3 = {m2,f2,3}, % X 165 F7 = {m2,f3,7}, % X 166 F4 = {m3,f1,4}, % X 167 F5 = {m3,f2,5}, 168 169 UF1 = {m1,f12,17}, 170 UF2 = {m17,f17,177}, 171 172 E1 = {F1,F3}, % X 173 E2 = {F6,F7}, % X 174 E3 = {F2,F6}, % X 175 E4 = {F1,F4}, % X 176 E5 = {F4,F5}, 177 E6 = {F7,F4}, % X 178 179 UE1 = {F2,UF2}, % X 180 UE2 = {F5,UF1}, % X 181 182 D1 = {F1,12}, 183 D6 = {F6,3}, 184 DefAt_m1 = [D1,D6], 185 X_m1 = [F6], 186 % L_m1 = [F1], 187 XC_m1 = [E1,E2,E4], 188 LC_m1 = [], 189 LCallAt_m1 = [], 190 XCallAt_m1 = [{E1,13},{E2,17},{E4,7}], 191 Info1 = #xref_mod{name = m1, app_name = [a1]}, 192 S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, 193 XC_m1, LC_m1), 194 195 D2 = {F2,7}, 196 D3 = {F3,9}, 197 D7 = {F7,19}, 198 DefAt_m2 = [D2,D3,D7], 199 X_m2 = [F3,F7], 200 % L_m2 = [F2], 201 XC_m2 = [E3,E6,UE1], 202 LC_m2 = [], 203 LCallAt_m2 = [], 204 XCallAt_m2 = [{E3,96},{E6,12},{UE1,77}], 205 Info2 = #xref_mod{name = m2, app_name = [a2]}, 206 S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, 207 XC_m2, LC_m2), 208 209 D4 = {F4,6}, 210 D5 = {F5,97}, 211 DefAt_m3 = [D4,D5], 212 X_m3 = [F4], 213 % L_m3 = [F5], 214 XC_m3 = [UE2], 215 LC_m3 = [E5], 216 LCallAt_m3 = [{E5,19}], 217 XCallAt_m3 = [{UE2,22}], 218 Info3 = #xref_mod{name = m3, app_name = [a3]}, 219 S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, 220 XC_m3, LC_m3), 221 222 Info4 = #xref_mod{name = m4, app_name = [a2]}, 223 S4 = add_module(S3, Info4, [], [], [], [], [], []), 224 225 AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, 226 S9 = add_application(S4, AppInfo1), 227 AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, 228 S10 = add_application(S9, AppInfo2), 229 AppInfo3 = #xref_app{name = a3, rel_name = [r2]}, 230 S11 = add_application(S10, AppInfo3), 231 232 RelInfo1 = #xref_rel{name = r1}, 233 S12 = add_release(S11, RelInfo1), 234 RelInfo2 = #xref_rel{name = r2}, 235 S13 = add_release(S12, RelInfo2), 236 237 S = set_up(S13), 238 239 {ok, _} = eval("(Lin)(m1->m1:Mod) * m1->m1", type_error, S), 240 {ok, _} = eval("(XXL)(Lin)(m1->m1:Mod) * m1->m1", type_error, S), 241 242 AllDefAt = eval("(Lin) M", S), 243 AllV = eval("(Fun) M", S), 244 AllCallAt = eval("(XXL)(Lin) E", S), 245 AllE = eval("E", S), 246 247 AM = eval("AM", S), 248 A = eval("A", S), 249 R = eval("R", S), 250 251 252 % vertices 253 % general 1 step 254 {ok, _} = eval("(Fun) (Lin) M", AllV, S), 255 {ok, _} = eval("(Fun) (Lin) (Lin) M", AllV, S), 256 {ok, _} = eval(f("(Fun) (Lin) ~p", [[F1, F3]]), [F1,F3], S), 257 {ok, _} = eval(f("(Mod) ~p", [AllV]), [m1,m17,m2,m3], S), 258 {ok, _} = eval(f("(Mod) ~p", [[F1,F3,F6]]), [m1,m2], S), 259 {ok, _} = eval("(App) M", A, S), 260 {ok, _} = eval(f("(App) ~p", [[m1,m2,m4]]), [a1,a2], S), 261 {ok, _} = eval(f("(Rel) ~p", [A]), R, S), 262 {ok, _} = eval(f("(Rel) ~p", [[a1,a2,a2]]), [r1], S), 263 % general 2 steps 264 {ok, _} = eval("(Mod) (Lin) M", [m1,m17,m2,m3], S), 265 {ok, _} = eval(f("(App) ~p", [AllV]), [a1,a2,a3], S), 266 {ok, _} = eval("(Rel) M", R, S), 267 % general 4 steps 268 {ok, _} = eval("(Rel) (Lin) M", [r1,r2], S), 269 270 % special 1 step 271 {ok, _} = eval(f("(Lin) ~p", [AllV]), AllDefAt, S), 272 {ok, _} = eval(f("(Lin) ~p", [[F1,F3]]), [{F1,12},{F3,9}], S), 273 {ok, _} = eval("(Fun) M", AllV, S), 274 {ok, _} = eval(f("(Fun) ~p", [[m1,m2]]), [F1,F2,F3,F6,F7,UF1], S), 275 {ok, _} = eval(f("(Mod) ~p", [A]), AM, S), 276 {ok, _} = eval(f("(Mod) ~p", [[a1,a2]]), [m1,m2,m4], S), 277 {ok, _} = eval(f("(App) ~p", [R]), A, S), 278 {ok, _} = eval(f("(App) ~p", [[r1]]), [a1,a2], S), 279 % special 2 steps 280 {ok, _} = eval("(Lin) M", AllDefAt, S), 281 AnalyzedV = eval("(Fun) AM", S), 282 {ok, _} = eval(f("(Fun) ~p", [A]), AnalyzedV, S), 283 {ok, _} = eval(f("(Mod) ~p", [R]), AM, S), 284 % special 4 steps 285 AnalyzedAllDefAt = eval("(Lin) AM", S), 286 {ok, _} = eval("(Lin) R", AnalyzedAllDefAt, S), 287 288 % edges 289 Ms = [{m1,m2},{m1,m3},{m2,m1},{m2,m3},{m3,m3}], 290 UMs = [{m2,m17},{m3,m1}], 291 AllMs = append(Ms, UMs), 292 As = [{a1,a2},{a1,a3},{a2,a1},{a2,a3},{a3,a3}], 293 Rs = [{r1,r1},{r1,r2},{r2,r2}], 294 295 % general 1 step 296 {ok, _} = eval("(Fun) (Lin) E", AllE, S), 297 {ok, _} = eval(f("(Fun)(Lin) ~p", [[E1, E6]]), [E1, E6], S), 298 {ok, _} = eval("(Mod) E", AllMs, S), 299 {ok, _} = eval(f("(Mod) ~p", [[E1, E6]]), [{m1,m2},{m2,m3}], S), 300 {ok, _} = eval(f("(App) ~p", [As]), As, S), 301 {ok, _} = eval("(App) [m1->m2,m2->m3]", [{a1,a2},{a2,a3}], S), 302 {ok, _} = eval(f("(Rel) ~p", [As]), Rs, S), 303 {ok, _} = eval("(Rel) a1->a2", [{r1,r1}], S), 304 305 % special 1 step 306 {ok, _} = eval("(XXL) (Lin) (Fun) E", AllCallAt, S), 307 {ok, _} = eval("(XXL) (XXL) (Lin) (Fun) E", AllCallAt, S), 308 309 {ok, _} = eval(f("(XXL) (Lin) ~p", [[E1, E6]]), 310 [{{D1,D3},[13]}, {{D7,D4},[12]}], S), 311 {ok, _} = eval(f("(Fun) ~p", [AllMs]), AllE, S), 312 {ok, _} = eval("(Fun) [m1->m2,m2->m3]", [E1,E2,E6], S), 313 {ok, _} = eval(f("(Mod) ~p", [As]), Ms, S), 314 {ok, _} = eval("(Mod) [a1->a2,a2->a3]", [{m1,m2},{m2,m3}], S), 315 {ok, _} = eval(f("(App) ~p", [Rs]), As, S), 316 {ok, _} = eval("(App) r1->r1", [{a1,a2},{a2,a1}], S), 317 ok. 318 319%% Inter Call Graph 320intergraph(Conf) when is_list(Conf) -> 321 S0 = new(), 322 323 F1 = {m1,f1,1}, % X 324 F2 = {m1,f2,2}, % X 325 F3 = {m1,f3,3}, 326 F4 = {m1,f4,4}, 327 F5 = {m1,f5,5}, 328 329 F6 = {m2,f1,6}, % X 330 F7 = {m2,f1,7}, 331 F8 = {m2,f1,8}, 332 F9 = {m2,f1,9}, 333 F10 = {m2,f1,10}, 334 F11 = {m2,f1,11}, 335 336 % Note: E1 =:= E4! 337 E1 = {F2,F1}, 338 E2 = {F2,F3}, 339 E3 = {F3,F1}, 340 E4 = {F2,F1}, % X 341 E5 = {F4,F2}, 342 E6 = {F5,F4}, 343 E7 = {F4,F5}, 344 345 E8 = {F6,F7}, 346 E9 = {F7,F8}, 347 E10 = {F8,F1}, % X 348 E11 = {F6,F9}, 349 E12 = {F6,F10}, 350 E13 = {F9,F11}, 351 E14 = {F10,F11}, 352 E15 = {F11,F1}, % X 353 354 D1 = {F1,1}, 355 D2 = {F2,2}, 356 D3 = {F3,3}, 357 D4 = {F4,4}, 358 D5 = {F5,5}, 359 DefAt_m1 = [D1,D2,D3,D4,D5], 360 X_m1 = [F1,F2], 361 % L_m1 = [F3,F4,F5], 362 XC_m1 = [E4], 363 LC_m1 = [E1,E2,E3,E5,E6,E7], 364 % Note: E1 and E4 together! 365 LCallAt_m1 = [{E1,1},{E2,2},{E3,3},{E5,5},{E6,6},{E7,7}], 366 XCallAt_m1 = [{E1,4}], 367 Info1 = #xref_mod{name = m1, app_name = [a1]}, 368 S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, 369 XC_m1, LC_m1), 370 371 D6 = {F6,6}, 372 D7 = {F7,7}, 373 D8 = {F8,8}, 374 D9 = {F9,9}, 375 D10 = {F10,10}, 376 D11 = {F11,11}, 377 DefAt_m2 = [D6,D7,D8,D9,D10,D11], 378 X_m2 = [F6], 379 % L_m2 = [F7,F8,F9,F10,F11], 380 XC_m2 = [E10,E15], 381 LC_m2 = [E8,E9,E11,E12,E13,E14], 382 LCallAt_m2 = [{E8,8},{E9,9},{E11,11},{E12,12},{E13,13},{E14,14}], 383 XCallAt_m2 = [{E10,10},{E15,15}], 384 Info2 = #xref_mod{name = m2, app_name = [a2]}, 385 S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, 386 XC_m2, LC_m2), 387 388 AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, 389 S5 = add_application(S2, AppInfo1), 390 AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, 391 S6 = add_application(S5, AppInfo2), 392 393 RelInfo = #xref_rel{name = r1}, 394 S7 = add_release(S6, RelInfo), 395 396 S = set_up(S7), 397 398 {ok, _} = eval("EE | m1", [E1,E5,E6,E7], S), 399 {ok, _} = eval("EE | m2", [{F6,F1}], S), 400 {ok, _} = eval("EE | m2 + EE | m2", [{F6,F1}], S), 401 402 {ok, _} = eval("(Fun)(Lin)(E | m1)", 403 to_external(union(set(XC_m1), set(LC_m1))), S), 404 {ok, _} = eval("(XXL)(ELin) (EE | m1)", 405 [{{D2,D1},[1,2,4]},{{D4,D2},[5]},{{D5,D4},[6]},{{D4,D5},[7]}], 406 S), 407 {ok, _} = eval("(XXL)(ELin)(EE | m2)", [{{D6,D1},[8,11,12]}], S), 408 {ok, _} = eval("(XXL)(ELin)(ELin)(EE | m2)", 409 [{{D6,D1},[8,11,12]}], S), 410 411 %% Combining graphs (equal or different): 412 {ok, _} = eval("(XXL)(ELin)(EE | m2 + EE | m2)", 413 [{{D6,D1},[8,11,12]}], S), 414 {ok, _} = eval("(XXL)(ELin)(EE | m2 * EE | m2)", 415 [{{D6,D1},[8,11,12]}], S), 416 {ok, _} = eval("(XXL)(ELin)(EE | m2 - EE | m1)", 417 [{{D6,D1},[8,11,12]}], S), 418 {ok, _} = eval("(XXL)(ELin)(EE | m2 - E | m2)", 419 [{{D6,D1},[8,11,12]}], S), 420 {ok, _} = eval("(XXL)(ELin)(Fun)(ELin)(EE | m2)", 421 [{{D6,D1},[8,11,12]}], S), 422 {ok, _} = eval("EE | m1 + E | m1", LC_m1, S), 423 {ok, _} = eval(f("EE | ~p + E | ~p", [F2, F2]), [E1,E2], S), 424 %% [1,4] from 'calls' is a subset of [1,2,4] from Inter Call Graph: 425 {ok, _} = eval(f("(XXL)(Lin) (E | ~p)", [F2]), 426 [{{D2,D1},[1,4]},{{D2,D3},[2]}], S), 427 428 {ok, _} = eval(f("(XXL)(ELin) (EE | ~p)", [F2]), 429 [{{D2,D1},[1,2,4]}], S), 430 {ok, _} = eval(f("(XXL)((ELin)(EE | ~p) + (Lin)(E | ~p))", [F2, F2]), 431 [{{D2,D1},[1,2,4]},{{D2,D3},[2]}], S), 432 {ok, _} = 433 eval(f("(XXL)((ELin) ~p + (Lin) ~p)", [{F2, F1}, {F2, F1}]), 434 [{{D2,D1},[1,2,4]}], S), 435 {ok, _} = eval(f("(Fun)(Lin) ~p", [{F2, F1}]), [E1], S), 436 %% The external call E4 is included in the reply: 437 {ok, _} = eval("(XXL)(Lin)(LC | m1)", 438 [{{D2,D1},[1,4]},{{D2,D3},[2]},{{D3,D1},[3]}, 439 {{D4,D2},[5]},{{D4,D5},[7]},{{D5,D4},[6]}], S), 440 %% The local call E1 is included in the reply: 441 {ok, _} = eval("(XXL)(Lin)(XC | m1)", [{{D2,D1},[1,4]}], S), 442 443 {ok, _} = eval(f("(LLin) (E | ~p || ~p) + (XLin) (E | ~p || ~p)", 444 [F2, F1, F2, F1]), [{E4,[1,4]}], S), 445 446 {ok, _} = eval("# (ELin) E", 6, S), 447 448 ok. 449 450%% More test of Inter Call Graph, and regular expressions 451lines(Conf) when is_list(Conf) -> 452 S0 = new(), 453 454 F1 = {m1,f1,1}, % X 455 F2 = {m1,f2,2}, 456 F3 = {m1,f3,3}, 457 F4 = {m2,f4,4}, % X 458 F5 = {m1,f5,5}, % X 459 F6 = {m1,f6,6}, 460 461 E1 = {F1,F2}, 462 E2 = {F2,F1}, % X 463 E3 = {F3,F2}, 464 E4 = {F1,F4}, % X 465 E5 = {F2,F4}, % X 466 E6 = {F5,F6}, 467 E7 = {F6,F4}, % X 468 469 D1 = {F1,1}, 470 D2 = {F2,2}, 471 D3 = {F3,3}, 472 D4 = {F4,4}, 473 D5 = {F5,5}, 474 D6 = {F6,6}, 475 476 DefAt_m1 = [D1,D2,D3,D5,D6], 477 X_m1 = [F1,F5], 478 % L_m1 = [F2,F3,F6], 479 XC_m1 = [E4,E5,E7], 480 LC_m1 = [E1,E2,E3,E6], 481 LCallAt_m1 = [{E1,1},{E3,3},{E6,6}], 482 XCallAt_m1 = [{E2,2},{E4,4},{E5,5},{E7,7}], 483 Info1 = #xref_mod{name = m1, app_name = [a1]}, 484 S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, 485 XC_m1, LC_m1), 486 487 DefAt_m2 = [D4], 488 X_m2 = [F4], 489 % L_m2 = [], 490 XC_m2 = [], 491 LC_m2 = [], 492 LCallAt_m2 = [], 493 XCallAt_m2 = [], 494 Info2 = #xref_mod{name = m2, app_name = [a2]}, 495 S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, 496 XC_m2, LC_m2), 497 498 AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, 499 S5 = add_application(S2, AppInfo1), 500 AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, 501 S6 = add_application(S5, AppInfo2), 502 503 RelInfo = #xref_rel{name = r1}, 504 S7 = add_release(S6, RelInfo), 505 506 S = set_up(S7), 507 508 {ok, _} = eval("(XXL) (ELin) (EE | m1)", 509 [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, 510 {{D5,D4},[6]}], S), 511 {ok, _} = eval("(XXL)(Lin) (E | m1)", 512 [{{D1,D2},[1]},{{D1,D4},[4]},{{D2,D1},[2]}, 513 {{D2,D4},[5]},{{D3,D2},[3]},{{D5,D6},[6]},{{D6,D4},[7]}], 514 S), 515 {ok, _} = eval("(E | m1) + (EE | m1)", 516 [E1,E2,E3,E4,E5,E6,E7,{F1,F1},{F3,F1},{F3,F4},{F5,F4}], 517 S), 518 {ok, _} = eval("(Lin)(E | m1)", 519 [{E4,[4]},{E1,[1]},{E2,[2]},{E5,[5]}, 520 {E3,[3]},{E7,[7]},{E6,[6]}], S), 521 {ok, _} = eval("(ELin)(EE | m1)", 522 [{{F1,F1},[1]},{{F1,F4},[1,4]},{{F3,F1},[3]},{{F3,F4},[3]}, 523 {{F5,F4},[6]}], S), 524 {ok, _} = eval("(Lin)(E | m1) + (ELin)(EE | m1)", 525 [{E4,[1,4]},{E1,[1]},{E2,[2]},{E5,[5]}, 526 {E3,[3]},{E7,[7]},{E6,[6]}, 527 {{F1,F1},[1]},{{F3,F1},[3]},{{F3,F4},[3]}, 528 {{F5,F4},[6]}], S), 529 {ok, _} = eval("(Lin)(E | m1) - (ELin)(EE | m1)", 530 [{E1,[1]},{E2,[2]},{E5,[5]}, 531 {E3,[3]},{E7,[7]},{E6,[6]}], S), 532 {ok, _} = eval("(Lin)(E | m1) * (ELin)(EE | m1)", 533 [{E4,[4]}], S), 534 {ok, _} = eval("(XXL)(Lin) (E | m1)", 535 [{{D1,D4},[4]},{{D1,D2},[1]},{{D2,D1},[2]},{{D2,D4},[5]}, 536 {{D3,D2},[3]},{{D6,D4},[7]},{{D5,D6},[6]}], S), 537 {ok, _} = eval("(XXL)(ELin) (EE | m1)", 538 [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, 539 {{D5,D4},[6]}], S), 540 {ok, _} = eval("(XXL)(Lin)(Fun)(Lin) (E | m1)", 541 [{{D1,D4},[4]},{{D1,D2},[1]},{{D2,D1},[2]},{{D2,D4},[5]}, 542 {{D3,D2},[3]},{{D6,D4},[7]},{{D5,D6},[6]}], S), 543 {ok, _} = eval("(XXL)(ELin)(Fun)(ELin) (EE | m1)", 544 [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, 545 {{D5,D4},[6]}], S), 546 547 %% A few tests on regexp. 548 {ok, _} = eval("\"(foo\":Mod", parse_error, S), 549 {ok, _} = eval("_Foo:_/_", parse_error, S), 550 {ok, _} = eval("\".*foo\"", parse_error, S), 551 {ok, _} = eval("_:_/_:Lin", parse_error, S), 552 {ok, _} = eval("_:_/_:Mod", parse_error, S), 553 {ok, _} = eval("_:_/_:App", parse_error, S), 554 {ok, _} = eval("_:_/_:Rel", parse_error, S), 555 {ok, _} = eval("m2:_/4", [F4], S), 556 {ok, _} = eval("m2:_/4:Fun", [F4], S), 557 {ok, _} = eval("\"m.?\":\"f.*\"/\"6\"", [F6], S), 558 {ok, _} = eval("_:_/6", [F6], S), 559 {ok, _} = eval("m1:\"f1\"/_", [F1], S), 560 {ok, _} = eval("\"m1\":f1/_", [F1], S), 561 {ok, _} = eval("\"m1\":Mod", [m1], S), 562 {ok, _} = eval("\"a1\":App", [a1], S), 563 {ok, _} = eval("\"r1\":Rel", [r1], S), 564 {ok, _} = eval("_:_/-1", [], S), 565 566 ok. 567 568%% More Inter Call Graph, loops and "unusual" cases 569loops(Conf) when is_list(Conf) -> 570 S0 = new(), 571 572 F1 = {m1,f1,1}, % X 573 F2 = {m1,f2,2}, 574 F3 = {m1,f3,3}, % X 575 F4 = {m1,f4,4}, 576 F5 = {m1,f5,5}, 577 F6 = {m1,f1,6}, % X 578 F7 = {m1,f1,7}, 579 580 E1 = {F1,F1}, % X 581 E2 = {F2,F2}, 582 E3 = {F3,F4}, 583 E4 = {F4,F5}, 584 E5 = {F5,F3}, % X 585 586 D1 = {F1,1}, 587 D2 = {F2,2}, 588 D3 = {F3,3}, 589 D4 = {F4,4}, 590 D5 = {F5,5}, 591 D6 = {F6,6}, 592 D7 = {F7,7}, 593 DefAt_m1 = [D1,D2,D3,D4,D5,D6,D7], 594 X_m1 = [F1,F3,F6], 595 % L_m1 = [F2,F4,F5], 596 XC_m1 = [], 597 LC_m1 = [E1,E2,E3,E4,E5], 598 LCallAt_m1 = [{E2,2},{E3,3},{E4,4}], 599 XCallAt_m1 = [{E1,1},{E5,5}], 600 Info1 = #xref_mod{name = m1, app_name = [a1]}, 601 S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, 602 XC_m1, LC_m1), 603 604 S = set_up(S1), 605 606 % Neither F6 nor F7 is included. Perhaps one should change that? 607 {ok, _} = eval("EE | m1", [E1,E2,{F3,F3}], S), 608 {ok, _} = eval(f("(XXL)(ELin) (EE | ~p)", [F3]), [{{D3,D3},[3]}], S), 609 610 {ok, _} = eval("m1->m1 | m1->m1", type_error, S), 611 {ok, _} = eval(f("~p | ~p", [F2, F1]), type_error, S), 612 613 {ok, _} = eval(f("range (closure EE | ~p)", [F1]), [F1], S), 614 {ok, _} = eval(f("domain (closure EE || ~p)", [F3]), [F3], S), 615 616 {ok, _} = eval(f("domain (closure E || ~p)", [F3]), [F3,F4,F5], S), 617 618 {ok, _} = eval("components E", [[F1],[F2],[F3,F4,F5]], S), 619 {ok, _} = eval("components EE", [[F1],[F2],[F3]], S), 620 621 ok. 622 623%% Simple tests when there is no data 624no_data(Conf) when is_list(Conf) -> 625 S0 = new(), 626 S1 = set_up(S0), 627 {ok, _} = eval("M", [], S1), 628 {ok, _} = eval("A", [], S1), 629 {ok, _} = eval("R", [], S1), 630 631 ModInfo = #xref_mod{name = m, app_name = []}, 632 S2 = add_module(S1, ModInfo, [], [], [], [], [], []), 633 AppInfo = #xref_app{name = a, rel_name = []}, 634 S3 = add_application(S2, AppInfo), 635 RelInfo = #xref_rel{name = r, dir = ""}, 636 S4 = add_release(S3, RelInfo), 637 S5 = set_up(S4), 638 {ok, _} = eval("M", [m], S5), 639 {ok, _} = eval("A", [a], S5), 640 {ok, _} = eval("R", [r], S5), 641 ok. 642 643%% Modules mode 644modules(Conf) when is_list(Conf) -> 645 CopyDir = ?copydir, 646 Dir = fname(CopyDir, "rel2"), 647 X = fname(Dir, "x.erl"), 648 Y = fname(Dir, "y.erl"), 649 A1_1 = fname([Dir,"lib","app1-1.1"]), 650 A2 = fname([Dir,"lib","app2-1.1"]), 651 EB1_1 = fname(A1_1, "ebin"), 652 EB2 = fname(A2, "ebin"), 653 Xbeam = fname(EB2, "x.beam"), 654 Ybeam = fname(EB1_1, "y.beam"), 655 656 {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), 657 {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), 658 659 {ok, S0} = xref_base:new([{xref_mode, modules}]), 660 {ok, release2, S1} = 661 xref_base:add_release(S0, Dir, [{name,release2}]), 662 S = set_up(S1), 663 {{error, _, {unavailable_analysis, undefined_function_calls}}, _} = 664 xref_base:analyze(S, undefined_function_calls), 665 {{error, _, {unavailable_analysis, locals_not_used}}, _} = 666 xref_base:analyze(S, locals_not_used), 667 {{error, _, {unavailable_analysis, {call, foo}}}, _} = 668 xref_base:analyze(S, {call, foo}), 669 {{error, _, {unavailable_analysis, {use, foo}}}, _} = 670 xref_base:analyze(S, {use, foo}), 671 analyze(undefined_functions, [{x,undef,0}], S), 672 5 = length(xref_base:info(S)), 673 674 %% More: all info, conversions. 675 676 ok = file:delete(Xbeam), 677 ok = file:delete(Ybeam), 678 ok = xref_base:delete(S), 679 ok. 680 681 682%% Add modules, applications, releases, directories 683add(Conf) when is_list(Conf) -> 684 CopyDir = ?copydir, 685 Dir = fname(CopyDir, "rel2"), 686 UDir = fname([CopyDir,"dir","unreadable"]), 687 DDir = fname(CopyDir,"dir"), 688 UFile = fname([DDir, "dir","unreadable.beam"]), 689 X = fname(Dir, "x.erl"), 690 Y = fname(Dir, "y.erl"), 691 A1_1 = fname([Dir,"lib","app1-1.1"]), 692 A2 = fname([Dir,"lib","app2-1.1"]), 693 EB1_1 = fname(A1_1, "ebin"), 694 EB2 = fname(A2, "ebin"), 695 Xbeam = fname(EB2, "x.beam"), 696 Ybeam = fname(EB1_1, "y.beam"), 697 698 {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), 699 {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), 700 701 case os:type() of 702 {unix, _} -> 703 make_udir(UDir), 704 make_ufile(UFile); 705 _ -> 706 true 707 end, 708 709 {error, _, {invalid_options,[not_an_option] }} = 710 xref_base:new([not_an_option]), 711 {error, _, {invalid_options,[{verbose,not_a_value}] }} = 712 xref_base:new([{verbose,not_a_value}]), 713 S = new(), 714 {error, _, {invalid_options,[not_an_option]}} = 715 xref_base:set_up(S, [not_an_option]), 716 {error, _, {invalid_options,[{builtins,true},not_an_option]}} = 717 xref_base:add_directory(S, foo, [{builtins,true},not_an_option]), 718 {error, _, {invalid_options,[{builtins,not_a_value}]}} = 719 xref_base:add_directory(S, foo, [{builtins,not_a_value}]), 720 {error, _, {invalid_filename,{foo,bar}}} = 721 xref_base:add_directory(S, {foo,bar}, []), 722 {error, _, {invalid_options,[{builtins,true},not_an_option]}} = 723 xref_base:add_module(S, foo, [{builtins,true},not_an_option]), 724 {error, _, {invalid_options,[{builtins,not_a_value}]}} = 725 xref_base:add_module(S, foo, [{builtins,not_a_value}]), 726 {error, _, {invalid_filename,{foo,bar}}} = 727 xref_base:add_module(S, {foo,bar}, []), 728 {error, _, {invalid_options,[{builtins,true},not_an_option]}} = 729 xref_base:add_application(S, foo, [{builtins,true},not_an_option]), 730 {error, _, {invalid_options,[{builtins,not_a_value}]}} = 731 xref_base:add_application(S, foo, [{builtins,not_a_value}]), 732 {error, _, {invalid_filename,{foo,bar}}} = 733 xref_base:add_application(S, {foo,bar}, []), 734 {error, _, {invalid_options,[not_an_option]}} = 735 xref_base:add_release(S, foo, [not_an_option]), 736 {error, _, {invalid_options,[{builtins,not_a_value}]}} = 737 xref_base:add_release(S, foo, [{builtins,not_a_value}]), 738 {error, _, {invalid_filename,{foo,bar}}} = 739 xref_base:add_release(S, {foo,bar}, []), 740 {ok, S1} = 741 xref_base:set_default(S, [{verbose,false}, {warnings, false}]), 742 case os:type() of 743 {unix, _} -> 744 {error, _, {file_error, _, _}} = 745 xref_base:add_release(S, UDir); 746 _ -> 747 true 748 end, 749 {error, _, {file_error, _, _}} = 750 xref_base:add_release(S, fname(["/a/b/c/d/e/f","__foo"])), 751 {ok, release2, S2} = 752 xref_base:add_release(S1, Dir, [{name,release2}]), 753 {error, _, {module_clash, {x, _, _}}} = 754 xref_base:add_module(S2, Xbeam), 755 {ok, S3} = xref_base:remove_release(S2, release2), 756 {ok, rel2, S4} = xref_base:add_release(S3, Dir), 757 {error, _, {release_clash, {rel2, _, _}}} = 758 xref_base:add_release(S4, Dir), 759 {ok, S5} = xref_base:remove_release(S4, rel2), 760 %% One unreadable file and one JAM file found (no verification here): 761 {ok, [], S6} = xref_base:add_directory(S5, fname(CopyDir,"dir"), 762 [{recurse,true}, {warnings,true}]), 763 case os:type() of 764 {unix, _} -> 765 {error, _, {file_error, _, _}} = 766 xref_base:add_directory(S6, UDir); 767 _ -> 768 true 769 end, 770 {ok, app1, S7} = xref_base:add_application(S6, A1_1), 771 {error, _, {application_clash, {app1, _, _}}} = 772 xref_base:add_application(S7, A1_1), 773 {ok, S8} = xref_base:remove_application(S7, app1), 774 ok = xref_base:delete(S8), 775 ok = file:delete(Xbeam), 776 ok = file:delete(Ybeam), 777 case os:type() of 778 {unix, _} -> 779 ok = file:del_dir(UDir), 780 ok = file:delete(UFile); 781 _ -> 782 true 783 end, 784 ok. 785 786%% Default values of options 787default(Conf) when is_list(Conf) -> 788 S = new(), 789 {error, _, {invalid_options,[not_an_option]}} = 790 xref_base:set_default(S, not_an_option, true), 791 {error, _, {invalid_options,[{builtins, not_a_value}]}} = 792 xref_base:set_default(S, builtins, not_a_value), 793 {error, _, {invalid_options,[not_an_option]}} = 794 xref_base:get_default(S, not_an_option), 795 {error, _, {invalid_options,[not_an_option]}} = 796 xref_base:set_default(S, [not_an_option]), 797 798 D = xref_base:get_default(S), 799 [{builtins,false},{recurse,false},{verbose,false},{warnings,true}] = 800 D, 801 802 ok = xref_base:delete(S), 803 ok. 804 805%% The info functions 806info(Conf) when is_list(Conf) -> 807 CopyDir = ?copydir, 808 Dir = fname(CopyDir,"rel2"), 809 LDir = fname(CopyDir,"lib_test"), 810 X = fname(Dir, "x.erl"), 811 Y = fname(Dir, "y.erl"), 812 A1_1 = fname([Dir,"lib","app1-1.1"]), 813 A2 = fname([Dir,"lib","app2-1.1"]), 814 EB1_1 = fname(A1_1, "ebin"), 815 EB2 = fname(A2, "ebin"), 816 Xbeam = fname(EB2, "x.beam"), 817 Ybeam = fname(EB1_1, "y.beam"), 818 819 {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), 820 {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), 821 822 {ok, _} = start(s), 823 {error, _, {no_such_info, release}} = xref:info(s, release), 824 {error, _, {no_such_info, release}} = xref:info(s, release, rel), 825 {error, _, {no_such_module, mod}} = xref:info(s, modules, mod), 826 {error, _, {no_such_application, app}} = 827 xref:info(s, applications, app), 828 {error, _, {no_such_release, rel}} = xref:info(s, releases, rel), 829 ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), 830 {ok, rel2} = xref:add_release(s, Dir), 831 9 = length(xref:info(s)), 832 [{x,_}, {y, _}] = xref:info(s, modules), 833 [{app1,_}, {app2, _}] = xref:info(s, applications), 834 [{rel2,_}] = xref:info(s, releases), 835 [] = xref:info(s, libraries), 836 [{x,_}] = xref:info(s, modules, x), 837 [{rel2,_}] = xref:info(s, releases, rel2), 838 {error, _, {no_such_library, foo}} = xref:info(s, libraries, [foo]), 839 840 {ok, lib1} = 841 compile:file(fname(LDir,lib1),[debug_info,{outdir,LDir}]), 842 {ok, lib2} = 843 compile:file(fname(LDir,lib2),[debug_info,{outdir,LDir}]), 844 ok = xref:set_library_path(s, [LDir], [{verbose,false}]), 845 [{lib1,_}, {lib2, _}] = xref:info(s, libraries), 846 [{lib1,_}, {lib2, _}] = xref:info(s, libraries, [lib1,lib2]), 847 ok = file:delete(fname(LDir, "lib1.beam")), 848 ok = file:delete(fname(LDir, "lib2.beam")), 849 850 check_state(s), 851 852 xref:stop(s), 853 854 ok = file:delete(Xbeam), 855 ok = file:delete(Ybeam), 856 857 ok. 858 859%% Library modules 860lib(Conf) when is_list(Conf) -> 861 CopyDir = ?copydir, 862 Dir = fname(CopyDir,"lib_test"), 863 UDir = fname([CopyDir,"dir","non_existent"]), 864 865 {ok, lib1} = compile:file(fname(Dir,lib1),[debug_info,{outdir,Dir}]), 866 {ok, lib2} = compile:file(fname(Dir,lib2),[debug_info,{outdir,Dir}]), 867 {ok, lib3} = compile:file(fname(Dir,lib3),[debug_info,{outdir,Dir}]), 868 {ok, t} = compile:file(fname(Dir,t),[debug_info,{outdir,Dir}]), 869 870 {ok, _} = start(s), 871 ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), 872 {ok, t} = xref:add_module(s, fname(Dir,"t.beam")), 873 {error, _, {invalid_options,[not_an_option]}} = 874 xref:set_library_path(s, ["foo"], [not_an_option]), 875 {error, _, {invalid_path,otp}} = xref:set_library_path(s,otp), 876 {error, _, {invalid_path,[""]}} = xref:set_library_path(s,[""]), 877 {error, _, {invalid_path,[[$a | $b]]}} = 878 xref:set_library_path(s,[[$a | $b]]), 879 {error, _, {invalid_path,[otp]}} = xref:set_library_path(s,[otp]), 880 {ok, []} = xref:get_library_path(s), 881 ok = xref:set_library_path(s, [Dir], [{verbose,false}]), 882 {ok, UnknownFunctions} = xref:q(s, "U"), 883 [{lib1,unknown,0}, {lib2,local,0}, 884 {lib2,unknown,0}, {unknown,unknown,0}] 885 = UnknownFunctions, 886 {ok, [{lib2,f,0},{lib3,f,0}]} = xref:q(s, "DF"), 887 {ok, []} = xref:q(s, "DF_1"), 888 {ok, [{lib2,f,0}]} = xref:q(s, "DF_2"), 889 {ok, [{lib2,f,0}]} = xref:q(s, "DF_3"), 890 891 {ok, [unknown]} = xref:q(s, "UM"), 892 {ok, UnknownDefAt} = xref:q(s, "(Lin)U"), 893 [{{lib1,unknown,0},0},{{lib2,local,0},0}, {{lib2,unknown,0},0}, 894 {{unknown,unknown,0},0}] = UnknownDefAt, 895 {ok, LibFuns} = xref:q(s, "X * LM"), 896 [{lib2,f,0},{lib3,f,0}] = LibFuns, 897 {ok, LibMods} = xref:q(s, "LM"), 898 [lib1,lib2,lib3] = LibMods, 899 {ok, [{{lib2,f,0},0},{{lib3,f,0},0}]} = xref:q(s, "(Lin) (LM * X)"), 900 {ok, [{{lib1,unknown,0},0}, {{lib2,f,0},0}, {{lib2,local,0},0}, 901 {{lib2,unknown,0},0}, {{lib3,f,0},0}]} = xref:q(s,"(Lin)LM"), 902 {ok,[lib1,lib2,lib3,t,unknown]} = xref:q(s,"M"), 903 {ok,[{lib2,f,0},{lib3,f,0},{t,t,0}]} = xref:q(s,"X * M"), 904 check_state(s), 905 906 copy_file(fname(Dir, "lib1.erl"), fname(Dir,"lib1.beam")), 907 ok = xref:set_library_path(s, [Dir]), 908 {error, _, _} = xref:q(s, "U"), 909 910 %% OTP-3921. AM and LM not always disjoint. 911 {ok, lib1} = compile:file(fname(Dir,lib1),[debug_info,{outdir,Dir}]), 912 {ok, lib1} = xref:add_module(s, fname(Dir,"lib1.beam")), 913 check_state(s), 914 915 {error, _, {file_error, _, _}} = xref:set_library_path(s, [UDir]), 916 917 xref:stop(s), 918 ok = file:delete(fname(Dir, "lib1.beam")), 919 ok = file:delete(fname(Dir, "lib2.beam")), 920 ok = file:delete(fname(Dir, "lib3.beam")), 921 ok = file:delete(fname(Dir, "t.beam")), 922 923 {ok, cp} = compile:file(fname(Dir,cp),[debug_info,{outdir,Dir}]), 924 {ok, _} = start(s), 925 ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), 926 {ok, cp} = xref:add_module(s, fname(Dir,"cp.beam")), 927 {ok, [{lists, sort, 1}]} = xref:q(s, "U"), 928 ok = xref:set_library_path(s, code_path), 929 {ok, []} = xref:q(s, "U"), 930 check_state(s), 931 xref:stop(s), 932 ok = file:delete(fname(Dir, "cp.beam")), 933 ok. 934 935%% Data read from the Abstract Code 936read(Conf) when is_list(Conf) -> 937 CopyDir = ?copydir, 938 Dir = fname(CopyDir,"read"), 939 File = fname(Dir, "read"), 940 Beam = fname(Dir, "read.beam"), 941 {ok, read} = compile:file(File, [debug_info,{outdir,Dir}]), 942 do_read(File, abstract_v2), 943 copy_file(fname(Dir, "read.beam.v1"), Beam), 944 do_read(File, abstract_v1), 945 ok = file:delete(Beam), 946 ok. 947 948do_read(File, Version) -> 949 {ok, _} = start(s), 950 ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), 951 {ok, read} = xref:add_module(s, File), 952 953 {U, OK, OKB} = read_expected(Version), 954 955 %% {ok, UC} = xref:q(s, "(Lin) UC"), 956 %% RR = to_external(converse(family_to_relation(family(UC)))), 957 %% lists:foreach(fun(X) -> io:format("~w~n", [X]) end, RR), 958 Unres = to_external(relation_to_family(converse(from_term(U)))), 959 {ok, Unres} = xref:q(s, "(Lin) UC"), 960 961 %% {ok, EE} = xref:q(s, "(Lin) (E - UC)"), 962 %% AA = to_external(converse(family_to_relation(family(EE)))), 963 %% lists:foreach(fun(X) -> io:format("~w~n", [X]) end, AA), 964 Calls = to_external(relation_to_family(converse(from_term(OK)))), 965 {ok, Calls} = xref:q(s, "(Lin) (E - UC) "), 966 967 ok = check_state(s), 968 {ok, UM} = xref:q(s, "UM"), 969 true = member('$M_EXPR', UM), 970 971 {ok, X} = xref:q(s, "X"), 972 true = member({read, module_info, 0}, X), 973 false = member({foo, module_info, 0}, X), 974 false = member({erlang, module_info, 0}, X), 975 {ok, Unknowns} = xref:q(s, "U"), 976 false = member({read, module_info, 0}, Unknowns), 977 true = member({foo, module_info, 0}, Unknowns), 978 true = member({erlang, module_info, 0}, Unknowns), 979 {ok, LC} = xref:q(s, "LC"), 980 true = member({{read,bi,0},{read,bi,0}}, LC), 981 982 ok = xref:set_library_path(s, add_erts_code_path(fname(code:lib_dir(kernel),ebin))), 983 io:format("~p~n",[(catch xref:get_library_path(s))]), 984 {ok, X2} = xref:q(s, "X"), 985 ok = check_state(s), 986 true = member({read, module_info, 0}, X2), 987 false = member({foo, module_info, 0}, X2), 988 true = member({erlang, module_info, 0}, X2), 989 {ok, Unknowns2} = xref:q(s, "U"), 990 false = member({read, module_info, 0}, Unknowns2), 991 true = member({foo, module_info, 0}, Unknowns2), 992 false = member({erlang, module_info, 0}, Unknowns2), 993 994 ok = xref:remove_module(s, read), 995 {ok, read} = xref:add_module(s, File, [{builtins,true}]), 996 997 UnresB = to_external(relation_to_family(converse(from_term(U)))), 998 {ok, UnresB} = xref:q(s, "(Lin) UC"), 999 CallsB = to_external(relation_to_family(converse(from_term(OKB)))), 1000 {ok, CallsB} = xref:q(s, "(Lin) (E - UC) "), 1001 ok = check_state(s), 1002 {ok, XU} = xref:q(s, "XU"), 1003 Erl = set([{erlang,length,1},{erlang,integer,1}, 1004 {erlang,binary_to_term,1}]), 1005 [{erlang,binary_to_term,1},{erlang,length,1}] = 1006 to_external(intersection(set(XU), Erl)), 1007 xref:stop(s). 1008 1009%% What is expected when xref_SUITE_data/read/read.erl is added: 1010read_expected(Version) -> 1011 %% Line positions in xref_SUITE_data/read/read.erl: 1012 POS1 = 28, POS2 = POS1+10, POS3 = POS2+6, POS4 = POS3+6, POS5 = POS4+10, 1013 POS6 = POS5+5, POS7 = POS6+6, POS8 = POS7+6, POS9 = POS8+8, 1014 POS10 = POS9+10, POS11 = POS10+7, POS12 = POS11+8, POS13 = POS12+10, 1015 POS14 = POS13+18, POS15 = POS14+23, 1016 1017 FF = {read,funfuns,0}, 1018 U = [{POS1+5,{FF,{dist,'$F_EXPR',0}}}, 1019 {POS1+8,{FF,{dist,'$F_EXPR',0}}}, 1020 {POS2+8,{{read,funfuns,0},{expr,'$F_EXPR',1}}}, 1021 {POS3+4,{FF,{expr,'$F_EXPR',2}}}, 1022 {POS4+2,{FF,{modul,'$F_EXPR',1}}}, 1023 {POS4+4,{FF,{spm,'$F_EXPR',1}}}, 1024 {POS4+6,{FF,{spm,'$F_EXPR',1}}}, 1025 {POS4+8,{FF,{spm,'$F_EXPR',1}}}, 1026 {POS5+1,{FF,{'$M_EXPR','$F_EXPR',0}}}, 1027 {POS5+2,{FF,{'$M_EXPR','$F_EXPR',0}}}, 1028 {POS5+3,{FF,{'$M_EXPR','$F_EXPR',0}}}, 1029 {POS6+1,{FF,{'$M_EXPR','$F_EXPR',0}}}, 1030 {POS6+2,{FF,{'$M_EXPR','$F_EXPR',0}}}, 1031 {POS6+4,{FF,{n,'$F_EXPR',-1}}}, 1032 {POS7+1,{FF,{'$M_EXPR',f,1}}}, 1033 {POS7+2,{FF,{'$M_EXPR',f,1}}}, 1034 {POS8+2,{FF,{hej,'$F_EXPR',1}}}, 1035 {POS8+3,{FF,{t,'$F_EXPR',1}}}, 1036 {POS8+5,{FF,{a,'$F_EXPR',1}}}, 1037 {POS8+7,{FF,{m,'$F_EXPR',1}}}, 1038 {POS9+1,{FF,{'$M_EXPR',f,1}}}, 1039 {POS9+3,{FF,{a,'$F_EXPR',1}}}, 1040 {POS10+1,{FF,{'$M_EXPR',foo,1}}}, 1041 {POS10+2,{FF,{'$M_EXPR','$F_EXPR',1}}}, 1042 {POS10+3,{FF,{'$M_EXPR','$F_EXPR',2}}}, 1043 {POS10+4,{FF,{'$M_EXPR','$F_EXPR',1}}}, 1044 {POS10+5,{FF,{'$M_EXPR',san,1}}}, 1045 {POS10+6,{FF,{'$M_EXPR','$F_EXPR',1}}}, 1046 {POS11+1,{FF,{'$M_EXPR','$F_EXPR',1}}}, 1047 {POS11+2,{FF,{'$M_EXPR','$F_EXPR',-1}}}, 1048 {POS11+3,{FF,{m,f,-1}}}, 1049 {POS11+4,{FF,{m,f,-1}}}, 1050 {POS11+5,{FF,{'$M_EXPR','$F_EXPR',1}}}, 1051 {POS11+6,{FF,{'$M_EXPR','$F_EXPR',1}}}, 1052 {POS12+1,{FF,{'$M_EXPR','$F_EXPR',-1}}}, 1053 {POS12+4,{FF,{'$M_EXPR','$F_EXPR',2}}}, 1054 {POS12+7,{FF,{'$M_EXPR','$F_EXPR',-1}}}, 1055 {POS12+8,{FF,{m4,f4,-1}}}, 1056 {POS13+2,{FF,{debug,'$F_EXPR',0}}}, 1057 {POS13+3,{FF,{'$M_EXPR','$F_EXPR',-1}}}, 1058 {POS14+8,{{read,bi,0},{'$M_EXPR','$F_EXPR',1}}}], 1059 1060 O1 = [{20,{{read,lc,0},{ets,new,0}}}, 1061 {21,{{read,lc,0},{ets,tab2list,1}}}, 1062 {POS1+1,{FF,{erlang,spawn,1}}}, 1063 {POS1+1,{FF,{mod17,fun17,0}}}, 1064 {POS1+2,{FF,{erlang,spawn,1}}}, 1065 {POS1+2,{FF,{read,local,0}}}, 1066 {POS1+3,{FF,{erlang,spawn,1}}}, 1067 {POS1+4,{FF,{dist,func,0}}}, 1068 {POS1+4,{FF,{erlang,spawn,1}}}, 1069 {POS1+5,{FF,{erlang,spawn,1}}}, 1070 {POS1+6,{FF,{erlang,spawn_link,1}}}, 1071 {POS1+6,{FF,{mod17,fun17,0}}}, 1072 {POS1+7,{FF,{dist,func,0}}}, 1073 {POS1+7,{FF,{erlang,spawn_link,1}}}, 1074 {POS1+8,{FF,{erlang,spawn_link,1}}}, 1075 {POS2+1,{FF,{d,f,0}}}, 1076 {POS2+1,{FF,{dist,func,2}}}, 1077 {POS2+1,{FF,{erlang,spawn,2}}}, 1078 {POS2+2,{FF,{dist,func,2}}}, 1079 {POS2+2,{FF,{erlang,spawn,2}}}, 1080 {POS2+2,{FF,{mod42,func,0}}}, 1081 {POS2+3,{FF,{d,f,0}}}, 1082 {POS2+3,{FF,{dist,func,2}}}, 1083 {POS2+3,{FF,{erlang,spawn_link,2}}}, 1084 {POS2+4,{FF,{dist,func,2}}}, 1085 {POS2+4,{FF,{erlang,spawn_link,2}}}, 1086 {POS2+4,{FF,{mod42,func,0}}}, 1087 {POS3+1,{FF,{dist,func,2}}}, 1088 {POS3+3,{FF,{dist,func,2}}}, 1089 {POS4+1,{FF,{erlang,spawn,4}}}, 1090 {POS4+1,{FF,{modul,function,0}}}, 1091 {POS4+2,{FF,{erlang,spawn,4}}}, 1092 {POS4+3,{FF,{dist,func,2}}}, 1093 {POS4+3,{FF,{erlang,spawn,4}}}, 1094 {POS4+3,{FF,{spm,spf,2}}}, 1095 {POS4+4,{FF,{dist,func,2}}}, 1096 {POS4+4,{FF,{erlang,spawn,4}}}, 1097 {POS4+5,{FF,{dist,func,2}}}, 1098 {POS4+5,{FF,{erlang,spawn_link,4}}}, 1099 {POS4+5,{FF,{spm,spf,2}}}, 1100 {POS4+6,{FF,{dist,func,2}}}, 1101 {POS4+6,{FF,{erlang,spawn_link,4}}}, 1102 {POS4+7,{FF,{read,bi,0}}}, 1103 {POS4+7,{FF,{spm,spf,2}}}, 1104 {POS4+8,{FF,{read,bi,0}}}, 1105 {POS5+1,{FF,{erlang,spawn,1}}}, 1106 {POS5+2,{FF,{erlang,spawn,1}}}, 1107 {POS5+3,{FF,{erlang,spawn_link,1}}}, 1108 {POS6+1,{FF,{erlang,spawn,2}}}, 1109 {POS6+2,{FF,{erlang,spawn_link,2}}}, 1110 {POS7+1,{FF,{erlang,spawn,4}}}, 1111 {POS8+1,{FF,{hej,san,1}}}, 1112 {POS8+4,{FF,{a,b,1}}}, 1113 {POS8+6,{FF,{m,f,1}}}, 1114 {POS9+1,{FF,{read,bi,0}}}, 1115 {POS9+2,{FF,{a,b,1}}}, 1116 {POS9+4,{FF,{erlang,not_a_function,1}}}, 1117 {POS9+5,{FF,{mod,func,2}}}, 1118 {POS9+6,{FF,{erlang,apply,1}}}, 1119 {POS9+7,{FF,{math,add3,1}}}, 1120 {POS9+8,{FF,{q,f,1}}}, 1121 {POS10+5,{FF,{mod1,fun1,1}}}, 1122 {POS12+5,{FF,{m3,f3,2}}}, 1123 {POS13+1,{FF,{dm,df,1}}}, 1124 {POS13+6,{{read,bi,0},{foo,module_info,0}}}, 1125 {POS13+7,{{read,bi,0},{read,module_info,0}}}, 1126 {POS13+9,{{read,bi,0},{t,foo,1}}}, 1127 {POS14+11,{{read,bi,0},{erlang,module_info,0}}}, 1128 {POS14+17,{{read,bi,0},{read,bi,0}}}], 1129 1130 OK = case Version of 1131 abstract_v1 -> 1132 [{0,{FF,{read,'$F_EXPR',178}}}, 1133 {0,{FF,{modul,'$F_EXPR',179}}}] 1134 ++ O1; 1135 _ -> 1136 [{16,{FF,{read,'$F_EXPR',178}}}, 1137 {17,{FF,{modul,'$F_EXPR',179}}}] 1138 ++ 1139 O1 1140 end, 1141 1142 %% When builtins =:= true: 1143 OKB1 = [{POS13+1,{FF,{erts_debug,apply,4}}}, 1144 {POS13+2,{FF,{erts_debug,apply,4}}}, 1145 {POS13+3,{FF,{erts_debug,apply,4}}}, 1146 {POS1+3, {FF,{erlang,binary_to_term,1}}}, 1147 {POS3+1, {FF,{erlang,spawn,3}}}, 1148 {POS3+2, {FF,{erlang,spawn,3}}}, 1149 {POS3+3, {FF,{erlang,spawn_link,3}}}, 1150 {POS3+4, {FF,{erlang,spawn_link,3}}}, 1151 {POS4+7, {FF,{erlang,spawn_opt,4}}}, 1152 {POS4+8, {FF,{erlang,spawn_opt,4}}}, 1153 {POS6+4, {FF,{erlang,spawn,3}}}, 1154 {POS7+2, {FF,{erlang,spawn_opt,4}}}, 1155 {POS8+4,{FF,{erlang,apply,2}}}, 1156 {POS8+5,{FF,{erlang,apply,2}}}, 1157 {POS8+6,{FF,{erlang,apply,3}}}, 1158 {POS8+7,{FF,{erlang,apply,3}}}, 1159 {POS9+1,{FF,{erlang,apply,3}}}, 1160 {POS9+2,{FF,{erlang,apply,2}}}, 1161 {POS9+3,{FF,{erlang,apply,2}}}, 1162 {POS9+4,{FF,{erlang,apply,2}}}, 1163 {POS9+5,{FF,{erlang,apply,3}}}, 1164 {POS9+7,{FF,{erlang,apply,2}}}, 1165 {POS10+4,{FF,{erlang,apply,2}}}, 1166 {POS11+1,{FF,{erlang,apply,3}}}, 1167 {POS11+2,{FF,{erlang,apply,3}}}, 1168 {POS11+3,{FF,{erlang,apply,3}}}, 1169 {POS11+4,{FF,{erlang,apply,3}}}, 1170 {POS11+6,{FF,{erlang,apply,2}}}, 1171 {POS12+1,{FF,{erlang,apply,2}}}, 1172 {POS12+4,{FF,{erlang,apply,2}}}, 1173 {POS12+5,{FF,{erlang,apply,3}}}, 1174 {POS12+7,{FF,{erlang,apply,2}}}, 1175 {POS12+8,{FF,{erlang,apply,3}}}, 1176 {POS13+5, {{read,bi,0},{erlang,length,1}}}, 1177 {POS14+3, {{read,bi,0},{erlang,length,1}}}], 1178 1179 %% Operators (OTP-8647): 1180 OKB = case Version of 1181 abstract_v1 -> 1182 [{POS8+3, {FF,{erlang,apply,3}}}, 1183 {POS10+1, {FF,{erlang,apply,3}}}, 1184 {POS10+6, {FF,{erlang,apply,3}}}]; 1185 _ -> 1186 [{POS13+16, {{read,bi,0},{erlang,'!',2}}}, 1187 {POS13+16, {{read,bi,0},{erlang,'-',1}}}, 1188 {POS13+16, {{read,bi,0},{erlang,self,0}}}, 1189 {POS15+1, {{read,bi,0},{erlang,'>',2}}}, 1190 {POS15+2, {{read,bi,0},{erlang,'-',2}}}, 1191 {POS15+2, {{read,bi,0},{erlang,'*',2}}}, 1192 {POS15+8, {{read,bi,0},{erlang,'/',2}}}] 1193 end 1194 ++ [{POS14+19, {{read,bi,0},{erlang,'+',2}}}, 1195 {POS14+21, {{read,bi,0},{erlang,'+',2}}}, 1196 {POS13+16, {{read,bi,0},{erlang,'==',2}}}, 1197 {POS14+15, {{read,bi,0},{erlang,'==',2}}}, 1198 {POS13+5, {{read,bi,0},{erlang,'>',2}}}, 1199 {POS14+3, {{read,bi,0},{erlang,'>',2}}}] 1200 ++ OKB1 ++ OK, 1201 1202 {U, OK, OKB}. 1203 1204%% Data read from the Abstract Code (cont) 1205read2(Conf) when is_list(Conf) -> 1206 %% Handles the spawn_opt versions added in R9 (OTP-4180). 1207 %% Expected augmentations: try/catch, cond. 1208 CopyDir = ?copydir, 1209 Dir = fname(CopyDir,"read"), 1210 File = fname(Dir, "read2.erl"), 1211 MFile = fname(Dir, "read2"), 1212 Beam = fname(Dir, "read2.beam"), 1213 Test = <<"-module(read2). 1214 -compile(export_all). 1215 1216 f() -> 1217 spawn_opt({read2,f}, % POS2 1218 [f()]), 1219 spawn_opt(fun() -> foo end, [link]), 1220 spawn_opt(f(), 1221 {read2,f}, [{min_heap_size,1000}]), 1222 spawn_opt(f(), 1223 fun() -> f() end, [flopp]), 1224 spawn_opt(f(), 1225 read2, f, [], []); 1226 f() -> 1227 %% Duplicated unresolved calls are ignored: 1228 (f())(foo,bar),(f())(foo,bar). % POS1 1229 1230 %% Warning forms must be ignored. 1231 -warning(must_not_crash). 1232 ">>, 1233 ok = file:write_file(File, Test), 1234 {ok, read2} = compile:file(File, [debug_info,{outdir,Dir}]), 1235 1236 {ok, _} = xref:start(s), 1237 {ok, read2} = xref:add_module(s, MFile), 1238 {U0, OK0} = read2_expected(), 1239 1240 U = to_external(relation_to_family(converse(from_term(U0)))), 1241 OK = to_external(relation_to_family(converse(from_term(OK0)))), 1242 {ok, U2} = xref:q(s, "(Lin) UC"), 1243 {ok, OK2} = xref:q(s, "(Lin) (E - UC)"), 1244 true = U =:= U2, 1245 true = OK =:= OK2, 1246 ok = check_state(s), 1247 xref:stop(s), 1248 1249 ok = file:delete(File), 1250 ok = file:delete(Beam), 1251 ok. 1252 1253 1254read2_expected() -> 1255 POS1 = 16, 1256 POS2 = 5, 1257 FF = {read2,f,0}, 1258 U = [{POS1,{FF,{'$M_EXPR','$F_EXPR',2}}}], 1259 OK = [{POS2,{FF,{erlang,spawn_opt,2}}}, 1260 {POS2,{FF,FF}}, 1261 {POS2+1,{FF,FF}}, 1262 {POS2+2,{FF,{erlang,spawn_opt,2}}}, 1263 {POS2+3,{FF,{erlang,spawn_opt,3}}}, 1264 {POS2+3,{FF,FF}}, 1265 {POS2+3,{FF,FF}}, 1266 {POS2+5,{FF,{erlang,spawn_opt,3}}}, 1267 {POS2+5,{FF,FF}}, 1268 {POS2+6,{FF,FF}}, 1269 {POS2+7,{FF,{erlang,spawn_opt,5}}}, 1270 {POS2+7,{FF,FF}}, 1271 {POS2+7,{FF,FF}}, 1272 {POS1,{FF,FF}}], 1273 {U, OK}. 1274 1275%% Remove modules, applications, releases 1276remove(Conf) when is_list(Conf) -> 1277 S = new(), 1278 {error, _, {no_such_module, mod}} = 1279 xref_base:remove_module(S, mod), 1280 {error, _, {no_such_application, app}} = 1281 xref_base:remove_application(S, app), 1282 {error, _, {no_such_release, rel}} = 1283 xref_base:remove_release(S, rel), 1284 ok = xref_base:delete(S), 1285 ok. 1286 1287%% Replace modules, applications, releases 1288replace(Conf) when is_list(Conf) -> 1289 CopyDir = ?copydir, 1290 Dir = fname(CopyDir,"rel2"), 1291 X = fname(Dir, "x.erl"), 1292 Y = fname(Dir, "y.erl"), 1293 A1_0 = fname(Dir, fname("lib","app1-1.0")), 1294 A1_1 = fname(Dir, fname("lib","app1-1.1")), 1295 A2 = fname(Dir, fname("lib","app2-1.1")), 1296 EB1_0 = fname(A1_0, "ebin"), 1297 EB1_1 = fname(A1_1, "ebin"), 1298 Xbeam = fname(EB1_1, "x.beam"), 1299 Ybeam = fname(EB1_1, "y.beam"), 1300 1301 {ok, x} = compile:file(X, [debug_info, {outdir,EB1_0}]), 1302 {ok, x} = compile:file(X, [debug_info, {outdir,EB1_1}]), 1303 {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), 1304 1305 {ok, _} = start(s), 1306 {ok, false} = xref:set_default(s, verbose, false), 1307 {ok, true} = xref:set_default(s, warnings, false), 1308 {ok, rel2} = xref:add_release(s, Dir, []), 1309 {error, _, _} = xref:replace_application(s, app1, "no_data"), 1310 {error, _, {no_such_application, app12}} = 1311 xref:replace_application(s, app12, A1_0, []), 1312 {error, _, {invalid_filename,{foo,bar}}} = 1313 xref:replace_application(s, app1, {foo,bar}, []), 1314 {error, _, {invalid_options,[not_an_option]}} = 1315 xref:replace_application(s, foo, bar, [not_an_option]), 1316 {error, _, {invalid_options,[{builtins,not_a_value}]}} = 1317 xref:replace_application(s, foo, bar, [{builtins,not_a_value}]), 1318 {ok, app1} = 1319 xref:replace_application(s, app1, A1_0), 1320 [{_, AppInfo}] = xref:info(s, applications, app1), 1321 {value, {release, [rel2]}} = keysearch(release, 1, AppInfo), 1322 1323 {error, _, {no_such_module, xx}} = 1324 xref:replace_module(s, xx, Xbeam, []), 1325 {error, _, {invalid_options,[{builtins,true},not_an_option]}} = 1326 xref:replace_module(s, foo, bar,[{builtins,true},not_an_option]), 1327 {error, _, {invalid_options,[{builtins,not_a_value}]}} = 1328 xref:replace_module(s, foo, bar, [{builtins,not_a_value}]), 1329 {error, _, {invalid_filename,{foo,bar}}} = 1330 xref:replace_module(s, x, {foo,bar}), 1331 {ok, x} = xref:replace_module(s, x, Xbeam), 1332 [{x, ModInfo}] = xref:info(s, modules, x), 1333 {value, {application, [app1]}} = 1334 keysearch(application, 1, ModInfo), 1335 1336 {ok, x} = compile:file(X, [no_debug_info, {outdir,EB1_1}]), 1337 {error, _, {no_debug_info, _}} = xref:replace_module(s, x, Xbeam), 1338 {error, _, {module_mismatch, x,y}} = 1339 xref:replace_module(s, x, Ybeam), 1340 case os:type() of 1341 {unix, _} -> 1342 hide_file(Ybeam), 1343 {error, _, {file_error, _, _}} = 1344 xref:replace_module(s, x, Ybeam); 1345 _ -> 1346 true 1347 end, 1348 ok = xref:remove_module(s, x), 1349 {error, _, {no_debug_info, _}} = xref:add_module(s, Xbeam), 1350 1351 %% "app2" is ignored, the old application name is kept 1352 {ok, app1} = xref:replace_application(s, app1, A2), 1353 1354 xref:stop(s), 1355 ok = file:delete(fname(EB1_0, "x.beam")), 1356 ok = file:delete(Xbeam), 1357 ok = file:delete(Ybeam), 1358 ok. 1359 1360%% The update() function 1361update(Conf) when is_list(Conf) -> 1362 CopyDir = ?copydir, 1363 Dir = fname(CopyDir,"update"), 1364 Source = fname(Dir, "x.erl"), 1365 Beam = fname(Dir, "x.beam"), 1366 copy_file(fname(Dir, "x.erl.1"), Source), 1367 {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), 1368 1369 {ok, _} = start(s), 1370 ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), 1371 {ok, [x]} = xref:add_directory(s, Dir, [{builtins,true}]), 1372 {error, _, {invalid_options,[not_an_option]}} = 1373 xref:update(s, [not_an_option]), 1374 {ok, []} = xref:update(s), 1375 {ok, [{erlang,atom_to_list,1}]} = xref:q(s, "XU"), 1376 1377 [{x, ModInfo}] = xref:info(s, modules, x), 1378 case keysearch(directory, 1, ModInfo) of 1379 {value, {directory, Dir}} -> ok 1380 end, 1381 1382 timer:sleep(2000), % make sure modification time has changed 1383 copy_file(fname(Dir, "x.erl.2"), Source), 1384 {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), 1385 {ok, [x]} = xref:update(s, []), 1386 {ok, [{erlang,list_to_atom,1}]} = xref:q(s, "XU"), 1387 1388 timer:sleep(2000), 1389 {ok, x} = compile:file(Source, [no_debug_info,{outdir,Dir}]), 1390 {error, _, {no_debug_info, _}} = xref:update(s), 1391 1392 xref:stop(s), 1393 ok = file:delete(Beam), 1394 ok = file:delete(Source), 1395 ok. 1396 1397%% OTP-4695: Deprecated functions. 1398deprecated(Conf) when is_list(Conf) -> 1399 Dir = ?copydir, 1400 File = fname(Dir, "depr.erl"), 1401 MFile_r9c = fname(Dir, "depr_r9c"), 1402 MFile = fname(Dir, "depr"), 1403 Beam = fname(Dir, "depr.beam"), 1404 %% This file has been compiled to ?datadir/depr_r9c.beam 1405 %% using the R9C compiler. From R10B and onwards the linter 1406 %% checks the 'deprecated' attribute as well. 1407 % Test = <<"-module(depr). 1408 1409 % -export([t/0,f/1,bar/2,f/2,g/3]). 1410 1411 % -deprecated([{f,1}, % DF 1412 % {bar,2,eventually}]). % DF_3 1413 % -deprecated([{f,1,next_major_release}]). % DF_2 (again) 1414 % -deprecated([{frutt,0,next_version}]). % message... 1415 % -deprecated([{f,2,next_major_release}, % DF_2 1416 % {g,3,next_version}, % DF_1 1417 % {ignored,10,100}]). % message... 1418 % -deprecated([{does_not_exist,1}]). % message... 1419 1420 % -deprecated(foo). % message... 1421 1422 % t() -> 1423 % frutt(1), 1424 % g(1,2, 3), 1425 % ?MODULE:f(10). 1426 1427 % f(A) -> 1428 % ?MODULE:f(A,A). 1429 1430 % f(X, Y) -> 1431 % ?MODULE:g(X, Y, X). 1432 1433 % g(F, G, H) -> 1434 % ?MODULE:bar(F, {G,H}). 1435 1436 % bar(_, _) -> 1437 % true. 1438 1439 % frutt(_) -> 1440 % frutt(). 1441 1442 % frutt() -> 1443 % true. 1444 % ">>, 1445 1446 % ok = file:write_file(File, Test), 1447 % {ok, depr_r9c} = compile:file(File, [debug_info,{outdir,Dir}]), 1448 1449 {ok, _} = xref:start(s), 1450 {ok, depr_r9c} = xref:add_module(s, MFile_r9c), 1451 M9 = depr_r9c, 1452 DF_1 = usort([{{M9,f,2},{M9,g,3}}]), 1453 DF_2 = usort(DF_1++[{{M9,f,1},{M9,f,2}},{{M9,t,0},{M9,f,1}}]), 1454 DF_3 = usort(DF_2++[{{M9,g,3},{M9,bar,2}}]), 1455 DF = usort(DF_3++[{{M9,t,0},{M9,f,1}}]), 1456 1457 {ok,DF} = xref:analyze(s, deprecated_function_calls), 1458 {ok,DF_1} = 1459 xref:analyze(s, {deprecated_function_calls,next_version}), 1460 {ok,DF_2} = 1461 xref:analyze(s, {deprecated_function_calls,next_major_release}), 1462 {ok,DF_3} = 1463 xref:analyze(s, {deprecated_function_calls,eventually}), 1464 1465 D = to_external(range(from_term(DF))), 1466 D_1 = to_external(range(from_term(DF_1))), 1467 D_2 = to_external(range(from_term(DF_2))), 1468 D_3 = to_external(range(from_term(DF_3))), 1469 1470 {ok,D} = xref:analyze(s, deprecated_functions), 1471 {ok,D_1} = 1472 xref:analyze(s, {deprecated_functions,next_version}), 1473 {ok,D_2} = 1474 xref:analyze(s, {deprecated_functions,next_major_release}), 1475 {ok,D_3} = 1476 xref:analyze(s, {deprecated_functions,eventually}), 1477 1478 ok = check_state(s), 1479 xref:stop(s), 1480 1481 Test2= <<"-module(depr). 1482 1483 -export([t/0,f/1,bar/2,f/2,g/3,string/0]). 1484 1485 -deprecated([{'_','_',eventually}]). % DF_3 1486 -deprecated([{f,'_',next_major_release}]). % DF_2 1487 -deprecated([{g,'_',next_version}]). % DF_1 1488 -deprecated([{bar,2}]). % DF 1489 -deprecated([{string,0,\"hello\"}]). % DF 1490 1491 t() -> 1492 g(1,2, 3), 1493 ?MODULE:f(10). 1494 1495 f(A) -> 1496 ?MODULE:f(A,A). 1497 1498 f(X, Y) -> 1499 ?MODULE:g(X, Y, X). 1500 1501 g(F, G, H) -> 1502 ?MODULE:bar(F, {G,H}). 1503 1504 string() -> 1505 ?MODULE:string(). 1506 1507 bar(_, _) -> 1508 ?MODULE:t(). 1509 ">>, 1510 1511 ok = file:write_file(File, Test2), 1512 {ok, depr} = compile:file(File, [debug_info,{outdir,Dir}]), 1513 1514 {ok, _} = xref:start(s), 1515 {ok, depr} = xref:add_module(s, MFile), 1516 1517 M = depr, 1518 DFa_1 = usort([{{M,f,2},{M,g,3}}]), 1519 DFa_2 = usort(DFa_1++[{{M,f,1},{M,f,2}},{{M,t,0},{M,f,1}}]), 1520 DFa_3 = usort(DFa_2++[{{M,bar,2},{M,t,0}},{{M,g,3},{M,bar,2}}, 1521 {{M,string,0},{M,string,0}}]), 1522 DFa = DFa_3, 1523 1524 {ok,DFa} = xref:analyze(s, deprecated_function_calls), 1525 {ok,DFa_1} = 1526 xref:analyze(s, {deprecated_function_calls,next_version}), 1527 {ok,DFa_2} = 1528 xref:analyze(s, {deprecated_function_calls,next_major_release}), 1529 {ok,DFa_3} = 1530 xref:analyze(s, {deprecated_function_calls,eventually}), 1531 1532 ok = check_state(s), 1533 xref:stop(s), 1534 1535 %% All of the module is deprecated. 1536 Test3= <<"-module(depr). 1537 1538 -export([t/0,f/1,bar/2,f/2,g/3]). 1539 1540 -deprecated([{f,'_',next_major_release}]). % DF_2 1541 -deprecated([{g,'_',next_version}]). % DF_1 1542 -deprecated(module). % DF 1543 1544 t() -> 1545 g(1,2, 3), 1546 ?MODULE:f(10). 1547 1548 f(A) -> 1549 ?MODULE:f(A,A). 1550 1551 f(X, Y) -> 1552 ?MODULE:g(X, Y, X). 1553 1554 g(F, G, H) -> 1555 ?MODULE:bar(F, {G,H}). 1556 1557 bar(_, _) -> 1558 ?MODULE:t(). 1559 ">>, 1560 1561 ok = file:write_file(File, Test3), 1562 {ok, depr} = compile:file(File, [debug_info,{outdir,Dir}]), 1563 1564 {ok, _} = xref:start(s), 1565 {ok, depr} = xref:add_module(s, MFile), 1566 1567 DFb_1 = usort([{{M,f,2},{M,g,3}}]), 1568 DFb_2 = usort(DFb_1++[{{M,f,1},{M,f,2}},{{M,t,0},{M,f,1}}]), 1569 DFb_3 = DFb_2, 1570 DFb = usort(DFb_2++[{{M,bar,2},{M,t,0}},{{M,g,3},{M,bar,2}}]), 1571 1572 {ok,DFb} = xref:analyze(s, deprecated_function_calls), 1573 {ok,DFb_1} = 1574 xref:analyze(s, {deprecated_function_calls,next_version}), 1575 {ok,DFb_2} = 1576 xref:analyze(s, {deprecated_function_calls,next_major_release}), 1577 {ok,DFb_3} = 1578 xref:analyze(s, {deprecated_function_calls,eventually}), 1579 1580 ok = check_state(s), 1581 xref:stop(s), 1582 1583 ok = file:delete(File), 1584 ok = file:delete(Beam), 1585 ok. 1586 1587 1588%% OTP-5152: try/catch, final (?) version. 1589trycatch(Conf) when is_list(Conf) -> 1590 Dir = ?copydir, 1591 File = fname(Dir, "trycatch.erl"), 1592 MFile = fname(Dir, "trycatch"), 1593 Beam = fname(Dir, "trycatch.beam"), 1594 Test = <<"-module(trycatch). 1595 1596 -export([trycatch/0]). 1597 1598 trycatch() -> 1599 try 1600 foo:bar(), 1601 bar:foo() of 1602 1 -> foo:foo(); 1603 2 -> bar:bar() 1604 catch 1605 error:a -> err:e1(); 1606 error:b -> err:e2() 1607 after 1608 fini:shed() 1609 end. 1610 ">>, 1611 1612 ok = file:write_file(File, Test), 1613 {ok, trycatch} = compile:file(File, [debug_info,{outdir,Dir}]), 1614 1615 {ok, _} = xref:start(s), 1616 {ok, trycatch} = xref:add_module(s, MFile), 1617 A = trycatch, 1618 {ok,[{{{A,A,0},{bar,bar,0}},[10]}, 1619 {{{A,A,0},{bar,foo,0}},[8]}, 1620 {{{A,A,0},{err,e1,0}},[12]}, 1621 {{{A,A,0},{err,e2,0}},[13]}, 1622 {{{A,A,0},{fini,shed,0}},[15]}, 1623 {{{A,A,0},{foo,bar,0}},[7]}, 1624 {{{A,A,0},{foo,foo,0}},[9]}]} = 1625 xref:q(s, "(Lin) (E | trycatch:trycatch/0)"), 1626 1627 ok = check_state(s), 1628 xref:stop(s), 1629 1630 ok = file:delete(File), 1631 ok = file:delete(Beam), 1632 ok. 1633 1634 1635%% OTP-5653: fun M:F/A. 1636fun_mfa(Conf) when is_list(Conf) -> 1637 Dir = ?copydir, 1638 File = fname(Dir, "fun_mfa.erl"), 1639 MFile = fname(Dir, "fun_mfa"), 1640 Beam = fname(Dir, "fun_mfa.beam"), 1641 Test = <<"-module(fun_mfa). 1642 1643 -export([t/0, t1/0, t2/0, t3/0]). 1644 1645 t() -> 1646 F = fun ?MODULE:t/0, 1647 (F)(). 1648 1649 t1() -> 1650 F = fun t/0, 1651 (F)(). 1652 1653 t2() -> 1654 fun ?MODULE:t/0(). 1655 1656 t3() -> 1657 fun t3/0(). 1658 ">>, 1659 1660 ok = file:write_file(File, Test), 1661 A = fun_mfa, 1662 {ok, A} = compile:file(File, [debug_info,{outdir,Dir}]), 1663 {ok, _} = xref:start(s), 1664 {ok, A} = xref:add_module(s, MFile, {warnings,false}), 1665 {ok, [{{{A,t,0},{'$M_EXPR','$F_EXPR',0}},[7]}, 1666 {{{A,t,0},{A,t,0}},[6]}, 1667 {{{A,t1,0},{'$M_EXPR','$F_EXPR',0}},[11]}, 1668 {{{A,t1,0},{A,t,0}},[10]}, 1669 {{{A,t2,0},{A,t,0}},[14]}, 1670 {{{A,t3,0},{fun_mfa,t3,0}},[17]}]} = 1671 xref:q(s, "(Lin) E"), 1672 1673 ok = check_state(s), 1674 xref:stop(s), 1675 1676 ok = file:delete(File), 1677 ok = file:delete(Beam), 1678 ok. 1679 1680%% Same as the previous test case, except that we use a BEAM file 1681%% that was compiled by an R14 compiler to test backward compatibility. 1682fun_mfa_r14(Conf) when is_list(Conf) -> 1683 Dir = proplists:get_value(data_dir, Conf), 1684 MFile = fname(Dir, "fun_mfa_r14"), 1685 1686 A = fun_mfa_r14, 1687 {ok, _} = xref:start(s), 1688 {ok, A} = xref:add_module(s, MFile, {warnings,false}), 1689 {ok, [{{{A,t,0},{'$M_EXPR','$F_EXPR',0}},[7]}, 1690 {{{A,t,0},{A,t,0}},[6]}, 1691 {{{A,t1,0},{'$M_EXPR','$F_EXPR',0}},[11]}, 1692 {{{A,t1,0},{A,t,0}},[10]}, 1693 {{{A,t2,0},{A,t,0}},[14]}, 1694 {{{A,t3,0},{A,t3,0}},[17]}]} = 1695 xref:q(s, "(Lin) E"), 1696 1697 ok = check_state(s), 1698 xref:stop(s), 1699 1700 ok. 1701 1702%% fun M:F/A with varibles. 1703fun_mfa_vars(Conf) when is_list(Conf) -> 1704 Dir = ?copydir, 1705 File = fname(Dir, "fun_mfa_vars.erl"), 1706 MFile = fname(Dir, "fun_mfa_vars"), 1707 Beam = fname(Dir, "fun_mfa_vars.beam"), 1708 Test = <<"-module(fun_mfa_vars). 1709 1710 -export([t/1, t1/1, t2/3]). 1711 1712 t(Mod) -> 1713 F = fun Mod:bar/2, 1714 (F)(a, b). 1715 1716 t1(Name) -> 1717 F = fun ?MODULE:Name/1, 1718 (F)(a). 1719 1720 t2(Mod, Name, Arity) -> 1721 F = fun Mod:Name/Arity, 1722 (F)(a). 1723 1724 t3(Arity) -> 1725 F = fun ?MODULE:t/Arity, 1726 (F)(1, 2, 3). 1727 1728 t4(Mod, Name) -> 1729 F = fun Mod:Name/3, 1730 (F)(a, b, c). 1731 1732 t5(Mod, Arity) -> 1733 F = fun Mod:t/Arity, 1734 (F)(). 1735 ">>, 1736 1737 ok = file:write_file(File, Test), 1738 A = fun_mfa_vars, 1739 {ok, A} = compile:file(File, [report,debug_info,{outdir,Dir}]), 1740 {ok, _} = xref:start(s), 1741 {ok, A} = xref:add_module(s, MFile, {warnings,false}), 1742 {ok, [{{{A,t,1},{'$M_EXPR','$F_EXPR',2}},[7]}, 1743 {{{A,t,1},{'$M_EXPR',bar,2}},[6]}, 1744 {{{A,t1,1},{'$M_EXPR','$F_EXPR',1}},[11]}, 1745 {{{A,t1,1},{A,'$F_EXPR',1}},[10]}, 1746 {{{A,t2,3},{'$M_EXPR','$F_EXPR',-1}},[14]}, 1747 {{{A,t2,3},{'$M_EXPR','$F_EXPR',1}},[15]}, 1748 {{{A,t3,1},{'$M_EXPR','$F_EXPR',3}},[19]}, 1749 {{{A,t3,1},{fun_mfa_vars,t,-1}},[18]}, 1750 {{{A,t4,2},{'$M_EXPR','$F_EXPR',3}},[22,23]}, 1751 {{{A,t5,2},{'$M_EXPR','$F_EXPR',0}},[27]}, 1752 {{{A,t5,2},{'$M_EXPR',t,-1}},[26]}]} = 1753 xref:q(s, "(Lin) E"), 1754 1755 ok = check_state(s), 1756 xref:stop(s), 1757 1758 ok = file:delete(File), 1759 ok = file:delete(Beam), 1760 ok. 1761 1762%% OTP-5195: A bug fix when using qlc:q/1,2. 1763qlc(Conf) when is_list(Conf) -> 1764 Dir = ?copydir, 1765 File = fname(Dir, "qlc.erl"), 1766 MFile = fname(Dir, "qlc"), 1767 Beam = fname(Dir, "qlc.beam"), 1768 Test = <<"-module(qlc). 1769 1770 -include_lib(\"stdlib/include/qlc.hrl\"). 1771 1772 -export([t/0]). 1773 1774 t() -> 1775 dets:open_file(t, []), 1776 dets:insert(t, [{1,a},{2,b},{3,c},{4,d}]), 1777 MS = ets:fun2ms(fun({X,Y}) when (X > 1) or (X < 5) -> {Y} 1778 end), 1779 QH1 = dets:table(t, [{traverse, {select, MS}}]), 1780 QH2 = qlc:q([{Y} || {X,Y} <- dets:table(t), 1781 (X > 1) or (X < 5)]), 1782 true = qlc:info(QH1) =:= qlc:info(QH2), 1783 dets:close(t), 1784 ok. 1785 ">>, 1786 1787 ok = file:write_file(File, Test), 1788 A = qlc, 1789 {ok, A} = compile:file(File, [debug_info,{outdir,Dir}]), 1790 {ok, _} = xref:start(s), 1791 {ok, A} = xref:add_module(s, MFile, {warnings,false}), 1792 {ok, _} = xref:q(s, "(Lin) E"), % is can be loaded 1793 1794 ok = check_state(s), 1795 xref:stop(s), 1796 1797 ok = file:delete(File), 1798 ok = file:delete(Beam), 1799 ok. 1800 1801 1802 1803%% Simple analyses 1804analyze(Conf) when is_list(Conf) -> 1805 S0 = new(), 1806 {{error, _, {invalid_options,[not_an_option]}}, _} = 1807 xref_base:analyze(S0, undefined_function_calls, [not_an_option]), 1808 {{error, _, {invalid_query,{q}}}, _} = xref_base:q(S0,{q}), 1809 {{error, _, {unknown_analysis,foo}}, _} = xref_base:analyze(S0, foo), 1810 {{error, _, {unknown_constant,"foo:bar/-1"}}, _} = 1811 xref_base:analyze(S0, {use,{foo,bar,-1}}), 1812 1813 CopyDir = ?copydir, 1814 Dir = fname(CopyDir,"rel2"), 1815 X = fname(Dir, "x.erl"), 1816 Y = fname(Dir, "y.erl"), 1817 A1_1 = fname([Dir,"lib","app1-1.1"]), 1818 A2 = fname([Dir,"lib","app2-1.1"]), 1819 EB1_1 = fname(A1_1, "ebin"), 1820 EB2 = fname(A2, "ebin"), 1821 Xbeam = fname(EB2, "x.beam"), 1822 Ybeam = fname(EB1_1, "y.beam"), 1823 1824 {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), 1825 {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), 1826 1827 {ok, rel2, S1} = xref_base:add_release(S0, Dir, [{verbose,false}]), 1828 S = set_up(S1), 1829 1830 {ok, _} = analyze(undefined_function_calls, [{{x,xx,0},{x,undef,0}}], S), 1831 {ok, _} = analyze(undefined_functions, [{x,undef,0}], S), 1832 {ok, _} = analyze(locals_not_used, [{x,l,0},{x,l1,0}], S), 1833 {ok, _} = analyze(exports_not_used, [{x,xx,0},{y,t,0}], S), 1834 1835 {ok, _} = analyze(deprecated_function_calls, [{{y,t,0},{x,t,0}}], S), 1836 {ok, _} = analyze({deprecated_function_calls,next_version}, [], S), 1837 {ok, _} = analyze({deprecated_function_calls,next_major_release}, [], S), 1838 {ok, _} = analyze({deprecated_function_calls,eventually}, 1839 [{{y,t,0},{x,t,0}}], S), 1840 {ok, _} = analyze(deprecated_functions, [{x,t,0}], S), 1841 {ok, _} = analyze({deprecated_functions,next_version}, [], S), 1842 {ok, _} = analyze({deprecated_functions,next_major_release}, [], S), 1843 {ok, _} = analyze({deprecated_functions,eventually}, [{x,t,0}], S), 1844 1845 {ok, _} = analyze({call, {x,xx,0}}, [{x,undef,0}], S), 1846 {ok, _} = analyze({call, [{x,xx,0},{x,l,0}]}, [{x,l1,0},{x,undef,0}], S), 1847 {ok, _} = analyze({use, {x,l,0}}, [{x,l1,0}], S), 1848 {ok, _} = analyze({use, [{x,l,0},{x,l1,0}]}, [{x,l,0},{x,l1,0}], S), 1849 1850 {ok, _} = analyze({module_call, x}, [x], S), 1851 {ok, _} = analyze({module_call, [x,y]}, [x], S), 1852 {ok, _} = analyze({module_use, x}, [x,y], S), 1853 {ok, _} = analyze({module_use, [x,y]}, [x,y], S), 1854 1855 {ok, _} = analyze({application_call, app1}, [app2], S), 1856 {ok, _} = analyze({application_call, [app1,app2]}, [app2], S), 1857 {ok, _} = analyze({application_use, app2}, [app1,app2], S), 1858 {ok, _} = analyze({application_use, [app1,app2]}, [app1,app2], S), 1859 1860 ok = xref_base:delete(S), 1861 ok = file:delete(Xbeam), 1862 ok = file:delete(Ybeam), 1863 ok. 1864 1865%% Use of operators 1866basic(Conf) when is_list(Conf) -> 1867 S0 = new(), 1868 1869 F1 = {m1,f1,1}, 1870 F6 = {m1,f2,6}, % X 1871 F2 = {m2,f1,2}, 1872 F3 = {m2,f2,3}, % X 1873 F7 = {m2,f3,7}, % X 1874 F4 = {m3,f1,4}, % X 1875 F5 = {m3,f2,5}, 1876 1877 UF1 = {m1,f12,17}, 1878 UF2 = {m17,f17,177}, 1879 1880 E1 = {F1,F3}, % X 1881 E2 = {F6,F7}, % X 1882 E3 = {F2,F6}, % X 1883 E4 = {F1,F4}, % X 1884 E5 = {F4,F5}, 1885 E6 = {F7,F4}, % X 1886 E7 = {F1,F6}, 1887 1888 UE1 = {F2,UF2}, % X 1889 UE2 = {F5,UF1}, % X 1890 1891 D1 = {F1,12}, 1892 D6 = {F6,3}, 1893 DefAt_m1 = [D1,D6], 1894 X_m1 = [F6], 1895 % L_m1 = [F1], 1896 XC_m1 = [E1,E2,E4], 1897 LC_m1 = [E7], 1898 LCallAt_m1 = [{E7,12}], 1899 XCallAt_m1 = [{E1,13},{E2,17},{E4,7}], 1900 Info1 = #xref_mod{name = m1, app_name = [a1]}, 1901 S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, 1902 XC_m1, LC_m1), 1903 1904 D2 = {F2,7}, 1905 D3 = {F3,9}, 1906 D7 = {F7,19}, 1907 DefAt_m2 = [D2,D3,D7], 1908 X_m2 = [F3,F7], 1909 % L_m2 = [F2], 1910 XC_m2 = [E3,E6,UE1], 1911 LC_m2 = [], 1912 LCallAt_m2 = [], 1913 XCallAt_m2 = [{E3,96},{E6,12},{UE1,77}], 1914 Info2 = #xref_mod{name = m2, app_name = [a2]}, 1915 S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, 1916 XC_m2, LC_m2), 1917 1918 D4 = {F4,6}, 1919 D5 = {F5,97}, 1920 DefAt_m3 = [D4,D5], 1921 X_m3 = [F4], 1922 % L_m3 = [F5], 1923 XC_m3 = [UE2], 1924 LC_m3 = [E5], 1925 LCallAt_m3 = [{E5,19}], 1926 XCallAt_m3 = [{UE2,22}], 1927 Info3 = #xref_mod{name = m3, app_name = [a3]}, 1928 S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, 1929 XC_m3, LC_m3), 1930 1931 Info4 = #xref_mod{name = m4, app_name = [a2]}, 1932 S4 = add_module(S3, Info4, [], [], [], [], [], []), 1933 1934 AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, 1935 S9 = add_application(S4, AppInfo1), 1936 AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, 1937 S10 = add_application(S9, AppInfo2), 1938 AppInfo3 = #xref_app{name = a3, rel_name = [r2]}, 1939 S11 = add_application(S10, AppInfo3), 1940 1941 RelInfo1 = #xref_rel{name = r1}, 1942 S12 = add_release(S11, RelInfo1), 1943 RelInfo2 = #xref_rel{name = r2}, 1944 S13 = add_release(S12, RelInfo2), 1945 1946 S = set_up(S13), 1947 1948 {ok, _} = eval("[m1,m2] + m:f/1", unknown_constant, S), 1949 {ok, _} = eval("[m1, m2, m:f/1]", type_mismatch, S), 1950 1951 {ok, _} = eval("[m1, m1->m2]", type_mismatch, S), 1952 {ok, _} = eval("components:f/1", unknown_constant, S), 1953 {ok, _} = eval("'of':f/1", unknown_constant, S), 1954 {ok, _} = eval("of:f/1", parse_error, S), 1955 {ok, _} = eval("components", unknown_constant, S), 1956 {ok, _} = eval("[components, of, closure]", parse_error, S), 1957 {ok, _} = eval("[components, 'of', closure]", unknown_constant, S), 1958 1959 {ok, _} = eval("[a1->a2,m1->m2]", type_mismatch, S), 1960 {ok, _} = eval("a1->a2,m1->m2", parse_error, S), 1961 1962 {ok, _} = eval("m1->a1", type_mismatch, S), 1963 {ok, _} = eval("[{m1,f1,1}] : App", parse_error, S), 1964 {ok, _} = eval("[{m1,f1,1}] : Fun", [F1], S), 1965 {ok, _} = eval("range X", type_error, S), 1966 {ok, _} = eval("domain X", type_error, S), 1967 {ok, _} = eval("range M", type_error, S), 1968 {ok, _} = eval("domain M", type_error, S), 1969 1970 % Misc. 1971 {ok, _} = eval("not_a_prefix_operator m1", parse_error, S), 1972 {ok, _} = eval(f("(Mod) ~p", [[F1,F6,F5]]), [m1,m3], S), 1973 {ok, _} = eval("(Lin) M - (Lin) m1", 1974 [{F2,7},{F3,9},{F7,19},{F4,6},{F5,97},{UF2,0}], S), 1975 {ok, _} = eval(f("(Lin) M * (Lin) ~p", [[F1,F6]]), 1976 [{F1,12},{F6,3}], S), 1977 1978 {ok, _} = eval(f("X * ~p", [[F1, F2, F3, F4, F5]]), [F3, F4], S), 1979 {ok, _} = eval("X", [F6,F3,F7,F4], S), 1980 {ok, _} = eval("X * AM", [F6,F3,F7,F4], S), 1981 {ok, _} = eval("X * a2", [F3,F7], S), 1982 1983 {ok, _} = eval("L * r1", [F1,F2], S), 1984 {ok, _} = eval("U", [UF1, UF2], S), 1985 {ok, _} = eval("U * AM", [UF1], S), 1986 {ok, _} = eval("U * UM", [UF2], S), 1987 {ok, _} = eval("XU * [m1, m2]", [F6,F3,F7,UF1], S), 1988 {ok, _} = eval("LU * [m3, m4]", [F5], S), 1989 {ok, _} = eval("UU", [F1,F2], S), 1990 1991 {ok, _} = eval("XC | m1", [E1,E2,E4], S), 1992 {ok, _} = eval(f("XC | ~p", [F1]), [E1,E4], S), 1993 {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), 1994 [{{D1,D3},[13]},{{D1,D4},[7]}],S), 1995 {ok, _} = eval(f("XC | (~p + ~p)", [F1, F2]), [E1,E4,E3,UE1], S), 1996 {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), 1997 [{{D1,D3},[13]},{{D1,D4},[7]}], S), 1998 {ok, _} = eval("LC | m3", [E5], S), 1999 {ok, _} = eval(f("LC | ~p", [F1]), [E7], S), 2000 {ok, _} = eval(f("LC | (~p + ~p)", [F1, F4]), [E7, E5], S), 2001 {ok, _} = eval("E | m1", [E1,E2,E4,E7], S), 2002 {ok, _} = eval(f("E | ~p", [F1]), [E1,E7,E4], S), 2003 {ok, _} = eval(f("E | (~p + ~p)", [F1, F2]), [E1,E7,E4,E3,UE1], S), 2004 2005 {ok, _} = eval("XC || m1", [E3,UE2], S), 2006 {ok, _} = eval(f("XC || ~p", [F6]), [E3], S), 2007 {ok, _} = eval(f("XC || (~p + ~p)", [F4, UF2]), [UE1,E4,E6], S), 2008 {ok, _} = eval("LC || m3", [E5], S), 2009 {ok, _} = eval(f("LC || ~p", [F1]), [], S), 2010 {ok, _} = eval(f("LC || ~p", [F6]), [E7], S), 2011 {ok, _} = eval(f("LC || (~p + ~p)", [F5, F6]), [E7,E5], S), 2012 {ok, _} = eval("E || m1", [E3,UE2,E7], S), 2013 {ok, _} = eval(f("E || ~p", [F6]), [E3,E7], S), 2014 {ok, _} = eval(f("E || (~p + ~p)", [F3,F4]), [E1,E4,E6], S), 2015 2016 {ok, _} = eval(f("~p + ~p", [F1,F2]), [F1,F2], S), 2017 {ok, _} = eval(f("~p * ~p", [m1,[F1,F6,F2]]), [F1,F6], S), 2018 {ok, _} = eval(f("~p * ~p", [F1,F2]), [], S), 2019 2020 %% range, domain 2021 {ok, _} = eval("range (E || m1)", [F6,UF1], S), 2022 {ok, _} = eval("domain (E || m1)", [F1,F2,F5], S), 2023 {ok, _} = eval(f("E | domain ~p", [[E1, {F2,F4}]]), 2024 [E1,E7,E4,E3,UE1], S), 2025 2026 %% components, condensation, use, call 2027 {ok, _} = eval("(Lin) components E", type_error, S), 2028 {ok, _} = eval("components (Lin) E", type_error, S), 2029 {ok, _} = eval("components V", type_error, S), 2030 {ok, _} = eval("components E + components E", type_error, S), 2031 2032 {ok, _} = eval(f("range (closure E | ~p)", [[F1,F2]]), 2033 [F6,F3,F7,F4,F5,UF1,UF2], S), 2034 {ok, _} = 2035 eval(f("domain (closure E || ~p)", [[UF2,F7]]), [F1,F2,F6], S), 2036 {ok, _} = eval("components E", [], S), 2037 {ok, _} = eval("components (Mod) E", [[m1,m2,m3]], S), 2038 {ok, _} = eval("components closure (Mod) E", [[m1,m2,m3]], S), 2039 {ok, _} = eval("condensation (Mod) E", 2040 [{[m1,m2,m3],[m17]}], S), 2041 {ok, _} = eval("condensation closure (Mod) E", 2042 [{[m1,m2,m3],[m17]}], S), 2043 {ok, _} = eval("condensation closure closure closure (Mod) E", 2044 [{[m1,m2,m3],[m17]}], S), 2045 {ok, _} = eval("weak condensation (Mod) E", 2046 [{[m1,m2,m3],[m1,m2,m3]},{[m1,m2,m3],[m17]},{[m17],[m17]}], S), 2047 {ok, _} = eval("strict condensation (Mod) E", 2048 [{[m1,m2,m3],[m17]}], S), 2049 {ok, _} = eval("range condensation (Mod) E", 2050 [[m17]], S), 2051 {ok, _} = eval("domain condensation (Mod) E", 2052 [[m1,m2,m3]], S), 2053 2054 %% |, ||, ||| 2055 {ok, _} = eval("(Lin) E || V", type_error, S), 2056 {ok, _} = eval("E ||| (Lin) V", type_error, S), 2057 {ok, _} = eval("E ||| m1", [E7], S), 2058 {ok, _} = eval("closure E ||| m1", [E7,{F1,UF1},{F6,UF1}], S), 2059 {ok, _} = eval("closure E ||| [m1,m2]", 2060 [{F1,UF1},{F2,F7},{F1,F7},{F6,UF1},{F2,UF1},{F7,UF1},E7,E1,E2,E3], S), 2061 {ok, _} = eval("AE | a1", [{a1,a1},{a1,a2},{a1,a3}], S), 2062 2063 %% path ('of') 2064 {ok, _} = eval("(Lin) {m1,m2} of E", type_error, S), 2065 {ok, _} = eval("{m1,m2} of (Lin) E", type_error, S), 2066 [m1,m2] = eval("{m1,m2} of {m1,m2}", S), 2067 {ok, _} = eval("{m1,m2} of m1", type_error, S), 2068 {ok, _} = eval("{a3,m1} of ME", type_mismatch, S), 2069 [m1,m1] = eval("{m1} of ME", S), 2070 [m1,m1] = eval("{m1} of closure closure ME", S), 2071 false = eval("{m17} of ME", S), 2072 [m2,m1,m2] = eval("{m2} : Mod of ME", S), 2073 [m1,m2,m17] = eval("{m1, m17} of ME", S), 2074 [m1,m2,m17] = eval("m1 -> m17 of ME", S), 2075 {ok, _} = eval("[m1->m17,m17->m1] of ME", type_error, S), 2076 case eval(f("~p of E", [{F1,F7,UF1}]), S) of 2077 [F1,F6,F7,F4,F5,UF1] -> ok 2078 end, 2079 [a2,a1,a2] = eval("{a2} of AE", S), 2080 2081 %% weak/strict 2082 {ok, _} = eval("weak {m1,m2}", [{m1,m1},{m1,m2},{m2,m2}], S), 2083 {ok, _} = eval("strict [{m1,m1},{m1,m2},{m2,m2}]", [{m1,m2}], S), 2084 {ok, _} = eval("range weak [{m1,m2}] : Mod", [m1,m2], S), 2085 {ok, _} = eval("domain strict [{m1,m1},{m1,m2},{m2,m2}]", [m1], S), 2086 2087 %% #, number of 2088 {ok, _} = eval("# [{r1,r2}] : Rel", 1, S), 2089 {ok, _} = eval("# [{a3,a1}] : App", 1, S), 2090 {ok, _} = eval("# AE", 7, S), 2091 {ok, _} = eval("# ME", 8, S), 2092 {ok, _} = eval("# AE + # ME", 15, S), 2093 {ok, _} = eval("# AE * # ME", 56, S), 2094 {ok, _} = eval("# AE - # ME", -1, S), 2095 {ok, _} = eval("# E", 9, S), 2096 {ok, _} = eval("# V", 9, S), 2097 {ok, _} = eval("# (Lin) E", 9, S), 2098 {ok, _} = eval("# (ELin) E", 7, S), 2099 {ok, _} = eval("# closure E", type_error, S), 2100 {ok, _} = eval("# weak {m1,m2}", 3, S), 2101 {ok, _} = eval("#strict condensation (Mod) E", 1, S), 2102 {ok, _} = eval("#components closure (Mod) E", 1, S), 2103 {ok, _} = eval("# range strict condensation (Mod) E", 1, S), 2104 ok. 2105 2106%% The xref:m() and xref:d() functions 2107md(Conf) when is_list(Conf) -> 2108 CopyDir = ?copydir, 2109 Dir = fname(CopyDir,"md"), 2110 X = fname(Dir, "x__x.erl"), 2111 Y = fname(Dir, "y__y.erl"), 2112 Xbeam = fname(Dir, "x__x.beam"), 2113 Ybeam = fname(Dir, "y__y.beam"), 2114 2115 {error, _, {invalid_filename,{foo,bar}}} = xref:m({foo,bar}), 2116 {error, _, {invalid_filename,{foo,bar}}} = xref:d({foo,bar}), 2117 2118 {ok, x__x} = compile:file(X, [debug_info, {outdir,Dir}]), 2119 {ok, y__y} = compile:file(Y, [debug_info, {outdir,Dir}]), 2120 2121 {error, _, {no_such_module, foo_bar}} = xref:m(foo_bar), 2122 OldPath = code:get_path(), 2123 true = code:set_path([Dir | OldPath]), 2124 MInfo = xref:m(x__x), 2125 [{{x__x,t,1},{y__y,t,2}}] = info_tag(MInfo, undefined), 2126 [] = info_tag(MInfo, unused), 2127 [] = info_tag(MInfo, deprecated), 2128 DInfo = xref:d(Dir), 2129 [{{x__x,t,1},{y__y,t,2}}] = info_tag(DInfo, undefined), 2130 [{y__y,l,0},{y__y,l1,0}] = info_tag(DInfo, unused), 2131 [] = info_tag(MInfo, deprecated), 2132 2133 %% Switch from 'functions' mode to 'modules' mode. 2134 {ok, x__x} = compile:file(X, [no_debug_info, {outdir,Dir}]), 2135 {ok, y__y} = compile:file(Y, [no_debug_info, {outdir,Dir}]), 2136 MInfoMod = xref:m(x__x), 2137 [{y__y,t,2}] = info_tag(MInfoMod, undefined), 2138 [] = info_tag(MInfo, deprecated), 2139 DInfoMod = xref:d(Dir), 2140 [{y__y,t,2}] = info_tag(DInfoMod, undefined), 2141 [] = info_tag(MInfo, deprecated), 2142 2143 true = code:set_path(OldPath), 2144 ok = file:delete(Xbeam), 2145 ok = file:delete(Ybeam), 2146 ok. 2147 2148%% User queries 2149q(Conf) when is_list(Conf) -> 2150 S0 = new(), 2151 {ok, _} = eval("'foo", parse_error, S0), 2152 {ok, _} = eval("TT = E, TT = V", variable_reassigned, S0), 2153 {ok, _} = eval("TT = E, TTT", unknown_variable, S0), 2154 {ok, S} = eval("TT := E", [], S0), 2155 {ok, S1} = eval("TT * TT * TT", [], S), 2156 {ok, _S2} = xref_base:forget(S1, 'TT'), 2157 ok. 2158 2159%% Setting and getting values of query variables 2160variables(Conf) when is_list(Conf) -> 2161 Sa = new(), 2162 {{error, _, {invalid_options,[not_an_option]}}, _} = 2163 xref_base:variables(Sa, [not_an_option]), 2164 {error, _, {not_user_variable,foo}} = xref_base:forget(Sa, foo), 2165 Sa1 = set_up(Sa), 2166 {error, _, {not_user_variable,foo}} = xref_base:forget(Sa1, foo), 2167 ok = xref_base:delete(Sa1), 2168 2169 S0 = new(), 2170 2171 F1 = {m1,f1,1}, 2172 F2 = {m2,f1,2}, 2173 Lib = {lib1,f1,1}, % undefined 2174 2175 E1 = {F1,F2}, 2176 E2 = {F2,F1}, 2177 E3 = {F1,Lib}, 2178 2179 D1 = {F1,12}, 2180 DefAt_m1 = [D1], 2181 X_m1 = [F1], 2182 % L_m1 = [], 2183 XC_m1 = [E1,E3], 2184 LC_m1 = [], 2185 LCallAt_m1 = [], 2186 XCallAt_m1 = [{E1,13},{E3,17}], 2187 Info1 = #xref_mod{name = m1, app_name = [a1]}, 2188 S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, 2189 XC_m1, LC_m1), 2190 2191 D2 = {F2,7}, 2192 DefAt_m2 = [D2], 2193 X_m2 = [F2], 2194 % L_m2 = [], 2195 XC_m2 = [E2], 2196 LC_m2 = [], 2197 LCallAt_m2 = [], 2198 XCallAt_m2 = [{E2,96}], 2199 Info2 = #xref_mod{name = m2, app_name = [a2]}, 2200 S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, 2201 XC_m2, LC_m2), 2202 2203 S = set_up(S2), 2204 2205 eval("T1=E, T2=E*T1, T3 = T2*T2, T4=range T3, T5=T3|T4, T5", 2206 [E1,E2,E3], S), 2207 eval("((E*E)*(E*E)) | (range ((E*E)*(E*E)))", 2208 [E1,E2,E3], S), 2209 eval("T1=V*V,T2=T1*V,T3=V*V*V,T3", 2210 [F1,F2,Lib], S), 2211 eval("T1=V*V, T2=V*V, T1*T2", 2212 [F1,F2,Lib], S), 2213 2214 {ok, S100} = eval("T0 := E", [E1, E2, E3], S), 2215 {ok, S101} = eval("T1 := E | m1", [E1, E3], S100), 2216 {ok, S102} = eval("T2 := E | m2", [E2], S101), 2217 {{ok, [{user, ['T0', 'T1', 'T2']}]}, _} = xref_base:variables(S102), 2218 {ok, S103} = xref_base:forget(S102, 'T0'), 2219 {{ok, [{user, ['T1', 'T2']}]}, S104} = 2220 xref_base:variables(S103, [user]), 2221 {ok, S105} = xref_base:forget(S104), 2222 {{ok, [{user, []}]}, S106} = xref_base:variables(S105), 2223 {{ok, [{predefined,_}]}, S107_0} = 2224 xref_base:variables(S106, [predefined]), 2225 2226 {ok, S107_1} = 2227 eval("TT := E, TT2 := V, TT1 := TT * TT", [E1,E2,E3], S107_0), 2228 {{ok, [{user, ['TT', 'TT1', 'TT2']}]}, _} = 2229 xref_base:variables(S107_1), 2230 {ok, S107} = xref_base:forget(S107_1), 2231 2232 CopyDir = ?copydir, 2233 Dir = fname(CopyDir,"lib_test"), 2234 Beam = fname(Dir, "lib1.beam"), 2235 2236 copy_file(fname(Dir, "lib1.erl"), Beam), 2237 {ok, S108} = 2238 xref_base:set_library_path(S107, [Dir], [{verbose,false}]), 2239 {{error, _, _}, _} = xref_base:variables(S108, [{verbose,false}]), 2240 {ok, S109} = xref_base:set_library_path(S108, [], [{verbose,false}]), 2241 2242 NoOfTables = erlang:system_info(ets_count), 2243 2244 {ok, S110} = eval("Eplus := closure E, TT := Eplus", 2245 'closure()', S109), 2246 {{ok, [{user, ['Eplus','TT']}]}, S111} = xref_base:variables(S110), 2247 {ok, S112} = xref_base:forget(S111, ['TT','Eplus']), 2248 true = NoOfTables =:= erlang:system_info(ets_count), 2249 2250 {ok, NS0} = eval("Eplus := closure E", 'closure()', S112), 2251 {{ok, [{user, ['Eplus']}]}, NS} = xref_base:variables(NS0), 2252 ok = xref_base:delete(NS), 2253 true = NoOfTables =:= erlang:system_info(ets_count), 2254 2255 ok = file:delete(Beam), 2256 ok. 2257 2258%% OTP-5071. Too many unused functions. 2259unused_locals(Conf) when is_list(Conf) -> 2260 Dir = ?copydir, 2261 2262 File1 = fname(Dir, "a.erl"), 2263 MFile1 = fname(Dir, "a"), 2264 Beam1 = fname(Dir, "a.beam"), 2265 Test1 = <<"-module(a). 2266 -export([f/1, g/2]). 2267 2268 f(X) -> 2269 Y = b:f(X), 2270 Z = b:g(Y), 2271 start(b, h, [Z]). 2272 2273 g(X, Y) -> 2274 ok. 2275 2276 start(M, F, A) -> 2277 spawn(M, F, A). 2278 ">>, 2279 ok = file:write_file(File1, Test1), 2280 {ok, a} = compile:file(File1, [debug_info,{outdir,Dir}]), 2281 2282 File2 = fname(Dir, "b.erl"), 2283 MFile2 = fname(Dir, "b"), 2284 Beam2 = fname(Dir, "b.beam"), 2285 Test2 = <<"-module(b). 2286 -export([f/1, g/2]). 2287 2288 f(X) -> 2289 io:write(\"~w\", [X]), 2290 a:start(timer, sleep, [1000]). 2291 2292 g(X, Y) -> 2293 apply(a, g, [X, Y]). 2294 ">>, 2295 2296 ok = file:write_file(File2, Test2), 2297 {ok, b} = compile:file(File2, [debug_info,{outdir,Dir}]), 2298 2299 {ok, _} = xref:start(s), 2300 {ok, a} = xref:add_module(s, MFile1), 2301 {ok, b} = xref:add_module(s, MFile2), 2302 {ok, []} = xref:analyse(s, locals_not_used), 2303 ok = check_state(s), 2304 xref:stop(s), 2305 2306 ok = file:delete(File1), 2307 ok = file:delete(Beam1), 2308 ok = file:delete(File2), 2309 ok = file:delete(Beam2), 2310 ok. 2311 2312 2313%% Format error messages 2314format_error(Conf) when is_list(Conf) -> 2315 {ok, _Pid} = start(s), 2316 ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), 2317 2318 %% Parse error messages. 2319 "Invalid regular expression \"add(\"" ++ _ = fstring(xref:q(s,'"add("')), 2320 'Invalid operator foo\n' = fatom(xref:q(s,'foo E')), 2321 'Invalid wildcard variable \'_Var\' (only \'_\' is allowed)\n' 2322 = fatom(xref:q(s,"module:function/_Var")), 2323 'Missing type of regular expression ".*"\n' 2324 = fatom(xref:q(s,'".*"')), 2325 'Type does not match structure of constant: \'M\' : Fun\n' 2326 = fatom(xref:q(s,"'M' : Fun")), 2327 'Type does not match structure of constant: ".*" : Fun\n' 2328 = fatom(xref:q(s,'".*" : Fun')), 2329 'Type does not match structure of constant: [m:f/1, m1:f2/3] : App\n' 2330 = fatom(xref:q(s,"[m:f/1,m1:f2/3] : App")), 2331 'Parse error on line 1: syntax error before: \'-\'\n' 2332 = fatom(xref:q(s,"E + -")), 2333 "Parse error on line 1: unterminated atom starting with 'foo'\n" 2334 = flatten(xref:format_error(xref:q(s,"'foo"))), 2335 'Parse error at end of string: syntax error before: \n' 2336 = fatom(xref:q(s,"E +")), 2337 'Parse error on line 1: syntax error before: \'Lin\'\n' 2338 = fatom(xref:q(s,"Lin")), 2339 2340 %% Other messages 2341 'Variable \'QQ\' used before set\n' = fatom(xref:q(s,"QQ")), 2342 'Unknown constant a\n' = fatom(xref:q(s,"{a} of E")), 2343 2344 %% Testing xref_parser:t2s/1. 2345 'Variable assigned more than once: E := E + E\n' = fatom(xref:q(s,"E:=E + E")), 2346 'Variable assigned more than once: E = E + E\n' = fatom(xref:q(s,"E=E + E")), 2347 "Operator applied to argument(s) of different or invalid type(s): " 2348 "E + V * V\n" = flatten(xref:format_error(xref:q(s,"E + (V * V)"))), 2349 {error,xref_compiler,{type_error,"(V + V) * E"}} = xref:q(s,"(V + V) * E"), 2350 "Type does not match structure of constant: [m:f/3 -> g:h/17] : " 2351 "App\n" = flatten(xref:format_error(xref:q(s,"[{{m,f,3},{g,h,17}}] : App"))), 2352 'Type does not match structure of constant: [m -> f, g -> h] : Fun\n' 2353 = fatom(xref:q(s,"[{m,f},g->h] : Fun")), 2354 'Type does not match structure of constant: {m, n, o} : Fun\n' = 2355 fatom(xref:q(s,"{m,n,o} : Fun")), 2356 {error,xref_compiler,{type_error,"range (Lin) V"}} = 2357 xref:q(s,"range ((Lin) V)"), 2358 {error,xref_compiler,{type_error,"condensation range E"}} = 2359 xref:q(s,"condensation (range E)"), 2360 {error,xref_compiler,{type_error,"condensation (# E + # V)"}} = 2361 xref:q(s,"condensation (# E + # V)"), 2362 {error,xref_compiler,{type_error,"range (# E + # E)"}} = 2363 xref:q(s,"range (#E + #E)"), 2364 {error,xref_compiler,{type_error,"range (# E)"}} = 2365 xref:q(s,"range #E"), % Hm... 2366 {error,xref_compiler,{type_error,"E + # E"}} = 2367 xref:q(s,"E + #E + #E"), % Hm... 2368 {error,xref_compiler,{type_error,"V * E || V | V"}} = 2369 xref:q(s,"V * (E || V) | V"), 2370 {error,xref_compiler,{type_error,"E || (E | V)"}} = 2371 xref:q(s,"V * E || (E | V)"), 2372 {error,xref_compiler,{type_error,"E * \"m\" : Mod"}} = 2373 xref:q(s,'E * "m" : Mod'), 2374 {error,xref_compiler,{type_error,"E * (\"m\":f/_ + m:\"f\"/3)"}} = 2375 xref:q(s,'E * ("m":f/_ + m:"f"/3)'), 2376 2377 xref:stop(s), 2378 ok. 2379 2380%% OTP-7423. Xref scanner bug. 2381otp_7423(Conf) when is_list(Conf) -> 2382 {ok, _Pid} = start(s), 2383 S = "E | [compiler] : App || [{erlang, 2384 size, 2385 1}] : Fun", 2386 {error,xref_compiler,{unknown_constant,"compiler"}} = xref:q(s,S), 2387 xref:stop(s), 2388 ok. 2389 2390%% OTP-7831. Allow anonymous Xref processes. 2391otp_7831(Conf) when is_list(Conf) -> 2392 {ok, Pid1} = xref:start([]), 2393 xref:stop(Pid1), 2394 {ok, Pid2} = xref:start([{xref_mode, modules}]), 2395 xref:stop(Pid2), 2396 ok. 2397 2398%% OTP-10192. Allow filenames with character codes greater than 126. 2399otp_10192(Conf) when is_list(Conf) -> 2400 PrivDir = ?privdir, 2401 {ok, _Pid} = xref:start(s), 2402 Dir = filename:join(PrivDir, "ä"), 2403 ok = file:make_dir(Dir), 2404 {ok, []} = xref:add_directory(s, Dir), 2405 xref:stop(s), 2406 ok. 2407 2408otp_13708(Conf) when is_list(Conf) -> 2409 {ok, _} = start(s), 2410 ok = xref:set_default(s, [{verbose, true}]), 2411 {ok, []} = xref:q(s,"E"), 2412 xref:stop(s), 2413 2414 CopyDir = ?copydir, 2415 Dir = fname(CopyDir,"lib_test"), 2416 {ok, _} = start(s), 2417 ok = xref:set_library_path(s, [Dir], [{verbose, true}]), 2418 xref:stop(s). 2419 2420%% OTP-14464. Unicode atoms. 2421otp_14464(Conf) when is_list(Conf) -> 2422 Dir = ?copydir, 2423 2424 File1 = fname(Dir, "a.erl"), 2425 MFile1 = fname(Dir, "a"), 2426 Beam1 = fname(Dir, "a.beam"), 2427 Test1 = "-module(a). 2428 -export([ärlig/0, 'кlирилли́ческий атомB'/0]). 2429 2430 ärlig() -> 2431 'кlирилли́ческий атомB'. 2432 2433 'кlирилли́ческий атомB'() -> 2434 foo. 2435 ", 2436 ok = file:write_file(File1, unicode:characters_to_binary(Test1)), 2437 {ok, a} = compile:file(File1, [debug_info,{outdir,Dir}]), 2438 2439 {ok, _} = xref:start(s), 2440 {ok, a} = xref:add_module(s, MFile1), 2441 2442 {ok, [{a,ärlig,0}]} = xref:q(s, 'a:"ärlig"/0'), 2443 {ok, [{a,'кlирилли́ческий атомB',0}]} = 2444 xref:q(s, 'a:"кlирилли́ческий атомB"/0'), 2445 2446 xref:stop(s), 2447 ok = file:delete(File1), 2448 ok = file:delete(Beam1). 2449 2450%% OTP-14344. -on_load() attribute. 2451otp_14344(Conf) when is_list(Conf) -> 2452 Dir = ?copydir, 2453 2454 File1 = fname(Dir, "a.erl"), 2455 MFile1 = fname(Dir, "a"), 2456 Beam1 = fname(Dir, "a.beam"), 2457 Test1 = <<"-module(a). 2458 -on_load(init/0). 2459 init() -> do_init(). 2460 do_init() -> ok. 2461 ">>, 2462 ok = file:write_file(File1, Test1), 2463 {ok, a} = compile:file(File1, [debug_info,{outdir,Dir}]), 2464 2465 {ok, _} = xref:start(s), 2466 {ok, a} = xref:add_module(s, MFile1), 2467 2468 {ok, [{a,init,0}]} = xref:q(s, "OL"), 2469 {ok, []} = xref:analyze(s, locals_not_used), 2470 2471 xref:stop(s), 2472 ok = file:delete(File1), 2473 ok = file:delete(Beam1). 2474 2475%% PR-2752, ERL-1353, ERL-1476, GH-4192. 2476behaviour(Config) -> 2477 ModMode = [{xref_mode, modules}], 2478 FunMode = [], 2479 2480 Test1 = [{a, <<"-module(a). 2481 -callback a() -> ok. 2482 ">>}], 2483 {Undef1, UnusedExports1} = behaviour_test(Test1, Config, FunMode), 2484 [] = Undef1, 2485 [] = UnusedExports1, 2486 {Undef1m, UnusedExports1m} = behaviour_test(Test1, Config, ModMode), 2487 [] = Undef1m, 2488 [] = UnusedExports1m, 2489 2490 Test2 = [{a, <<"-module(a). 2491 -export([behaviour_info/1]). 2492 behaviour_info(_) -> 2493 ok. 2494 ">>}], 2495 {Undef2, UnusedExports2} = behaviour_test(Test2, Config, FunMode), 2496 [] = Undef2, 2497 [{a,behaviour_info,1}] = UnusedExports2, 2498 {Undef2m, UnusedExports2m} = behaviour_test(Test2, Config, ModMode), 2499 [] = Undef2m, 2500 %% Without abstract code it is not possible to determine if 2501 %% M:behaviour_info/1 is generated or not. The best we can do is 2502 %% to assume it is generated since it would otherwise always be 2503 %% returned as unused. 2504 [] = UnusedExports2m, 2505 2506 Test3 = [{a, <<"-module(a). 2507 -export([behaviour_info/1]). 2508 behaviour_info(_) -> 2509 ok. 2510 ">>}, 2511 {b, <<"-module(b). 2512 -export([bar/0]). 2513 bar() -> a:behaviour_info(callbacks). 2514 ">>}], 2515 {Undef3, UnusedExports3} = behaviour_test(Test3, Config, FunMode), 2516 [] = Undef3, 2517 [{b,bar,0}] = UnusedExports3, 2518 {Undef3m, UnusedExports3m} = behaviour_test(Test3, Config, ModMode), 2519 [] = Undef3m, 2520 [{b,bar,0}] = UnusedExports3m, 2521 ok. 2522 2523behaviour_test(Tests, Conf, Opts) -> 2524 {ok, _} = xref:start(s, Opts), 2525 add_modules(Tests, Conf), 2526 case lists:keyfind(xref_mode, 1, Opts) of 2527 {xref_mode, modules} -> 2528 UndefinedFunctionCalls = []; 2529 _ -> 2530 {ok, UndefinedFunctionCalls} = 2531 xref:analyze(s, undefined_function_calls) 2532 end, 2533 {ok, ExportsNotUsed} = xref:analyze(s, exports_not_used), 2534 xref:stop(s), 2535 {UndefinedFunctionCalls, ExportsNotUsed}. 2536 2537add_modules([], _Conf) -> 2538 ok; 2539add_modules([{Mod, Test} |Tests], Conf) -> 2540 Dir = ?copydir, 2541 Name = atom_to_list(Mod), 2542 File = fname(Dir, Name ++ ".erl"), 2543 MFile = fname(Dir, Name), 2544 Beam = fname(Dir, Name ++ ".beam"), 2545 ok = file:write_file(File, Test), 2546 {ok, Mod} = compile:file(File, [debug_info,{outdir,Dir}]), 2547 {ok, Mod} = xref:add_module(s, MFile), 2548 check_state(s), 2549 ok = file:delete(File), 2550 ok = file:delete(Beam), 2551 add_modules(Tests, Conf). 2552 2553%%% 2554%%% Utilities 2555%%% 2556 2557copy_file(Src, Dest) -> 2558 file:copy(Src, Dest). 2559 2560fname(N) -> 2561 filename:join(N). 2562 2563fname(Dir, Basename) -> 2564 filename:join(Dir, Basename). 2565 2566new() -> 2567 {ok, S} = xref_base:new(), 2568 S. 2569 2570set_up(S) -> 2571 {ok, S1} = xref_base:set_up(S, [{verbose, false}]), 2572 S1. 2573 2574eval(Query, E, S) -> 2575 ?format("------------------------------~n", []), 2576 ?format("Evaluating ~p~n", [Query]), 2577 {Answer, NewState} = xref_base:q(S, Query, [{verbose, false}]), 2578 {Reply, Expected} = 2579 case Answer of 2580 {ok, R} when is_list(E) -> 2581 {unsetify(R), sort(E)}; 2582 {ok, R} -> 2583 {unsetify(R), E}; 2584 {error, _Module, Reason} -> 2585 {element(1, Reason), E} 2586 end, 2587 if 2588 Reply =:= Expected -> 2589 ?format("As expected, got ~n~p~n", [Expected]), 2590 {ok, NewState}; 2591 true -> 2592 ?format("Expected ~n~p~nbut got ~n~p~n", [Expected, Reply]), 2593 not_ok 2594 end. 2595 2596analyze(Query, E, S) -> 2597 ?format("------------------------------~n", []), 2598 ?format("Evaluating ~p~n", [Query]), 2599 {{ok, L}, NewState} = 2600 xref_base:analyze(S, Query, [{verbose, false}]), 2601 case {unsetify(L), sort(E)} of 2602 {X,X} -> 2603 ?format("As was expected, got ~n~p~n", [X]), 2604 {ok, NewState}; 2605 {_R,_X} -> 2606 ?format("Expected ~n~p~nbut got ~n~p~n", [_X, _R]), 2607 not_ok 2608 end. 2609 2610unsetify(S) -> 2611 case is_sofs_set(S) of 2612 true -> to_external(S); 2613 false -> S 2614 end. 2615 2616%% Note: assumes S has been set up; the new state is not returned 2617eval(Query, S) -> 2618 {{ok, Answer}, _NewState} = 2619 xref_base:q(S, Query, [{verbose, false}]), 2620 unsetify(Answer). 2621 2622add_module(S, XMod, DefAt, X, LCallAt, XCallAt, XC, LC) -> 2623 Attr = {[], [], []}, 2624 Depr0 = {[], [], [], []}, 2625 DBad = [], 2626 Depr = {Depr0,DBad}, 2627 OL = [], 2628 Data = {DefAt, LCallAt, XCallAt, LC, XC, X, Attr, Depr, OL}, 2629 Unres = [], 2630 {ok, _Module, _Bad, State} = 2631 xref_base:do_add_module(S, XMod, Unres, Data), 2632 State. 2633 2634add_application(S, XApp) -> 2635 xref_base:do_add_application(S, XApp). 2636 2637add_release(S, XRel) -> 2638 xref_base:do_add_release(S, XRel). 2639 2640remove_module(S, M) -> 2641 xref_base:do_remove_module(S, M). 2642 2643info_tag(Info, Tag) -> 2644 {value, {_Tag, Value}} = lists:keysearch(Tag, 1, Info), 2645 Value. 2646 2647make_ufile(FileName) -> 2648 ok = file:write_file(FileName, term_to_binary(foo)), 2649 hide_file(FileName). 2650 2651make_udir(Dir) -> 2652 ok = file:make_dir(Dir), 2653 hide_file(Dir). 2654 2655hide_file(FileName) -> 2656 {ok, FileInfo} = file:read_file_info(FileName), 2657 NewFileInfo = FileInfo#file_info{mode = 0}, 2658 ok = file:write_file_info(FileName, NewFileInfo). 2659 2660%% Note that S has to be set up before calling this checking function. 2661check_state(S) -> 2662 Info = xref:info(S), 2663 2664 modules_mode_check(S, Info), 2665 case info(Info, mode) of 2666 modules -> 2667 ok; 2668 functions -> 2669 functions_mode_check(S, Info) 2670 end. 2671 2672%% The manual mentions some facts that should always hold. 2673%% Here they are again. 2674functions_mode_check(S, Info) -> 2675 %% F = L + X, 2676 {ok, F} = xref:q(S, "F"), 2677 {ok, F} = xref:q(S, "L + X"), 2678 2679 %% V = X + L + B + U, 2680 {ok, V} = xref:q(S, "V"), 2681 {ok, V} = xref:q(S, "X + L + B + U"), 2682 2683 %% X, L, B and U are disjoint. 2684 {ok, []} = 2685 xref:q(S, "X * L + X * B + X * U + L * B + L * U + B * U"), 2686 2687 %% V = UU + XU + LU, 2688 {ok, V} = xref:q(S, "UU + XU + LU"), 2689 2690 %% E = LC + XC 2691 {ok, E} = xref:q(S, "E"), 2692 {ok, E} = xref:q(S, "LC + XC"), 2693 2694 %% U subset of XU, 2695 {ok, []} = xref:q(S, "U - XU"), 2696 2697 %% LU = range LC 2698 {ok, []} = xref:q(S, "(LU - range LC) + (range LC - LU)"), 2699 2700 %% XU = range XC 2701 {ok, []} = xref:q(S, "(XU - range XC) + (range XC - XU)"), 2702 2703 %% LU subset F 2704 {ok, []} = xref:q(S, "LU - F"), 2705 2706 %% UU subset F 2707 {ok, []} = xref:q(S, "UU - F"), 2708 2709 %% OL subset F 2710 {ok, []} = xref:q(S, "OL - F"), 2711 2712 %% ME = (Mod) E 2713 {ok, ME} = xref:q(S, "ME"), 2714 {ok, ME} = xref:q(S, "(Mod) E"), 2715 2716 %% AE = (App) E 2717 {ok, AE} = xref:q(S, "AE"), 2718 {ok, AE} = xref:q(S, "(App) E"), 2719 2720 %% RE = (Rel) E 2721 {ok, RE} = xref:q(S, "RE"), 2722 {ok, RE} = xref:q(S, "(Rel) E"), 2723 2724 %% (Mod) V subset of M 2725 {ok, []} = xref:q(S, "(Mod) V - M"), 2726 2727 %% range UC subset of U 2728 {ok, []} = xref:q(S, "range UC - U"), 2729 2730 %% Some checks on the numbers returned by the info functions. 2731 2732 {Resolved, Unresolved} = info(Info, no_calls), 2733 AllCalls = Resolved + Unresolved, 2734 {ok, AllCalls} = xref:q(S, "# (XLin) E + # (LLin) E"), 2735 2736 {Local, Exported} = info(Info, no_functions), 2737 LX = Local+Exported, 2738 {ok, LXs} = xref:q(S, 'Extra = _:module_info/"(0|1)" + LM, 2739 # (F - Extra)'), 2740 true = LX =:= LXs, 2741 2742 {LocalCalls, ExternalCalls, UnresCalls} = 2743 info(Info, no_function_calls), 2744 LEU = LocalCalls + ExternalCalls + UnresCalls, 2745 {ok, LEU} = xref:q(S, "# LC + # XC"), 2746 2747 InterFunctionCalls = info(Info, no_inter_function_calls), 2748 {ok, InterFunctionCalls} = xref:q(S, "# EE"), 2749 2750 %% And some more checks on counters... 2751 check_count(S), 2752 2753 %% ... and more 2754 {ok, []} = xref:q(S, "LM - X - U - B"), 2755 2756 ok. 2757 2758modules_mode_check(S, Info) -> 2759 %% B subset of XU, 2760 {ok, []} = xref:q(S, "B - XU"), 2761 2762 %% M = AM + LM + UM 2763 {ok, M} = xref:q(S, "M"), 2764 {ok, M} = xref:q(S, "AM + LM + UM"), 2765 2766 %% DF is a subset of X U B, etc. 2767 {ok, []} = xref:q(S, "DF - X - B"), 2768 {ok, []} = xref:q(S, "DF_3 - DF"), 2769 {ok, []} = xref:q(S, "DF_2 - DF_3"), 2770 {ok, []} = xref:q(S, "DF_1 - DF_2"), 2771 2772 %% AM, LM and UM are disjoint. 2773 {ok, []} = xref:q(S, "AM * LM + AM * UM + LM * UM"), 2774 2775 %% (App) M subset of A 2776 {ok, []} = xref:q(S, "(App) M - A"), 2777 2778 AM = info(Info, no_analyzed_modules), 2779 {ok, AM} = xref:q(S, "# AM"), 2780 2781 A = info(Info, no_applications), 2782 {ok, A} = xref:q(S, "# A"), 2783 2784 NoR = info(Info, no_releases), 2785 {ok, NoR} = xref:q(S, "# R"), 2786 2787 ok. 2788 2789%% Checks the counters of some of the overall and modules info functions. 2790%% (Applications and releases are not checked.) 2791check_count(S) -> 2792 %%{ok, R} = xref:q(S, 'R'), 2793 %% {ok, A} = xref:q(S, 'A'), 2794 {ok, M} = xref:q(S, 'AM'), 2795 2796 {ok, _} = xref:q(S, 2797 "Extra := _:module_info/\"(0|1)\" + LM"), 2798 2799 %% info/1: 2800 {ok, NoR} = xref:q(S, '# R'), 2801 {ok, NoA} = xref:q(S, '# A'), 2802 {ok, NoM} = xref:q(S, '# AM'), 2803 {ok, NoCalls} = xref:q(S, '# (XLin) E + # (LLin) E'), 2804 {ok, NoFunCalls} = xref:q(S, '# E'), 2805 {ok, NoXCalls} = xref:q(S, '# XC'), 2806 {ok, NoLCalls} = xref:q(S, '# LC'), 2807 {ok, NoLXCalls} = xref:q(S, '# (XC * LC)'), 2808 NoAllCalls = NoXCalls + NoLCalls, 2809 {ok, NoFun} = xref:q(S, '# (F - Extra)'), 2810 {ok, NoICalls} = xref:q(S, '# EE'), 2811 2812 Info = xref:info(S), 2813 NoR = info(Info, no_releases), 2814 NoA = info(Info, no_applications), 2815 NoM = info(Info, no_analyzed_modules), 2816 {NoResolved, NoUC} = info(Info, no_calls), 2817 NoCalls = NoResolved + NoUC, 2818 {NoLocal, NoExternal, NoUnres} = info(Info, no_function_calls), 2819 NoAllCalls = NoLocal + NoExternal + NoUnres, 2820 NoAllCalls = NoFunCalls + NoLXCalls, 2821 {NoLocalFuns, NoExportedFuns} = info(Info, no_functions), 2822 NoFun = NoLocalFuns + NoExportedFuns, 2823 NoICalls = info(Info, no_inter_function_calls), 2824 2825 %% per module 2826 info_module(M, S), 2827 2828 ok. 2829 2830info_module([M | Ms], S) -> 2831 {ok, NoCalls} = per_module("T = (E | ~p : Mod), # (XLin) T + # (LLin) T", 2832 M, S), 2833 {ok, NoFunCalls} = per_module("# (E | ~p : Mod)", M, S), 2834 {ok, NoXCalls} = per_module("# (XC | ~p : Mod)", M, S), 2835 {ok, NoLCalls} = per_module("# (LC | ~p : Mod)", M, S), 2836 {ok, NoLXCalls} = per_module("# ((XC * LC) | ~p : Mod)", M, S), 2837 NoAllCalls = NoXCalls + NoLCalls, 2838 {ok, NoFun} = per_module("# (F * ~p : Mod - Extra)", M, S), 2839 {ok, NoICalls} = per_module("# (EE | ~p : Mod)", M, S), 2840 2841 [{_M,Info}] = xref:info(S, modules, M), 2842 {NoResolved, NoUC} = info(Info, no_calls), 2843 NoCalls = NoResolved + NoUC, 2844 {NoLocal, NoExternal, NoUnres} = info(Info, no_function_calls), 2845 NoAllCalls = NoLocal + NoExternal + NoUnres, 2846 NoAllCalls = NoFunCalls + NoLXCalls, 2847 {NoLocalFuns, NoExportedFuns} = info(Info, no_functions), 2848 NoFun = NoLocalFuns + NoExportedFuns, 2849 NoICalls = info(Info, no_inter_function_calls), 2850 2851 info_module(Ms, S); 2852info_module([], _S) -> 2853 ok. 2854 2855per_module(Q, M, S) -> 2856 xref:q(S, f(Q, [M])). 2857 2858info(Info, What) -> 2859 {value, {What, Value}} = lists:keysearch(What, 1, Info), 2860 Value. 2861 2862f(S, A) -> 2863 flatten(io_lib:format(S, A)). 2864 2865fatom(R) -> 2866 list_to_atom(fstring(R)). 2867 2868fstring(R) -> 2869 flatten(xref:format_error(R)). 2870 2871start(Server) -> 2872 case xref:start(Server) of 2873 {error, {already_started, _Pid}} -> 2874 xref:stop(Server), 2875 xref:start(Server); 2876 R -> R 2877 end. 2878 2879add_erts_code_path(KernelPath) -> 2880 VersionDirs = 2881 filelib:is_dir( 2882 filename:join( 2883 [code:lib_dir(), 2884 lists:flatten( 2885 ["kernel-", 2886 [X || 2887 {kernel,_,X} <- 2888 application_controller:which_applications()]])])), 2889 case VersionDirs of 2890 true -> 2891 case code:lib_dir(erts) of 2892 String when is_list(String) -> 2893 [KernelPath, fname(String,"ebin")]; 2894 _Other1 -> 2895 [KernelPath] 2896 end; 2897 false -> 2898 % Clearcase? 2899 PrelPath = filename:join([code:lib_dir(),"..","erts","preloaded"]), 2900 case filelib:is_dir(PrelPath) of 2901 true -> 2902 [KernelPath, fname(PrelPath,"ebin")]; 2903 false -> 2904 [KernelPath] 2905 end 2906 end. 2907