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

📄 cover.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 4 页
字号:
%% ``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 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-module(cover).%%%% This module implements the Erlang coverage tool. The module named%% cover_web implements a user interface for the coverage tool to run%% under webtool.%% %% ARCHITECTURE%% The coverage tool consists of one process on each node involved in%% coverage analysis. The process is registered as 'cover_server'%% (?SERVER).  All cover_servers in the distributed system are linked%% together.  The cover_server on the 'main' node is in charge, and it%% traps exits so it can detect nodedown or process crashes on the%% remote nodes. This process is implemented by the functions%% init_main/1 and main_process_loop/1. The cover_server on the remote%% nodes are implemented by the functions init_remote/2 and%% remote_process_loop/1.%%%% TABLES%% Each nodes has an ets table named 'cover_internal_data_table'%% (?COVER_TABLE).  This table contains the coverage data and is%% continously updated when cover compiled code is executed.%% %% The main node owns a table named%% 'cover_collected_remote_data_table' (?COLLECTION_TABLE). This table%% contains data which is collected from remote nodes (either when a%% remote node is stopped with cover:stop/1 or when analysing. When%% analysing, data is even moved from the ?COVER_TABLE on the main%% node to the ?COLLECTION_TABLE.%%%% The main node also has a table named 'cover_binary_code_table'%% (?BINARY_TABLE). This table contains the binary code for each cover%% compiled module. This is necessary so that the code can be loaded%% on remote nodes that are started after the compilation.%%%% External exports-export([start/0, start/1,	 compile/1, compile/2, compile_module/1, compile_module/2,	 compile_directory/0, compile_directory/1, compile_directory/2,	 compile_beam/1, compile_beam_directory/0, compile_beam_directory/1,	 analyse/1, analyse/2, analyse/3, analyze/1, analyze/2, analyze/3,	 analyse_to_file/1, analyse_to_file/2, analyse_to_file/3,	 analyze_to_file/1, analyze_to_file/2, analyze_to_file/3,	 export/1, export/2, import/1,	 modules/0, imported/0, imported_modules/0, which_nodes/0, is_compiled/1,	 reset/1, reset/0,	 stop/0, stop/1]).-export([remote_start/1]).%-export([bump/5]).-export([transform/4]). % for test purposes-record(main_state, {compiled=[],           % [{Module,File}]		     imported=[],           % [{Module,File,ImportFile}]		     stopper,               % undefined | pid()		     nodes=[]}).            % [Node]-record(remote_state, {compiled=[],         % [{Module,File}]		       main_node}).         % atom()-record(bump, {module   = '_',              % atom()	       function = '_',              % atom()	       arity    = '_',              % integer()	       clause   = '_',              % integer()	       line     = '_'               % integer()	      }).-define(BUMP_REC_NAME,bump).-record(vars, {module,                      % atom() Module name	       vsn,                         % atom()	       	       init_info=[],                % [{M,F,A,C,L}]	       function,                    % atom()	       arity,                       % int()	       clause,                      % int()	       lines,                       % [int()]	       depth,                       % int()	       is_guard=false               % boolean	      }).-define(COVER_TABLE, 'cover_internal_data_table').-define(BINARY_TABLE, 'cover_binary_code_table').-define(COLLECTION_TABLE, 'cover_collected_remote_data_table').-define(TAG, cover_compiled).-define(SERVER, cover_server).-include_lib("stdlib/include/ms_transform.hrl").%%%----------------------------------------------------------------------%%% External exports%%%----------------------------------------------------------------------%% start() -> {ok,Pid} | {error,Reason}%%   Pid = pid()%%   Reason = {already_started,Pid} | term()start() ->    case whereis(?SERVER) of	undefined ->	    Starter = self(),	    Pid = spawn(fun() -> init_main(Starter) end),	    Ref = erlang:monitor(process,Pid),	    Return = 		receive 		    {?SERVER,started} -> 			{ok,Pid};		    {'DOWN', Ref, _Type, _Object, Info} -> 			{error,Info}		end,	    erlang:demonitor(Ref),	    Return;	Pid ->	    {error,{already_started,Pid}}    end.%% start(Nodes) -> {ok,StartedNodes}%%   Nodes = Node | [Node,...]%%   Node = atom()start(Node) when is_atom(Node) ->    start([Node]);start(Nodes) ->    call({start_nodes,remove_myself(Nodes,[])}).%% compile(ModFile) ->%% compile(ModFile, Options) ->%% compile_module(ModFile) -> Result%% compile_module(ModFile, Options) -> Result%%   ModFile = Module | File%%     Module = atom()%%     File = string()%%   Options = [Option]%%     Option = {i,Dir} | {d,Macro} | {d,Macro,Value}%%   Result = {ok,Module} | {error,File}compile(ModFile) ->    compile_module(ModFile, []).compile(ModFile, Options) ->    compile_module(ModFile, Options).compile_module(ModFile) when is_atom(ModFile);			     is_list(ModFile) ->    compile_module(ModFile, []).compile_module(Module, Options) when is_atom(Module), is_list(Options) ->    compile_module(atom_to_list(Module), Options);compile_module(File, Options) when is_list(File), is_list(Options) ->    WithExt = case filename:extension(File) of		  ".erl" ->		      File;		  _ ->		      File++".erl"	      end,    AbsFile = filename:absname(WithExt),    [R] = compile_modules([AbsFile], Options),    R.%% compile_directory() ->%% compile_directory(Dir) ->%% compile_directory(Dir, Options) -> [Result] | {error,Reason}%%   Dir = string()%%   Options - see compile/1%%   Result - see compile/1%%   Reason = eacces | enoentcompile_directory() ->    case file:get_cwd() of	{ok, Dir} ->	    compile_directory(Dir, []);	Error ->	    Error    end.compile_directory(Dir) when is_list(Dir) ->    compile_directory(Dir, []).compile_directory(Dir, Options) when is_list(Dir), is_list(Options) ->    case file:list_dir(Dir) of	{ok, Files} ->	    	    %% Filter out all erl files (except cover.erl)	    ErlFileNames =		lists:filter(fun("cover.erl") ->				     false;				(File) ->				     case filename:extension(File) of					 ".erl" -> true;					 _ -> false				     end			     end,			     Files),	    %% Create a list of .erl file names (incl path) and call	    %% compile_modules/2 with the list of file names.	    ErlFiles = lists:map(fun(ErlFileName) ->					 filename:join(Dir, ErlFileName)				 end,				 ErlFileNames),	    compile_modules(ErlFiles, Options);	Error ->	    Error    end.compile_modules(Files,Options) ->    Options2 = lists:filter(fun(Option) ->				    case Option of					{i, Dir} when is_list(Dir) -> true;					{d, _Macro} -> true;					{d, _Macro, _Value} -> true;					_ -> false				    end			    end,			    Options),    compile_modules(Files,Options2,[]).compile_modules([File|Files], Options, Result) ->    R = call({compile, File, Options}),    compile_modules(Files,Options,[R|Result]);compile_modules([],_Opts,Result) ->    reverse(Result).%% compile_beam(ModFile) -> Result | {error,Reason}%%   ModFile - see compile/1%%   Result - see compile/1%%   Reason = non_existing | already_cover_compiledcompile_beam(Module) when is_atom(Module) ->    case code:which(Module) of	non_existing -> 	    {error,non_existing};	?TAG ->	    compile_beam(Module,?TAG);	File ->	    compile_beam(Module,File)    end;compile_beam(File) when is_list(File) ->    {WithExt,WithoutExt}	= case filename:rootname(File,".beam") of	      File ->		  {File++".beam",File};	      Rootname ->		  {File,Rootname}	      end,    AbsFile = filename:absname(WithExt),    Module = list_to_atom(filename:basename(WithoutExt)),    compile_beam(Module,AbsFile).compile_beam(Module,File) ->    call({compile_beam,Module,File}).    %% compile_beam_directory(Dir) -> [Result] | {error,Reason}%%   Dir - see compile_directory/1%%   Result - see compile/1%%   Reason = eacces | enoentcompile_beam_directory() ->    case file:get_cwd() of	{ok, Dir} ->	    compile_beam_directory(Dir);	Error ->	    Error    end.compile_beam_directory(Dir) when is_list(Dir) ->    case file:list_dir(Dir) of	{ok, Files} ->	    	    %% Filter out all beam files (except cover.beam)	    BeamFileNames =		lists:filter(fun("cover.beam") ->				     false;				(File) ->				     case filename:extension(File) of					 ".beam" -> true;					 _ -> false				     end			     end,			     Files),	    %% Create a list of .beam file names (incl path) and call	    %% compile_beam/1 for each such file name	    BeamFiles = lists:map(fun(BeamFileName) ->					  filename:join(Dir, BeamFileName)				  end,				  BeamFileNames),	    compile_beams(BeamFiles);	Error ->	    Error    end.compile_beams(Files) ->    compile_beams(Files,[]).compile_beams([File|Files],Result) ->    R = compile_beam(File),    compile_beams(Files,[R|Result]);compile_beams([],Result) ->    reverse(Result).%% analyse(Module) ->%% analyse(Module, Analysis) ->%% analyse(Module, Level) ->%% analyse(Module, Analysis, Level) -> {ok,Answer} | {error,Error}%%   Module = atom()%%   Analysis = coverage | calls%%   Level = line | clause | function | module%%   Answer = {Module,Value} | [{Item,Value}]%%     Item = Line | Clause | Function%%      Line = {M,N}%%      Clause = {M,F,A,C}%%      Function = {M,F,A}%%        M = F = atom()%%        N = A = C = integer()%%     Value = {Cov,NotCov} | Calls%%       Cov = NotCov = Calls = integer()%%   Error = {not_cover_compiled,Module}analyse(Module) ->    analyse(Module, coverage).analyse(Module, Analysis) when Analysis=:=coverage; Analysis=:=calls ->    analyse(Module, Analysis, function);analyse(Module, Level) when Level=:=line; Level=:=clause; Level=:=function;			    Level=:=module ->    analyse(Module, coverage, Level).analyse(Module, Analysis, Level) when is_atom(Module),				      Analysis=:=coverage; Analysis=:=calls,				      Level=:=line; Level=:=clause;				      Level=:=function; Level=:=module ->    call({{analyse, Analysis, Level}, Module}).analyze(Module) -> analyse(Module).analyze(Module, Analysis) -> analyse(Module, Analysis).analyze(Module, Analysis, Level) -> analyse(Module, Analysis, Level).%% analyse_to_file(Module) ->%% analyse_to_file(Module, Options) ->%% analyse_to_file(Module, OutFile) ->%% analyse_to_file(Module, OutFile, Options) -> {ok,OutFile} | {error,Error}%%   Module = atom()%%   OutFile = string()%%   Options = [Option]%%     Option = html%%   Error = {not_cover_compiled,Module} | no_source_code_found |%%           {file,File,Reason}%%     File = string()%%     Reason = term()analyse_to_file(Module) when is_atom(Module) ->    analyse_to_file(Module, outfilename(Module,[]), []).analyse_to_file(Module, []) when is_atom(Module) ->    analyse_to_file(Module, outfilename(Module,[]), []);analyse_to_file(Module, Options) when is_atom(Module),				      is_list(Options), is_atom(hd(Options)) ->    analyse_to_file(Module, outfilename(Module,Options), Options);analyse_to_file(Module, OutFile) when is_atom(Module), is_list(OutFile) ->    analyse_to_file(Module, OutFile, []).analyse_to_file(Module, OutFile, Options) when is_atom(Module), is_list(OutFile) ->    call({{analyse_to_file, OutFile, Options}, Module}).analyze_to_file(Module) -> analyse_to_file(Module).analyze_to_file(Module, OptOrOut) -> analyse_to_file(Module, OptOrOut).analyze_to_file(Module, OutFile, Options) ->     analyse_to_file(Module, OutFile, Options).outfilename(Module,Opts) ->    case lists:member(html,Opts) of	true ->	    atom_to_list(Module)++".COVER.html";	false ->	    atom_to_list(Module)++".COVER.out"    end.%% export(File)%% export(File,Module) -> ok | {error,Reason}%%   File = string(); file to write the exported data to%%   Module = atom()export(File) ->    export(File, '_').export(File, Module) ->    call({export,File,Module}).%% import(File) -> ok | {error, Reason}%%   File = string(); file created with cover:export/1,2import(File) ->    call({import,File}).%% modules() -> [Module]%%   Module = atom()modules() ->   call(modules).%% imported_modules() -> [Module]%%   Module = atom()imported_modules() ->   call(imported_modules).%% imported() -> [ImportFile]%%   ImportFile = string()imported() ->   call(imported).%% which_nodes() -> [Node]%%   Node = atom()which_nodes() ->   call(which_nodes).%% is_compiled(Module) -> {file,File} | false%%   Module = atom()%%   File = string()is_compiled(Module) when is_atom(Module) ->    call({is_compiled, Module}).%% reset(Module) -> ok | {error,Error}%% reset() -> ok%%   Module = atom()%%   Error = {not_cover_compiled,Module}reset(Module) when is_atom(Module) ->    call({reset, Module}).reset() ->    call(reset).%% stop() -> okstop() ->    call(stop).stop(Node) when is_atom(Node) ->    stop([Node]);stop(Nodes) ->    call({stop,remove_myself(Nodes,[])}).%% bump(Module, Function, Arity, Clause, Line)%%   Module = Function = atom()%%   Arity = Clause = Line = integer()%% This function is inserted into Cover compiled modules, once for each%% executable line.%bump(Module, Function, Arity, Clause, Line) ->%    Key = #bump{module=Module, function=Function, arity=Arity, clause=Clause,%		line=Line},%    ets:update_counter(?COVER_TABLE, Key, 1).call(Request) ->    Ref = erlang:monitor(process,?SERVER),    receive {'DOWN', Ref, _Type, _Object, noproc} -> 	    erlang:demonitor(Ref),	    start(),	    call(Request)    after 0 ->	    ?SERVER ! {self(),Request},	    Return = 		receive 		    {'DOWN', Ref, _Type, _Object, Info} -> 			exit(Info);		    {?SERVER,Reply} -> 			Reply		end,	    erlang:demonitor(Ref),	    Return    end.reply(From, Reply) ->    From ! {?SERVER,Reply}.is_from(From) ->    is_pid(From).remote_call(Node,Request) ->    Ref = erlang:monitor(process,{?SERVER,Node}),    receive {'DOWN', Ref, _Type, _Object, noproc} -> 	    erlang:demonitor(Ref),	    {error,node_dead}

⌨️ 快捷键说明

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