⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xref_base.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 4 页
字号:
%% -> {ok, Value} | Errorget_default(State, Option) ->    case catch current_default(State, Option) of	{'EXIT', _} ->	    error({invalid_options, [Option]});	Value ->	    {ok, Value}    end.%% -> [{Option, Value}]get_default(State) ->    Fun = fun(O) -> V = current_default(State, O), {O, V} end,     map(Fun, [builtins, recurse, verbose, warnings]).%% -> {ok, NewState} -> Errorset_default(State, Options) ->    Opts = [builtins, recurse, verbose, warnings],    ValidOptions = option_values(Opts, State),    case xref_utils:options(Options, ValidOptions) of	{Values = [[_], [_], [_], [_]], []} ->	    {ok, set_defaults(Opts, Values, State)};	_ ->	    error({invalid_options, Options})    end.format_error({error, Module, Error}) ->    Module:format_error(Error);format_error({invalid_options, Options}) ->    io_lib:format("Unknown option(s) or invalid option value(s): ~p~n", 		  [Options]);format_error({invalid_filename, Term}) ->    io_lib:format("A file name (a string) was expected: ~p~n", [Term]);format_error({no_debug_info, FileName}) ->    io_lib:format("The BEAM file ~p has no debug info~n", [FileName]);format_error({invalid_path, Term}) ->    io_lib:format("A path (a list of strings) was expected: ~p~n", [Term]);format_error({invalid_query, Term}) ->    io_lib:format("A query (a string or an atom) was expected: ~p~n", [Term]);format_error({not_user_variable, Variable}) ->    io_lib:format("~p is not a user variable~n", [Variable]);format_error({unknown_analysis, Term}) ->    io_lib:format("~p is not a predefined analysis~n", [Term]);format_error({module_mismatch, Module, ReadModule}) ->    io_lib:format("Name of read module ~p does not match analyzed module ~p~n",		  [ReadModule, Module]);format_error({release_clash, {Release, Dir, OldDir}}) ->    io_lib:format("The release ~p read from ~p clashes with release "		  "already read from ~p~n", [Release, Dir, OldDir]);format_error({application_clash, {Application, Dir, OldDir}}) ->    io_lib:format("The application ~p read from ~p clashes with application "		  "already read from ~p~n", [Application, Dir, OldDir]);format_error({module_clash, {Module, Dir, OldDir}}) ->    io_lib:format("The module ~p read from ~p clashes with module "		  "already read from ~p~n", [Module, Dir, OldDir]);format_error({no_such_release, Name}) ->    io_lib:format("There is no analyzed release ~p~n", [Name]);format_error({no_such_application, Name}) ->    io_lib:format("There is no analyzed application ~p~n", [Name]);format_error({no_such_module, Name}) ->    io_lib:format("There is no analyzed module ~p~n", [Name]);format_error({no_such_info, Term}) ->    io_lib:format("~p is not one of 'modules', 'applications', "		  "'releases' and 'libraries'~n", [Term]);format_error(E) ->    io_lib:format("~p~n", [E]).%%%%  Local functions%%check_name([N]) when is_atom(N) -> true;check_name(_) -> false.do_update(OV, OW, State) ->    Changed = updated_modules(State),    Fun = fun({Mod,File}, S) ->		  {ok, _M, NS} = do_replace_module(Mod, File, OV, OW, S),		  NS	  end,    NewState = foldl(Fun, State, Changed),    {ok, NewState, to_external(domain(a_function(Changed)))}.%% -> [{Module, File}]updated_modules(State) ->    Fun = fun({M,XMod}, L) ->		  RTime = XMod#xref_mod.mtime,		  File = module_file(XMod),		  case xref_utils:file_info(File) of		      {ok, {_, file, readable, MTime}} when MTime =/= RTime ->			  [{M,File} | L];		      _Else -> 			  L		  end	  end,    foldl(Fun, [], dict:to_list(State#xref.modules)).do_forget([Variable | Variables], Vars, Vs, State) ->    case dict:find(Variable, Vars) of	{ok, #xref_var{vtype = user}} ->	    do_forget(Variables, Vars, Vs, State);	_ ->	    error({not_user_variable, Variable})    end;do_forget([], Vars, Vs, State) ->    Fun = fun(V, VT) ->		  {ok, #xref_var{value = Value}} = dict:find(V, VT),		  VT1 = xref_compiler:update_graph_counter(Value, -1, VT),		  dict:erase(V, VT1)	  end,    NewVars = foldl(Fun, Vars, Vs),    NewState = State#xref{variables = NewVars},    {ok, NewState}.%% -> {ok, Module, State} | throw(Error)do_replace_module(Module, File, OV, OW, State) ->    {ok, OldXMod, State1} = do_remove_module(State, Module),    OldApp = OldXMod#xref_mod.app_name,    OB = OldXMod#xref_mod.builtins,    case do_add_a_module(File, OldApp, OB, OV, OW, State1) of	{ok, [Module], NewState} ->	    {ok, Module, NewState};	{ok, [ReadModule], _State} ->	    throw_error({module_mismatch, Module, ReadModule});	{ok, [], _NewState} ->	    throw_error({no_debug_info, File})    end.do_replace_application(Appl, Dir, OB, OV, OW, State) ->    {ok, OldXApp, State1} = do_remove_application(State, Appl),    Rel = OldXApp#xref_app.rel_name,    N = OldXApp#xref_app.name,    %% The application name is kept; the name of Dir is not used    %% as source for a "new" application name.    do_add_application(Dir, Rel, [N], OB, OV, OW, State1).%% -> {ok, ReleaseName, NewState} | throw(Error)do_add_release(Dir, RelName, OB, OV, OW, State) ->    ok = is_filename(Dir),    case xref_utils:release_directory(Dir, true, "ebin") of	{ok, ReleaseDirName, ApplDir, Dirs} ->	    ApplDirs = xref_utils:select_last_application_version(Dirs),	    Release = case RelName of 			  [[]] -> ReleaseDirName;			  [Name] -> Name		      end,	    XRel = #xref_rel{name = Release, dir = ApplDir},	    NewState = do_add_release(State, XRel),	    add_rel_appls(ApplDirs, [Release], OB, OV, OW, NewState);	Error ->	    throw(Error)    end.do_add_release(S, XRel) ->    Release = XRel#xref_rel.name,    case dict:find(Release, S#xref.releases) of	{ok, OldXRel} ->	    Dir = XRel#xref_rel.dir,	    OldDir = OldXRel#xref_rel.dir,	    throw_error({release_clash, {Release, Dir, OldDir}});	error ->	    D1 = dict:store(Release, XRel, S#xref.releases),	    S#xref{releases = D1}    end.add_rel_appls([ApplDir | ApplDirs], Release, OB, OV, OW, State) ->    {ok, _AppName,  NewState} = 	add_appldir(ApplDir, Release, [[]], OB, OV, OW, State),    add_rel_appls(ApplDirs, Release, OB, OV, OW, NewState);add_rel_appls([], [Release], _OB, _OV, _OW, NewState) ->    {ok, Release, NewState}.do_add_application(Dir0, Release, Name, OB, OV, OW, State) ->    ok = is_filename(Dir0),    case xref_utils:select_application_directories([Dir0], "ebin") of	{ok, [ApplD]} ->	    add_appldir(ApplD, Release, Name, OB, OV, OW, State);	Error ->	    throw(Error)    end.%% -> {ok, AppName, NewState} | throw(Error)add_appldir(ApplDir, Release, Name, OB, OV, OW, OldState) ->    {AppName0, Vsn, Dir} = ApplDir,    AppName = case Name of		  [[]] -> AppName0;		  [N] -> N	      end,    AppInfo = #xref_app{name = AppName, rel_name = Release, 			vsn = Vsn, dir = Dir},    State1 = do_add_application(OldState, AppInfo),    {ok, _Modules, NewState} = 	do_add_directory(Dir, [AppName], OB, false, OV, OW, State1),    {ok, AppName, NewState}.%% -> State | throw(Error)do_add_application(S, XApp) ->    Application = XApp#xref_app.name,    case dict:find(Application, S#xref.applications) of	{ok, OldXApp} ->	    Dir = XApp#xref_app.dir,	    OldDir = OldXApp#xref_app.dir,	    throw_error({application_clash, {Application, Dir, OldDir}});	error ->	    D1 = dict:store(Application, XApp, S#xref.applications),	    S#xref{applications = D1}    end.%% -> {ok, Modules, NewState} | throw(Error)do_add_directory(Dir, AppName, Bui, Rec, Ver, War, State) ->    ok = is_filename(Dir),    {FileNames, Errors, Jams, Unreadable} =	xref_utils:scan_directory(Dir, Rec, [?Suffix], [".jam"]),    warnings(War, jam, Jams),	    warnings(War, unreadable, Unreadable),    case Errors of	[] ->	    do_add_modules(FileNames, AppName, Bui, Ver, War, State, []);	[Error | _] ->	    throw(Error)    end.do_add_modules([], _AppName, _OB, _OV, _OW, State, Modules) ->    {ok, sort(Modules), State};do_add_modules([File | Files], AppName, OB, OV, OW, State, Modules) ->    {ok, M, NewState} = do_add_module(File, AppName, OB, OV, OW, State),    do_add_modules(Files, AppName, OB, OV, OW, NewState, M ++ Modules).%% -> {ok, Module, State} | throw(Error)do_add_a_module(File, AppName, Builtins, Verbose, Warnings, State) ->    case xref_utils:split_filename(File, ?Suffix) of	false ->	    throw_error({invalid_filename, File});	Splitname ->	    do_add_module(Splitname, AppName, Builtins, Verbose, 			  Warnings, State)    end.%% -> {ok, Module, State} | throw(Error)%% Options: verbose, warnings, builtinsdo_add_module({Dir, Basename}, AppName, Builtins, Verbose, Warnings, State) ->    File = filename:join(Dir, Basename),    {ok, M, Bad, NewState} = 	do_add_module1(Dir, File, AppName, Builtins, Verbose, Warnings, State),    filter(fun({Tag,B}) -> warnings(Warnings, Tag, [[File,B]]) end, Bad),    {ok, M, NewState}.do_add_module1(Dir, File, AppName, Builtins, Verbose, Warnings, State) ->    message(Verbose, reading_beam, [File]),    Mode = State#xref.mode,    Me = self(),    Fun = fun() -> Me ! {self(), abst(File, Builtins, Mode)} end,    case xref_utils:subprocess(Fun, [link, {min_heap_size,100000}]) of	{ok, _M, no_abstract_code} when Verbose ->	    message(Verbose, skipped_beam, []),	    {ok, [], [], State};	{ok, _M, no_abstract_code} when not Verbose ->	    message(Warnings, no_debug_info, [File]),	    {ok, [], [], State};	{ok, M, Data, UnresCalls0}  ->	    %% Remove duplicates. Identical unresolved calls on the	    %% same line are counted as _one_ unresolved call.	    UnresCalls = usort(UnresCalls0),	    message(Verbose, done, []),	    NoUnresCalls = length(UnresCalls),	    case NoUnresCalls of		0 -> ok;		1 -> warnings(Warnings, unresolved_summary1, [[M]]);		N -> warnings(Warnings, unresolved_summary, [[M, N]])	    end,	    T = case xref_utils:file_info(File) of		    {ok, {_, _, _, Time}} -> Time;		    Error -> throw(Error)		end,	    XMod = #xref_mod{name = M, app_name = AppName, dir = Dir, 			     mtime = T, builtins = Builtins,			     no_unresolved = NoUnresCalls},	    do_add_module(State, XMod, UnresCalls, Data);	Error ->	    message(Verbose, error, []),	    throw(Error)    end.abst(File, Builtins, Mode) when Mode =:= functions ->    case beam_lib:chunks(File, [abstract_code, exports, attributes]) of	{ok, {M,[{abstract_code,NoA},_X,_A]}} when NoA =:= no_abstract_code ->	    {ok, M, NoA};	{ok, {M, [{abstract_code, {abstract_v1, Forms}},                   {exports,X0}, {attributes,A}]}} ->	    %% R7.	    X = xref_utils:fa_to_mfa(X0, M),            D = deprecated(A, X, M),	    xref_reader:module(M, Forms, Builtins, X, D);	{ok, {M, [{abstract_code, {abstract_v2, Forms}},                   {exports,X0}, {attributes,A}]}} ->	    %% R8-R9B.	    X = xref_utils:fa_to_mfa(X0, M),            D = deprecated(A, X, M),	    xref_reader:module(M, Forms, Builtins, X, D);	{ok, {M, [{abstract_code, {raw_abstract_v1, Code}},                  {exports,X0}, {attributes,A}]}} ->	    %% R9C-            Forms0 = epp:interpret_file_attribute(Code),	    {_,_,Forms,_} = sys_pre_expand:module(Forms0, []),	    X = mfa_exports(X0, A, M),            D = deprecated(A, X, M),	    xref_reader:module(M, Forms, Builtins, X, D);	Error when element(1, Error) =:= error ->	    Error    end;abst(File, Builtins, Mode) when Mode =:= modules ->    case beam_lib:chunks(File, [exports, imports, attributes]) of	{ok, {Mod, [{exports,X0}, {imports,I0}, {attributes,At}]}} ->	    X1 = mfa_exports(X0, At, Mod),	    X = filter(fun(MFA) -> not (predef_fun())(MFA) end, X1),            D = deprecated(At, X, Mod),	    I = case Builtins of		    true ->			I0;		    false ->			Fun = fun({M,F,A}) -> 				      not xref_utils:is_builtin(M, F, A) 			      end,			filter(Fun, I0)		end,	    {ok, Mod, {X, I, D}, []};	Error when element(1, Error) =:= error ->	    Error    end.mfa_exports(X0, Attributes, M) ->    %% Adjust arities for abstract modules.    X1 = case member({abstract, true}, Attributes) of             true ->                 [{F,adjust_arity(F,A)} || {F,A} <- X0];             false ->                 X0         end,    xref_utils:fa_to_mfa(X1, M).adjust_arity(F, A) ->    case xref_utils:is_static_function(F, A) of         true -> A;        false -> A - 1    end.deprecated(A, X, M) ->    DF = {[],[],[],[]},    case keysearch(deprecated, 1, A) of        {value, {deprecated, D0}} ->            depr(D0, M, DF, X, []);        false ->            {DF,[]}    end.depr([D | Depr], M, DF, X, Bad) ->    case depr_cat(D, M, X) of        {I,Dt} ->            NDF = setelement(I, DF, Dt ++ element(I, DF)),            depr(Depr, M, NDF, X, Bad);        undefined ->            depr(Depr, M, DF, X, [D | Bad])    end;depr([], _M, DF, _X, Bad) ->    {DF, reverse(Bad)}.depr_cat({F, A, Flg}, M, X) ->    case deprecated_flag(Flg) of        undefined -> undefined;        I -> depr_fa(F, A, X, M, I)    end;depr_cat({F, A}, M, X) ->    depr_fa(F, A, X, M, 4);depr_cat(module, M, X) ->    depr_fa('_', '_', X, M, 4);depr_cat(_D, _M, _X) ->    undefined.depr_fa('_', '_', X, _M, I) ->    {I, X};depr_fa(F, '_', X, _M, I) when is_atom(F) ->    {I, filter(fun({_,F1,_}) -> F1 =:= F end, X)};depr_fa(F, A, _X, M, I) when is_atom(F), is_integer(A), A >= 0 ->    {I, [{M,F,A}]};depr_fa(_F, _A, _X, _M, _I) ->    undefined.%% deprecated_flag(Flag) -> integer() | undefined%% Maps symbolic flags for deprecated functions to integers.%deprecated_flag(1) -> 1;%deprecated_flag(2) -> 2;%deprecated_flag(3) -> 3;deprecated_flag(next_version) -> 1;deprecated_flag(next_major_release) -> 2;deprecated_flag(eventually) -> 3;deprecated_flag(_) -> undefined.%% -> {ok, Module, Bad, State} | throw(Error)%% Assumes:%% L U X is a subset of dom DefAt%% dom CallAt = LC U XC%% Attrs is collected from the attribute 'xref' (experimental).do_add_module(S, XMod, Unres, Data) ->    M = XMod#xref_mod.name,    case dict:find(M, S#xref.modules) of	{ok, OldXMod}  ->	    BF2 = module_file(XMod),	    BF1 = module_file(OldXMod),	    throw_error({module_clash, {M, BF1, BF2}});	error ->	    do_add_module(S, M, XMod, Unres, Data)    end.%%do_add_module(S, M, _XMod, _Unres, Data)->%%    {ok, M, [], S};do_add_module(S, M, XMod, Unres0, Data) when S#xref.mode =:= functions ->    {DefAt0, LPreCAt0, XPreCAt0, LC0, XC0, X0, Attrs, Depr} = Data,    %% Bad is a list of bad values of 'xref' attributes.    {ALC0,AXC0,Bad0} = Attrs,    FT = [tspec(func)],    FET = [tspec(fun_edge)],    PCA = [tspec(pre_call_at)],    XPreCAt1 = xref_utils:xset(XPreCAt0, PCA),    LPreCAt1 = xref_utils:xset(LPreCAt0, PCA),    DefAt = xref_utils:xset(DefAt0, [tspec(def_at)]),    X1 = xref_utils:xset(X0, FT),    XC1 = xref_utils:xset(XC0, FET),    LC1 = xref_utils:xset(LC0, FET),    AXC1 = xref_utils:xset(AXC0, PCA),    ALC1 = xref_utils:xset(ALC0, PCA),    UnresCalls = xref_utils:xset(Unres0, PCA),    Unres = domain(UnresCalls),    DefinedFuns = domain(DefAt),    {AXC, ALC, Bad1, LPreCAt2, XPreCAt2} = 	extra_edges(AXC1, ALC1, Bad0, DefinedFuns),    Bad = map(fun(B) -> {xref_attr, B} end, Bad1),    LPreCAt = union(LPreCAt1, LPreCAt2),    XPreCAt = union(XPreCAt1, XPreCAt2),    NoCalls = no_elements(LPreCAt) + no_elements(XPreCAt),    LCallAt = relation_to_family(LPreCAt),    XCallAt = relation_to_family(XPreCAt),    CallAt = family_union(LCallAt, XCallAt),    %% Local and exported functions with no definitions are removed.    L = difference(DefinedFuns, X1),    X = difference(DefinedFuns, L),    XC = union(XC1, AXC),    LC = union(LC1, ALC),    {DF1,DF_11,DF_21,DF_31,DBad} = depr_mod(Depr, X),

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -