📄 xref_base.erl
字号:
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 2000, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id $%%-module(xref_base).-export([new/0, new/1, delete/1, add_directory/2, add_directory/3, add_module/2, add_module/3, add_application/2, add_application/3, replace_module/3, replace_module/4, replace_application/3, replace_application/4, remove_module/2, remove_application/2, remove_release/2, add_release/2, add_release/3, get_library_path/1, set_library_path/2, set_library_path/3, set_up/1, set_up/2, q/2, q/3, info/1, info/2, info/3, update/1, update/2, forget/1, forget/2, variables/1, variables/2, analyze/2, analyze/3, analysis/1, get_default/2, set_default/3, get_default/1, set_default/2]).-export([format_error/1]).%% The following functions are exported for testing purposes only:-export([do_add_module/4, do_add_application/2, do_add_release/2, do_remove_module/2]).-import(lists, [filter/2, flatten/1, foldl/3, keysearch/3, map/2, mapfoldl/3, member/2, reverse/1, sort/1, usort/1]).-import(sofs, [constant_function/2, converse/1, difference/2, domain/1, empty_set/0, family/1, family_difference/2, intersection/2, family_projection/2, family_to_relation/1, family_union/1, family_union/2, from_sets/1, from_term/1, a_function/1, image/2, family_intersection/2, inverse/1, is_empty_set/1, multiple_relative_product/2, no_elements/1, partition_family/2, projection/2, range/1, relation/1, relation_to_family/1, relative_product1/2, restriction/2, restriction/3, set/1, specification/2, substitution/2, to_external/1, union/1, union/2, union_of_family/1]).-include("xref.hrl").-define(Suffix, ".beam").%-define(debug, true).-ifdef(debug).-define(FORMAT(P, A), io:format(P, A)).-else.-define(FORMAT(P, A), ok).-endif.%%%% Exported functions%%new() -> new([]).%% -> {ok, InitialState}new(Options) -> Modes = [functions,modules,function,module], case xref_utils:options(Options, [{xref_mode,Modes}]) of {[[function]], []} -> {ok, #xref{mode = functions}}; {[[module]], []} -> {ok, #xref{mode = modules}}; {[[OM]], []} -> {ok, #xref{mode = OM}}; _ -> error({invalid_options, Options}) end.%% -> ok%% Need not be called by the server.delete(State) when State#xref.variables =:= not_set_up -> ok;delete(State) -> Fun = fun({X, _}) -> case catch digraph:info(X) of Info when is_list(Info) -> true = digraph:delete(X); _Else -> ok end end, map(Fun, dict:to_list(State#xref.variables)), ok.add_directory(State, Dir) -> add_directory(State, Dir, []). %% -> {ok, Modules, NewState} | Erroradd_directory(State, Dir, Options) -> ValOptions = option_values([builtins, recurse, verbose, warnings], State), case xref_utils:options(Options, ValOptions) of {[[OB], [OR], [OV], [OW]], []} -> catch do_add_directory(Dir, [], OB, OR, OV, OW, State); _ -> error({invalid_options, Options}) end.add_module(State, File) -> add_module(State, File, []).%% -> {ok, Module, NewState} | Erroradd_module(State, File, Options) -> ValOptions = option_values([builtins, verbose, warnings], State), case xref_utils:options(Options, ValOptions) of {[[OB], [OV], [OW]], []} -> case catch do_add_a_module(File, [], OB, OV, OW, State) of {ok, [Module], NewState} -> {ok, Module, NewState}; {ok, [], _NewState} -> error({no_debug_info, File}); Error -> Error end; _ -> error({invalid_options, Options}) end.add_application(State, AppDir) -> add_application(State, AppDir, []).%% -> {ok, AppName, NewState} | Erroradd_application(State, AppDir, Options) -> OptVals = option_values([builtins, verbose, warnings], State), ValidOptions = [{name, ["", fun check_name/1]} | OptVals], case xref_utils:options(Options, ValidOptions) of {[ApplName, [OB], [OV], [OW]], []} -> catch do_add_application(AppDir, [], ApplName, OB, OV, OW, State); _ -> error({invalid_options, Options}) end.replace_module(State, Module, File) -> replace_module(State, Module, File, []).%% -> {ok, Module, NewState} | Errorreplace_module(State, Module, File, Options) -> ValidOptions = option_values([verbose, warnings], State), case xref_utils:options(Options, ValidOptions) of {[[OV], [OW]], []} -> catch do_replace_module(Module, File, OV, OW, State); _ -> error({invalid_options, Options}) end.replace_application(State, Appl, Dir) -> replace_application(State, Appl, Dir, []).%% -> {ok, AppName, NewState} | Errorreplace_application(State, Appl, Dir, Options) -> ValidOptions = option_values([builtins, verbose, warnings], State), case xref_utils:options(Options, ValidOptions) of {[[OB], [OV], [OW]], []} -> catch do_replace_application(Appl, Dir, OB, OV, OW, State); _ -> error({invalid_options, Options}) end.%% -> {ok, NewState} | Errorremove_module(State, Mod) when is_atom(Mod) -> remove_module(State, [Mod]);remove_module(State, [Mod | Mods]) -> case catch do_remove_module(State, Mod) of {ok, _OldXMod, NewState} -> remove_module(NewState, Mods); Error -> Error end;remove_module(State, []) -> {ok, State}.%% -> {ok, NewState} | Errorremove_application(State, Appl) when is_atom(Appl) -> remove_application(State, [Appl]);remove_application(State, [Appl | Appls]) -> case catch do_remove_application(State, Appl) of {ok, _OldXApp, NewState} -> remove_application(NewState, Appls); Error -> Error end;remove_application(State, []) -> {ok, State}.%% -> {ok, NewState} | Errorremove_release(State, Rel) when is_atom(Rel) -> remove_release(State, [Rel]);remove_release(State, [Rel | Rels]) -> case catch do_remove_release(State, Rel) of {ok, _OldXRel, NewState} -> remove_release(NewState, Rels); Error -> Error end;remove_release(State, []) -> {ok, State}.add_release(State, RelDir) -> add_release(State, RelDir, []).%% -> {ok, ReleaseName, NewState} | Erroradd_release(State, RelDir, Options) -> ValidOptions0 = option_values([builtins, verbose, warnings], State), ValidOptions = [{name, ["", fun check_name/1]} | ValidOptions0], case xref_utils:options(Options, ValidOptions) of {[RelName, [OB], [OV], [OW]], []} -> catch do_add_release(RelDir, RelName, OB, OV, OW, State); _ -> error({invalid_options, Options}) end.get_library_path(State) -> {ok, State#xref.library_path}.set_library_path(State, Path) -> set_library_path(State, Path, []).%% -> {ok, NewState} | Errorset_library_path(State, code_path, _Options) -> S1 = State#xref{library_path = code_path, libraries = dict:new()}, {ok, take_down(S1)};set_library_path(State, Path, Options) -> case xref_utils:is_path(Path) of true -> ValidOptions = option_values([verbose], State), case xref_utils:options(Options, ValidOptions) of {[[OV]], []} -> do_add_libraries(Path, OV, State); _ -> error({invalid_options, Options}) end; false -> error({invalid_path, Path}) end.set_up(State) -> set_up(State, []).%% -> {ok, NewState} | Errorset_up(State, Options) -> ValidOptions = option_values([verbose], State), case xref_utils:options(Options, ValidOptions) of {[[Verbose]], []} -> do_set_up(State, Verbose); _ -> error({invalid_options, Options}) end.q(S, Q) -> q(S, Q, []).%% -> {{ok, Answer}, NewState} | {Error, NewState}q(S, Q, Options) when is_atom(Q) -> q(S, atom_to_list(Q), Options);q(S, Q, Options) -> case xref_utils:is_string(Q, 1) of true -> case set_up(S, Options) of {ok, S1} -> case xref_compiler:compile(Q, S1#xref.variables) of {NewT, Ans} -> {{ok, Ans}, S1#xref{variables = NewT}}; Error -> {Error, S1} end; Error -> {Error, S} end; false -> {error({invalid_query, Q}), S} end.%% -> InfoListinfo(State) -> D0 = sort(dict:to_list(State#xref.modules)), D = map(fun({_M, XMod}) -> XMod end, D0), NoApps = length(dict:to_list(State#xref.applications)), NoRels = length(dict:to_list(State#xref.releases)), No = no_sum(State, D), [{library_path, State#xref.library_path}, {mode, State#xref.mode}, {no_releases, NoRels}, {no_applications, NoApps}] ++ No.info(State, What) -> do_info(State, What).%% -> [{what(), InfoList}]info(State, What, Qual) -> catch do_info(State, What, Qual).update(State) -> update(State, []).%% -> {ok, NewState, Modules} | Errorupdate(State, Options) -> ValidOptions = option_values([verbose, warnings], State), case xref_utils:options(Options, ValidOptions) of {[[OV],[OW]], []} -> catch do_update(OV, OW, State); _ -> error({invalid_options, Options}) end.%% -> {ok, NewState}forget(State) -> {U, _P} = do_variables(State), {ok, foldl(fun(V, S) -> {ok, NS} = forget(S, V), NS end, State, U)}.%% -> {ok, NewState} | Errorforget(State, Variable) when State#xref.variables =:= not_set_up -> error({not_user_variable, Variable});forget(State, Variable) when is_atom(Variable) -> forget(State, [Variable]);forget(State, Variables) -> Vars = State#xref.variables, do_forget(Variables, Vars, Variables, State). variables(State) -> variables(State, [user]).%% -> {{ok, Answer}, NewState} | {Error, NewState}%% Answer = [{vartype(), [VariableName]}]variables(State, Options) -> ValidOptions = option_values([verbose], State), case xref_utils:options(Options, [user, predefined | ValidOptions]) of {[User,Predef,[OV]],[]} -> case do_set_up(State, OV) of {ok, NewState} -> {U, P} = do_variables(NewState), R1 = if User -> [{user, U}]; true -> [] end, R = if Predef -> [{predefined,P} | R1]; true -> R1 end, {{ok, R}, NewState}; Error -> {Error, State} end; _ -> {error({invalid_options, Options}), State} end.analyze(State, Analysis) -> analyze(State, Analysis, []).%% -> {{ok, Answer}, NewState} | {Error, NewState}analyze(State, Analysis, Options) -> case analysis(Analysis, State#xref.mode) of P when is_list(P) -> q(State, P, Options); error -> R = case analysis(Analysis, functions) of error -> unknown_analysis; P when is_list(P) -> unavailable_analysis end, Error = error({R, Analysis}), {Error, State} end.analysis(Analysis) -> analysis(Analysis, functions).%% -> string() | Erroranalysis(undefined_function_calls, functions) -> "(XC - UC) || (XU - X - B)";analysis(undefined_functions, modules) -> %% "XU * (L + U)" is equivalent, but the following works when L is %% not available. "XU - X - B";analysis(undefined_functions, functions) -> %% "XU * ((L + U) - range UC)" is equivalent. "XU - range UC - X - B";analysis(locals_not_used, functions) -> %% The Inter Call Graph is used to get local functions that are not %% used (indirectly) from any export: "(domain EE + range EE) * L". %% But then we only get locals that make some calls, so we add %% locals that are not used at all: "L * (UU + XU - LU)". "L * ((UU + XU - LU) + domain EE + range EE)";analysis(exports_not_used, _) -> %% Local calls are not considered here. "X * UU" would do otherwise. "X - XU";analysis({call, F}, functions) -> make_query("range (E | ~w : Fun)", [F]);analysis({use, F}, functions) -> make_query("domain (E || ~w : Fun)", [F]);analysis({module_call, M}, _) -> make_query("range (ME | ~w : Mod)", [M]);analysis({module_use, M}, _) -> make_query("domain (ME || ~w : Mod)", [M]);analysis({application_call, A}, _) -> make_query("range (AE | ~w : App)", [A]);analysis({application_use, A}, _) -> make_query("domain (AE || ~w : App)", [A]);analysis({release_call, R}, _) -> make_query("range (RE | ~w : Rel)", [R]);analysis({release_use, R}, _) -> make_query("domain (RE || ~w : Rel)", [R]);analysis(deprecated_function_calls, functions) -> "XC || DF";analysis({deprecated_function_calls,Flag}, functions) -> case deprecated_flag(Flag) of undefined -> error; I -> make_query("XC || DF_~w", [I]) end;analysis(deprecated_functions, _) -> "XU * DF";analysis({deprecated_functions,Flag}, _) -> case deprecated_flag(Flag) of undefined -> error; I -> make_query("XU * DF_~w", [I]) end;analysis(_, _) -> error.%% -> {ok, OldValue, NewState} | Errorset_default(State, Option, Value) -> case get_default(State, Option) of {ok, OldValue} -> Values = option_values([Option], State), case xref_utils:options([{Option,Value}], Values) of {_, []} -> NewState = set_def(Option, Value, State), {ok, OldValue, NewState}; {_, Unknown} -> error({invalid_options, Unknown}) end; Error -> Error end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -