1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2001-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(cover).
21
22%%
23%% This module implements the Erlang coverage tool.
24%%
25%% ARCHITECTURE
26%% The coverage tool consists of one process on each node involved in
27%% coverage analysis. The process is registered as 'cover_server'
28%% (?SERVER).  The cover_server on the 'main' node is in charge, and
29%% it monitors the cover_servers on all remote nodes. When it gets a
30%% 'DOWN' message for another cover_server, it marks the node as
31%% 'lost'. If a nodeup is received for a lost node the main node
32%% ensures that the cover compiled modules are loaded again. If the
33%% remote node was alive during the disconnected periode, cover data
34%% for this periode will also be included in the analysis.
35%%
36%% The cover_server process on the main node is implemented by the
37%% functions init_main/1 and main_process_loop/1. The cover_server on
38%% the remote nodes are implemented by the functions init_remote/2 and
39%% remote_process_loop/1.
40%%
41%% TABLES
42%% Each nodes has two tables: cover_internal_data_table (?COVER_TABLE) and.
43%% cover_internal_clause_table (?COVER_CLAUSE_TABLE).
44%% ?COVER_TABLE contains the bump data i.e. the data about which lines
45%% have been executed how many times.
46%% ?COVER_CLAUSE_TABLE contains information about which clauses in which modules
47%% cover is currently collecting statistics.
48%%
49%% The main node owns tables named
50%% 'cover_collected_remote_data_table' (?COLLECTION_TABLE) and
51%% 'cover_collected_remote_clause_table' (?COLLECTION_CLAUSE_TABLE).
52%% These tables contain data which is collected from remote nodes (either when a
53%% remote node is stopped with cover:stop/1 or when analysing). When
54%% analysing, data is even moved from the COVER tables on the main
55%% node to the COLLECTION tables.
56%%
57%% The main node also has a table named 'cover_binary_code_table'
58%% (?BINARY_TABLE). This table contains the binary code for each cover
59%% compiled module. This is necessary so that the code can be loaded
60%% on remote nodes that are started after the compilation.
61%%
62%% PARALLELISM
63%% To take advantage of SMP when doing the cover analysis both the data
64%% collection and analysis has been parallelized. One process is spawned for
65%% each node when collecting data, and on the remote node when collecting data
66%% one process is spawned per module.
67%%
68%% When analyzing data it is possible to issue multiple analyse(_to_file)/X
69%% calls at once. They are however all calls (for backwards compatibility
70%% reasons) so the user of cover will have to spawn several processes to to the
71%% calls ( or use async_analyse_to_file ).
72%%
73
74%% External exports
75-export([start/0, start/1,
76	 compile/1, compile/2, compile_module/1, compile_module/2,
77	 compile_directory/0, compile_directory/1, compile_directory/2,
78	 compile_beam/1, compile_beam_directory/0, compile_beam_directory/1,
79	 analyse/0, analyse/1, analyse/2, analyse/3,
80	 analyze/0, analyze/1, analyze/2, analyze/3,
81	 analyse_to_file/0,
82	 analyse_to_file/1, analyse_to_file/2, analyse_to_file/3,
83	 analyze_to_file/0,
84	 analyze_to_file/1, analyze_to_file/2, analyze_to_file/3,
85	 async_analyse_to_file/1,async_analyse_to_file/2,
86	 async_analyse_to_file/3, async_analyze_to_file/1,
87	 async_analyze_to_file/2, async_analyze_to_file/3,
88	 export/1, export/2, import/1,
89	 modules/0, imported/0, imported_modules/0, which_nodes/0, is_compiled/1,
90	 reset/1, reset/0,
91	 flush/1,
92	 stop/0, stop/1]).
93-export([remote_start/1,get_main_node/0]).
94
95%% Used internally to ensure we upgrade the code to the latest version.
96-export([main_process_loop/1,remote_process_loop/1]).
97
98-record(main_state, {compiled=[],           % [{Module,File}]
99		     imported=[],           % [{Module,File,ImportFile}]
100		     stopper,               % undefined | pid()
101		     nodes=[],              % [Node]
102		     lost_nodes=[]}).       % [Node]
103
104-record(remote_state, {compiled=[],         % [{Module,File}]
105		       main_node}).         % atom()
106
107-record(bump, {module   = '_',              % atom()
108	       function = '_',              % atom()
109	       arity    = '_',              % integer()
110	       clause   = '_',              % integer()
111	       line     = '_'               % integer()
112	      }).
113-define(BUMP_REC_NAME,bump).
114-define(CHUNK_SIZE, 20000).
115
116-record(vars, {module,                      % atom() Module name
117
118	       init_info=[],                % [{M,F,A,C,L}]
119
120	       function,                    % atom()
121	       arity,                       % int()
122	       clause,                      % int()
123	       lines,                       % [int()]
124               no_bump_lines,               % [int()]
125	       depth,                       % int()
126	       is_guard=false               % boolean
127	      }).
128
129-define(COVER_TABLE, 'cover_internal_data_table').
130-define(COVER_CLAUSE_TABLE, 'cover_internal_clause_table').
131-define(BINARY_TABLE, 'cover_binary_code_table').
132-define(COLLECTION_TABLE, 'cover_collected_remote_data_table').
133-define(COLLECTION_CLAUSE_TABLE, 'cover_collected_remote_clause_table').
134-define(TAG, cover_compiled).
135-define(SERVER, cover_server).
136
137%% Line doesn't matter.
138-define(BLOCK(Expr), {block,erl_anno:new(0),[Expr]}).
139-define(BLOCK1(Expr),
140        if
141            element(1, Expr) =:= block ->
142                Expr;
143            true -> ?BLOCK(Expr)
144        end).
145
146-define(SPAWN_DBG(Tag,Value),put(Tag,Value)).
147-define(STYLESHEET, "styles.css").
148-define(TOOLS_APP, tools).
149
150-include_lib("stdlib/include/ms_transform.hrl").
151
152%%%----------------------------------------------------------------------
153%%% External exports
154%%%----------------------------------------------------------------------
155
156%% start() -> {ok,Pid} | {error,Reason}
157%%   Pid = pid()
158%%   Reason = {already_started,Pid} | term()
159start() ->
160    case whereis(?SERVER) of
161	undefined ->
162	    Starter = self(),
163	    Pid = spawn(fun() ->
164				?SPAWN_DBG(start,[]),
165				init_main(Starter)
166			end),
167	    Ref = erlang:monitor(process,Pid),
168	    Return =
169		receive
170		    {?SERVER,started} ->
171			{ok,Pid};
172		    {?SERVER,{error,Error}} ->
173			{error,Error};
174		    {'DOWN', Ref, _Type, _Object, Info} ->
175			{error,Info}
176		end,
177	    erlang:demonitor(Ref),
178	    Return;
179	Pid ->
180	    {error,{already_started,Pid}}
181    end.
182
183%% start(Nodes) -> {ok,StartedNodes}
184%%   Nodes = Node | [Node,...]
185%%   Node = atom()
186start(Node) when is_atom(Node) ->
187    start([Node]);
188start(Nodes) ->
189    call({start_nodes,remove_myself(Nodes,[])}).
190
191%% compile(ModFiles) ->
192%% compile(ModFiles, Options) ->
193%% compile_module(ModFiles) -> Result
194%% compile_module(ModFiles, Options) -> Result
195%%   ModFiles = ModFile | [ModFile]
196%%   ModFile = Module | File
197%%     Module = atom()
198%%     File = string()
199%%   Options = [Option]
200%%     Option = {i,Dir} | {d,Macro} | {d,Macro,Value}
201%%   Result = {ok,Module} | {error,File}
202compile(ModFile) ->
203    compile_module(ModFile, []).
204compile(ModFile, Options) ->
205    compile_module(ModFile, Options).
206compile_module(ModFile) when is_atom(ModFile);
207			     is_list(ModFile) ->
208    compile_module(ModFile, []).
209compile_module(ModFile, Options) when is_atom(ModFile);
210				      is_list(ModFile), is_integer(hd(ModFile)) ->
211    [R] = compile_module([ModFile], Options),
212    R;
213compile_module(ModFiles, Options) when is_list(Options) ->
214    AbsFiles =
215	[begin
216	     File =
217		 case ModFile of
218		     _ when is_atom(ModFile) -> atom_to_list(ModFile);
219		     _ when is_list(ModFile) -> ModFile
220		 end,
221	     WithExt = case filename:extension(File) of
222			   ".erl" ->
223			       File;
224			   _ ->
225			       File++".erl"
226		       end,
227	     filename:absname(WithExt)
228	 end || ModFile <- ModFiles],
229    compile_modules(AbsFiles, Options).
230
231%% compile_directory() ->
232%% compile_directory(Dir) ->
233%% compile_directory(Dir, Options) -> [Result] | {error,Reason}
234%%   Dir = string()
235%%   Options - see compile/1
236%%   Result - see compile/1
237%%   Reason = eacces | enoent
238compile_directory() ->
239    case file:get_cwd() of
240	{ok, Dir} ->
241	    compile_directory(Dir, []);
242	Error ->
243	    Error
244    end.
245compile_directory(Dir) when is_list(Dir) ->
246    compile_directory(Dir, []).
247compile_directory(Dir, Options) when is_list(Dir), is_list(Options) ->
248    case file:list_dir(Dir) of
249	{ok, Files} ->
250	    ErlFiles = [filename:join(Dir, File) ||
251			   File <- Files,
252			   filename:extension(File) =:= ".erl"],
253	    compile_modules(ErlFiles, Options);
254	Error ->
255	    Error
256    end.
257
258compile_modules(Files,Options) ->
259    Options2 = filter_options(Options),
260    %% compile_modules(Files,Options2,[]).
261    call({compile, Files, Options2}).
262
263%% compile_modules([File|Files], Options, Result) ->
264%%     R = call({compile, File, Options}),
265%%     compile_modules(Files,Options,[R|Result]);
266%% compile_modules([],_Opts,Result) ->
267%%     lists:reverse(Result).
268
269filter_options(Options) ->
270    lists:filter(fun(Option) ->
271                         case Option of
272                             {i, Dir} when is_list(Dir) -> true;
273                             {d, _Macro} -> true;
274                             {d, _Macro, _Value} -> true;
275                             export_all -> true;
276                             _ -> false
277                         end
278                 end,
279                 Options).
280
281%% compile_beam(ModFile) -> Result | {error,Reason}
282%%   ModFile - see compile/1
283%%   Result - see compile/1
284%%   Reason = non_existing | already_cover_compiled
285compile_beam(ModFile0) when is_atom(ModFile0);
286			    is_list(ModFile0), is_integer(hd(ModFile0)) ->
287    case compile_beams([ModFile0]) of
288	[{error,{non_existing,_}}] ->
289	    %% Backwards compatibility
290	    {error,non_existing};
291	[Result] ->
292	    Result
293    end;
294compile_beam(ModFiles) when is_list(ModFiles) ->
295    compile_beams(ModFiles).
296
297
298%% compile_beam_directory(Dir) -> [Result] | {error,Reason}
299%%   Dir - see compile_directory/1
300%%   Result - see compile/1
301%%   Reason = eacces | enoent
302compile_beam_directory() ->
303    case file:get_cwd() of
304	{ok, Dir} ->
305	    compile_beam_directory(Dir);
306	Error ->
307	    Error
308    end.
309compile_beam_directory(Dir) when is_list(Dir) ->
310    case file:list_dir(Dir) of
311	{ok, Files} ->
312	    BeamFiles =  [filename:join(Dir, File) ||
313			     File <- Files,
314			     filename:extension(File) =:= ".beam"],
315	    compile_beams(BeamFiles);
316	Error ->
317	    Error
318    end.
319
320compile_beams(ModFiles0) ->
321    ModFiles = get_mods_and_beams(ModFiles0,[]),
322    call({compile_beams,ModFiles}).
323
324get_mods_and_beams([Module|ModFiles],Acc) when is_atom(Module) ->
325    case code:which(Module) of
326	non_existing ->
327	    get_mods_and_beams(ModFiles,[{error,{non_existing,Module}}|Acc]);
328	File ->
329	    get_mods_and_beams([{Module,File}|ModFiles],Acc)
330    end;
331get_mods_and_beams([File|ModFiles],Acc) when is_list(File) ->
332    {WithExt,WithoutExt}
333	= case filename:rootname(File,".beam") of
334	      File ->
335		  {File++".beam",File};
336	      Rootname ->
337		  {File,Rootname}
338	      end,
339    AbsFile = filename:absname(WithExt),
340    Module = list_to_atom(filename:basename(WithoutExt)),
341    get_mods_and_beams([{Module,AbsFile}|ModFiles],Acc);
342get_mods_and_beams([{Module,File}|ModFiles],Acc) ->
343    %% Check for duplicates
344    case lists:keyfind(Module,2,Acc) of
345	{ok,Module,File} ->
346	    %% Duplicate, but same file so ignore
347	    get_mods_and_beams(ModFiles,Acc);
348	{ok,Module,_OtherFile} ->
349	    %% Duplicate and differnet file - error
350	    get_mods_and_beams(ModFiles,[{error,{duplicate,Module}}|Acc]);
351	_ ->
352	    get_mods_and_beams(ModFiles,[{ok,Module,File}|Acc])
353    end;
354get_mods_and_beams([],Acc) ->
355    lists:reverse(Acc).
356
357
358%% analyse(Modules) ->
359%% analyse(Analysis) ->
360%% analyse(Level) ->
361%% analyse(Modules, Analysis) ->
362%% analyse(Modules, Level) ->
363%% analyse(Analysis, Level)
364%% analyse(Modules, Analysis, Level) -> {ok,Answer} | {error,Error}
365%%   Modules = Module | [Module]
366%%   Module = atom()
367%%   Analysis = coverage | calls
368%%   Level = line | clause | function | module
369%%   Answer = {Module,Value} | [{Item,Value}]
370%%     Item = Line | Clause | Function
371%%      Line = {M,N}
372%%      Clause = {M,F,A,C}
373%%      Function = {M,F,A}
374%%        M = F = atom()
375%%        N = A = C = integer()
376%%     Value = {Cov,NotCov} | Calls
377%%       Cov = NotCov = Calls = integer()
378%%   Error = {not_cover_compiled,Module} | not_main_node
379-define(is_analysis(__A__),
380	(__A__=:=coverage orelse __A__=:=calls)).
381-define(is_level(__L__),
382	(__L__=:=line orelse __L__=:=clause orelse
383	 __L__=:=function orelse __L__=:=module)).
384analyse() ->
385    analyse('_').
386
387analyse(Analysis) when ?is_analysis(Analysis) ->
388    analyse('_', Analysis);
389analyse(Level) when ?is_level(Level) ->
390    analyse('_', Level);
391analyse(Module) ->
392    analyse(Module, coverage).
393
394analyse(Analysis, Level) when ?is_analysis(Analysis) andalso
395			      ?is_level(Level) ->
396    analyse('_', Analysis, Level);
397analyse(Module, Analysis) when ?is_analysis(Analysis) ->
398    analyse(Module, Analysis, function);
399analyse(Module, Level) when ?is_level(Level) ->
400    analyse(Module, coverage, Level).
401
402analyse(Module, Analysis, Level) when ?is_analysis(Analysis),
403				      ?is_level(Level) ->
404    call({{analyse, Analysis, Level}, Module}).
405
406analyze() -> analyse( ).
407analyze(Module) -> analyse(Module).
408analyze(Module, Analysis) -> analyse(Module, Analysis).
409analyze(Module, Analysis, Level) -> analyse(Module, Analysis, Level).
410
411%% analyse_to_file() ->
412%% analyse_to_file(Modules) ->
413%% analyse_to_file(Modules, Options) ->
414%%   Modules = Module | [Module]
415%%   Module = atom()
416%%   OutFile = string()
417%%   Options = [Option]
418%%     Option = html | {outfile,filename()} | {outdir,dirname()}
419%%   Error = {not_cover_compiled,Module} | no_source_code_found |
420%%           {file,File,Reason}
421%%     File = string()
422%%     Reason = term()
423%%
424%% Kept for backwards compatibility:
425%% analyse_to_file(Modules, OutFile) ->
426%% analyse_to_file(Modules, OutFile, Options) -> {ok,OutFile} | {error,Error}
427analyse_to_file() ->
428    analyse_to_file('_').
429analyse_to_file(Arg) ->
430    case is_options(Arg) of
431	true ->
432	    analyse_to_file('_',Arg);
433	false ->
434	    analyse_to_file(Arg,[])
435    end.
436analyse_to_file(Module, OutFile) when is_list(OutFile), is_integer(hd(OutFile)) ->
437    %% Kept for backwards compatibility
438    analyse_to_file(Module, [{outfile,OutFile}]);
439analyse_to_file(Module, Options) when is_list(Options) ->
440    call({{analyse_to_file, Options}, Module}).
441analyse_to_file(Module, OutFile, Options) when is_list(OutFile) ->
442    %% Kept for backwards compatibility
443    analyse_to_file(Module,[{outfile,OutFile}|Options]).
444
445analyze_to_file() -> analyse_to_file().
446analyze_to_file(Module) -> analyse_to_file(Module).
447analyze_to_file(Module, OptOrOut) -> analyse_to_file(Module, OptOrOut).
448analyze_to_file(Module, OutFile, Options) ->
449    analyse_to_file(Module, OutFile, Options).
450
451async_analyse_to_file(Module) ->
452    do_spawn(?MODULE, analyse_to_file, [Module]).
453async_analyse_to_file(Module, OutFileOrOpts) ->
454    do_spawn(?MODULE, analyse_to_file, [Module, OutFileOrOpts]).
455async_analyse_to_file(Module, OutFile, Options) ->
456    do_spawn(?MODULE, analyse_to_file, [Module, OutFile, Options]).
457
458is_options([html]) ->
459    true; % this is not 100% safe - could be a module named html...
460is_options([html|Opts]) ->
461    is_options(Opts);
462is_options([{Opt,_}|_]) when Opt==outfile; Opt==outdir ->
463    true;
464is_options(_) ->
465    false.
466
467do_spawn(M,F,A) ->
468    spawn_link(fun() ->
469		  case apply(M,F,A) of
470		      {ok, _} ->
471			  ok;
472		      {error, Reason} ->
473			  exit(Reason)
474		  end
475	  end).
476
477async_analyze_to_file(Module) ->
478    async_analyse_to_file(Module).
479async_analyze_to_file(Module, OutFileOrOpts) ->
480    async_analyse_to_file(Module, OutFileOrOpts).
481async_analyze_to_file(Module, OutFile, Options) ->
482    async_analyse_to_file(Module, OutFile, Options).
483
484outfilename(undefined, Module, HTML) ->
485    outfilename(Module, HTML);
486outfilename(OutDir, Module, HTML) ->
487    filename:join(OutDir, outfilename(Module, HTML)).
488
489outfilename(Module, true) ->
490    atom_to_list(Module)++".COVER.html";
491outfilename(Module, false) ->
492    atom_to_list(Module)++".COVER.out".
493
494
495%% export(File)
496%% export(File,Module) -> ok | {error,Reason}
497%%   File = string(); file to write the exported data to
498%%   Module = atom()
499export(File) ->
500    export(File, '_').
501export(File, Module) ->
502    call({export,File,Module}).
503
504%% import(File) -> ok | {error, Reason}
505%%   File = string(); file created with cover:export/1,2
506import(File) ->
507    call({import,File}).
508
509%% modules() -> [Module]
510%%   Module = atom()
511modules() ->
512   call(modules).
513
514%% imported_modules() -> [Module]
515%%   Module = atom()
516imported_modules() ->
517   call(imported_modules).
518
519%% imported() -> [ImportFile]
520%%   ImportFile = string()
521imported() ->
522   call(imported).
523
524%% which_nodes() -> [Node]
525%%   Node = atom()
526which_nodes() ->
527   call(which_nodes).
528
529%% is_compiled(Module) -> {file,File} | false
530%%   Module = atom()
531%%   File = string()
532is_compiled(Module) when is_atom(Module) ->
533    call({is_compiled, Module}).
534
535%% reset(Module) -> ok | {error,Error}
536%% reset() -> ok
537%%   Module = atom()
538%%   Error = {not_cover_compiled,Module}
539reset(Module) when is_atom(Module) ->
540    call({reset, Module}).
541reset() ->
542    call(reset).
543
544%% stop() -> ok
545stop() ->
546    call(stop).
547
548stop(Node) when is_atom(Node) ->
549    stop([Node]);
550stop(Nodes) ->
551    call({stop,remove_myself(Nodes,[])}).
552
553%% flush(Nodes) -> ok | {error,not_main_node}
554%%   Nodes = [Node] | Node
555%%   Node = atom()
556%%   Error = {not_cover_compiled,Module}
557flush(Node) when is_atom(Node) ->
558    flush([Node]);
559flush(Nodes) ->
560    call({flush,remove_myself(Nodes,[])}).
561
562%% Used by test_server only. Not documented.
563get_main_node() ->
564    call(get_main_node).
565
566%% bump(Module, Function, Arity, Clause, Line)
567%%   Module = Function = atom()
568%%   Arity = Clause = Line = integer()
569%% This function is inserted into Cover compiled modules, once for each
570%% executable line.
571%bump(Module, Function, Arity, Clause, Line) ->
572%    Key = #bump{module=Module, function=Function, arity=Arity, clause=Clause,
573%		line=Line},
574%    ets:update_counter(?COVER_TABLE, Key, 1).
575
576call(Request) ->
577    Ref = erlang:monitor(process,?SERVER),
578    receive {'DOWN', Ref, _Type, _Object, noproc} ->
579	    erlang:demonitor(Ref),
580            {ok,_} = start(),
581	    call(Request)
582    after 0 ->
583	    ?SERVER ! {self(),Request},
584	    Return =
585		receive
586		    {'DOWN', Ref, _Type, _Object, Info} ->
587			exit(Info);
588		    {?SERVER,Reply} ->
589			Reply
590		end,
591	    erlang:demonitor(Ref, [flush]),
592	    Return
593    end.
594
595reply(From, Reply) ->
596    From ! {?SERVER,Reply},
597    ok.
598
599is_from(From) ->
600    is_pid(From).
601
602remote_call(Node,Request) ->
603    Ref = erlang:monitor(process,{?SERVER,Node}),
604    receive {'DOWN', Ref, _Type, _Object, noproc} ->
605	    erlang:demonitor(Ref),
606	    {error,node_dead}
607    after 0 ->
608	    {?SERVER,Node} ! Request,
609	    Return =
610		receive
611		    {'DOWN', Ref, _Type, _Object, _Info} ->
612			case Request of
613			    {remote,stop} -> ok;
614			    _ -> {error,node_dead}
615			end;
616		    {?SERVER,Reply} ->
617			Reply
618		end,
619	    erlang:demonitor(Ref, [flush]),
620	    Return
621    end.
622
623remote_reply(Proc,Reply) when is_pid(Proc) ->
624    Proc ! {?SERVER,Reply},
625    ok;
626remote_reply(MainNode,Reply) ->
627    {?SERVER,MainNode} ! {?SERVER,Reply},
628    ok.
629
630%%%----------------------------------------------------------------------
631%%% cover_server on main node
632%%%----------------------------------------------------------------------
633
634init_main(Starter) ->
635    try register(?SERVER,self()) of
636            true ->
637        %% Having write concurrancy here gives a 40% performance boost
638        %% when collect/1 is called.
639        ?COVER_TABLE = ets:new(?COVER_TABLE, [set, public, named_table,
640                                              {write_concurrency, true}]),
641        ?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
642                                                            named_table]),
643        ?BINARY_TABLE = ets:new(?BINARY_TABLE, [set, public, named_table]),
644        ?COLLECTION_TABLE = ets:new(?COLLECTION_TABLE, [set, public,
645                                                        named_table]),
646        ?COLLECTION_CLAUSE_TABLE = ets:new(?COLLECTION_CLAUSE_TABLE,
647                                           [set, public, named_table]),
648        ok = net_kernel:monitor_nodes(true),
649        Starter ! {?SERVER,started},
650        main_process_loop(#main_state{})
651    catch
652        error:badarg ->
653            %% The server's already registered; either report that it's already
654            %% started or try again if it died before we could find its pid.
655            case whereis(?SERVER) of
656                undefined ->
657                    init_main(Starter);
658                Pid ->
659                    Starter ! {?SERVER, {error, {already_started, Pid}}}
660            end
661    end.
662
663main_process_loop(State) ->
664    receive
665	{From, {start_nodes,Nodes}} ->
666	    {StartedNodes,State1} = do_start_nodes(Nodes, State),
667	    reply(From, {ok,StartedNodes}),
668	    main_process_loop(State1);
669
670	{From, {compile, Files, Options}} ->
671	    {R,S} = do_compile(Files, Options, State),
672	    reply(From,R),
673	    %% This module (cover) could have been reloaded. Make
674	    %% sure we run the new code.
675	    ?MODULE:main_process_loop(S);
676
677	{From, {compile_beams, ModsAndFiles}} ->
678	    {R,S} = do_compile_beams(ModsAndFiles,State),
679	    reply(From,R),
680	    %% This module (cover) could have been reloaded. Make
681	    %% sure we run the new code.
682	    ?MODULE:main_process_loop(S);
683
684	{From, {export,OutFile,Module}} ->
685	    spawn(fun() ->
686			  ?SPAWN_DBG(export,{OutFile, Module}),
687			  do_export(Module, OutFile, From, State)
688		  end),
689	    main_process_loop(State);
690
691	{From, {import,File}} ->
692	    case file:open(File,[read,binary,raw]) of
693		{ok,Fd} ->
694		    Imported = do_import_to_table(Fd,File,
695						  State#main_state.imported),
696		    reply(From, ok),
697		    ok = file:close(Fd),
698		    main_process_loop(State#main_state{imported=Imported});
699		{error,Reason} ->
700		    reply(From, {error, {cant_open_file,File,Reason}}),
701		    main_process_loop(State)
702	    end;
703
704	{From, modules} ->
705	    %% Get all compiled modules which are still loaded
706	    {LoadedModules,Compiled} =
707		get_compiled_still_loaded(State#main_state.nodes,
708					  State#main_state.compiled),
709
710	    reply(From, LoadedModules),
711	    main_process_loop(State#main_state{compiled=Compiled});
712
713	{From, imported_modules} ->
714	    %% Get all modules with imported data
715	    ImportedModules = lists:map(fun({Mod,_File,_ImportFile}) -> Mod end,
716					State#main_state.imported),
717	    reply(From, ImportedModules),
718	    main_process_loop(State);
719
720	{From, imported} ->
721	    %% List all imported files
722	    reply(From, get_all_importfiles(State#main_state.imported,[])),
723	    main_process_loop(State);
724
725	{From, which_nodes} ->
726	    %% List all imported files
727	    reply(From, State#main_state.nodes),
728	    main_process_loop(State);
729
730	{From, reset} ->
731	    lists:foreach(
732	      fun({Module,_File}) ->
733		      do_reset_main_node(Module,State#main_state.nodes)
734	      end,
735	      State#main_state.compiled),
736	    reply(From, ok),
737	    main_process_loop(State#main_state{imported=[]});
738
739	{From, {stop,Nodes}} ->
740	    remote_collect('_',Nodes,true),
741	    reply(From, ok),
742	    Nodes1 = State#main_state.nodes--Nodes,
743	    LostNodes1 = State#main_state.lost_nodes--Nodes,
744	    main_process_loop(State#main_state{nodes=Nodes1,
745					       lost_nodes=LostNodes1});
746
747	{From, {flush,Nodes}} ->
748	    remote_collect('_',Nodes,false),
749	    reply(From, ok),
750	    main_process_loop(State);
751
752	{From, stop} ->
753	    lists:foreach(
754	      fun(Node) ->
755		      remote_call(Node,{remote,stop})
756	      end,
757	      State#main_state.nodes),
758	    reload_originals(State#main_state.compiled),
759            ets:delete(?COVER_TABLE),
760            ets:delete(?COVER_CLAUSE_TABLE),
761            ets:delete(?BINARY_TABLE),
762            ets:delete(?COLLECTION_TABLE),
763            ets:delete(?COLLECTION_CLAUSE_TABLE),
764            unregister(?SERVER),
765	    reply(From, ok);
766
767	{From, {{analyse, Analysis, Level}, '_'}} ->
768	    R = analyse_all(Analysis, Level, State),
769	    reply(From, R),
770	    main_process_loop(State);
771
772	{From, {{analyse, Analysis, Level}, Modules}} when is_list(Modules) ->
773	    R = analyse_list(Modules, Analysis, Level, State),
774	    reply(From, R),
775	    main_process_loop(State);
776
777	{From, {{analyse, Analysis, Level}, Module}} ->
778	    S = try
779		    Loaded = is_loaded(Module, State),
780		    spawn(fun() ->
781				  ?SPAWN_DBG(analyse,{Module,Analysis, Level}),
782				  do_parallel_analysis(
783				    Module, Analysis, Level,
784				    Loaded, From, State)
785			  end),
786		    State
787		catch throw:Reason ->
788			reply(From,{error, {not_cover_compiled,Module}}),
789			not_loaded(Module, Reason, State)
790		end,
791	    main_process_loop(S);
792
793	{From, {{analyse_to_file, Opts},'_'}} ->
794	    R = analyse_all_to_file(Opts, State),
795	    reply(From,R),
796	    main_process_loop(State);
797
798	{From, {{analyse_to_file, Opts},Modules}} when is_list(Modules) ->
799	    R = analyse_list_to_file(Modules, Opts, State),
800	    reply(From,R),
801	    main_process_loop(State);
802
803	{From, {{analyse_to_file, Opts},Module}} ->
804	    S = try
805		    Loaded = is_loaded(Module, State),
806		    spawn_link(fun() ->
807				  ?SPAWN_DBG(analyse_to_file,{Module,Opts}),
808				  do_parallel_analysis_to_file(
809				    Module, Opts, Loaded, From, State)
810			  end),
811		    State
812		catch throw:Reason ->
813			reply(From,{error, {not_cover_compiled,Module}}),
814			not_loaded(Module, Reason, State)
815		end,
816	    main_process_loop(S);
817
818	{From, {is_compiled, Module}} ->
819	    S = try is_loaded(Module, State) of
820		    {loaded, File} ->
821			reply(From,{file, File}),
822			State;
823		    {imported,_File,_ImportFiles} ->
824			reply(From,false),
825			State
826		catch throw:Reason ->
827			reply(From,false),
828			not_loaded(Module, Reason, State)
829		end,
830	    main_process_loop(S);
831
832	{From, {reset, Module}} ->
833	    S = try
834		    Loaded = is_loaded(Module,State),
835		    R = case Loaded of
836			    {loaded, _File} ->
837				do_reset_main_node(
838				  Module, State#main_state.nodes);
839			    {imported, _File, _} ->
840				do_reset_collection_table(Module)
841			end,
842		    Imported =
843			remove_imported(Module,
844					State#main_state.imported),
845		    reply(From, R),
846		    State#main_state{imported=Imported}
847		catch throw:Reason ->
848			reply(From,{error, {not_cover_compiled,Module}}),
849			not_loaded(Module, Reason, State)
850		end,
851	    main_process_loop(S);
852
853	{'DOWN', _MRef, process, {?SERVER,Node}, _Info} ->
854	    %% A remote cover_server is down, mark as lost
855	    {Nodes,Lost} =
856		case lists:member(Node,State#main_state.nodes) of
857		    true ->
858			N = State#main_state.nodes--[Node],
859			L = [Node|State#main_state.lost_nodes],
860			{N,L};
861		    false -> % node stopped
862			{State#main_state.nodes,State#main_state.lost_nodes}
863		end,
864	    main_process_loop(State#main_state{nodes=Nodes,lost_nodes=Lost});
865
866	{nodeup,Node} ->
867	    State1 =
868		case lists:member(Node,State#main_state.lost_nodes) of
869		    true ->
870			sync_compiled(Node,State);
871		    false ->
872			State
873	    end,
874	    main_process_loop(State1);
875
876	{nodedown,_} ->
877	    %% Will be taken care of when 'DOWN' message arrives
878	    main_process_loop(State);
879
880	{From, get_main_node} ->
881	    reply(From, node()),
882	    main_process_loop(State);
883
884	get_status ->
885	    io:format("~tp~n",[State]),
886	    main_process_loop(State)
887    end.
888
889%%%----------------------------------------------------------------------
890%%% cover_server on remote node
891%%%----------------------------------------------------------------------
892
893init_remote(Starter,MainNode) ->
894    register(?SERVER,self()),
895    %% write_concurrency here makes otp_8270 break :(
896    ?COVER_TABLE = ets:new(?COVER_TABLE, [set, public, named_table
897                                          %,{write_concurrency, true}
898                                         ]),
899    ?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
900                                                        named_table]),
901    Starter ! {self(),started},
902    remote_process_loop(#remote_state{main_node=MainNode}).
903
904
905
906remote_process_loop(State) ->
907    receive
908	{remote,load_compiled,Compiled} ->
909	    Compiled1 = load_compiled(Compiled,State#remote_state.compiled),
910	    remote_reply(State#remote_state.main_node, ok),
911	    ?MODULE:remote_process_loop(State#remote_state{compiled=Compiled1});
912
913	{remote,unload,UnloadedModules} ->
914	    unload(UnloadedModules),
915	    Compiled =
916		update_compiled(UnloadedModules, State#remote_state.compiled),
917	    remote_reply(State#remote_state.main_node, ok),
918	    remote_process_loop(State#remote_state{compiled=Compiled});
919
920	{remote,reset,Module} ->
921	    do_reset(Module),
922	    remote_reply(State#remote_state.main_node, ok),
923	    remote_process_loop(State);
924
925	{remote,collect,Module,CollectorPid} ->
926	    self() ! {remote,collect,Module,CollectorPid, ?SERVER};
927
928	{remote,collect,Modules0,CollectorPid,From} ->
929	    Modules = case Modules0 of
930			  '_' -> [M || {M,_} <- State#remote_state.compiled];
931			  _ -> Modules0
932		      end,
933            spawn(fun() ->
934                          ?SPAWN_DBG(remote_collect,
935                                     {Modules, CollectorPid, From}),
936                          do_collect(Modules, CollectorPid, From)
937                  end),
938	    remote_process_loop(State);
939
940	{remote,stop} ->
941	    reload_originals(State#remote_state.compiled),
942	    ets:delete(?COVER_TABLE),
943            ets:delete(?COVER_CLAUSE_TABLE),
944            unregister(?SERVER),
945	    ok; % not replying since 'DOWN' message will be received anyway
946
947	{remote,get_compiled} ->
948	    remote_reply(State#remote_state.main_node,
949			 State#remote_state.compiled),
950	    remote_process_loop(State);
951
952	{From, get_main_node} ->
953	    remote_reply(From, State#remote_state.main_node),
954	    remote_process_loop(State);
955
956	get_status ->
957	    io:format("~tp~n",[State]),
958	    remote_process_loop(State);
959
960	M ->
961	    io:format("WARNING: remote cover_server received\n~p\n",[M]),
962	    case M of
963		{From,_} ->
964		    case is_from(From) of
965			true ->
966			    reply(From,{error,not_main_node});
967		        false ->
968			    ok
969		    end;
970		_ ->
971		    ok
972	    end,
973	    remote_process_loop(State)
974
975    end.
976
977do_collect(Modules, CollectorPid, From) ->
978    _ = pmap(
979          fun(Module) ->
980                  Pattern = {#bump{module=Module, _='_'}, '$1'},
981                  MatchSpec = [{Pattern,[{'=/=','$1',0}],['$_']}],
982                  Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE),
983                  send_chunks(Match, CollectorPid, [])
984          end,Modules),
985    CollectorPid ! done,
986    remote_reply(From, ok).
987
988send_chunks('$end_of_table', _CollectorPid, Mons) ->
989    get_downs(Mons);
990send_chunks({Chunk,Continuation}, CollectorPid, Mons) ->
991    Mon = spawn_monitor(
992	    fun() ->
993		    lists:foreach(fun({Bump,_N}) ->
994					  ets:insert(?COVER_TABLE, {Bump,0})
995				  end,
996				  Chunk) end),
997    send_chunk(CollectorPid,Chunk),
998    send_chunks(ets:select(Continuation), CollectorPid, [Mon|Mons]).
999
1000send_chunk(CollectorPid,Chunk) ->
1001    CollectorPid ! {chunk,Chunk,self()},
1002    receive continue -> ok end.
1003
1004get_downs([]) ->
1005    ok;
1006get_downs(Mons) ->
1007    receive
1008	{'DOWN', Ref, _Type, Pid, _Reason} = Down ->
1009	    case lists:member({Pid,Ref},Mons) of
1010		true ->
1011		    get_downs(lists:delete({Pid,Ref},Mons));
1012		false ->
1013		    %% This should be handled somewhere else
1014		    self() ! Down,
1015		    get_downs(Mons)
1016	    end
1017    end.
1018
1019reload_originals(Compiled) ->
1020    _ = pmap(fun do_reload_original/1, [M || {M,_} <- Compiled]),
1021    ok.
1022
1023do_reload_original(Module) ->
1024    case code:which(Module) of
1025	?TAG ->
1026	    _ = code:purge(Module),     % remove code marked as 'old'
1027	    _ = code:delete(Module),    % mark cover compiled code as 'old'
1028	    %% Note: original beam code must be loaded before the cover
1029	    %% compiled code is purged, in order to for references to
1030	    %% 'fun M:F/A' and %% 'fun F/A' funs to be correct (they
1031	    %% refer to (M:)F/A in the *latest* version  of the module)
1032            _ = code:load_file(Module), % load original code
1033	    _ = code:purge(Module);     % remove cover compiled code
1034	_ ->
1035	    ignore
1036    end.
1037
1038load_compiled([{Module,File,Binary,InitialTable}|Compiled],Acc) ->
1039    %% Make sure the #bump{} records are available *before* the
1040    %% module is loaded.
1041    insert_initial_data(InitialTable),
1042    Sticky = case code:is_sticky(Module) of
1043                 true ->
1044                     code:unstick_mod(Module),
1045                     true;
1046                 false ->
1047                     false
1048             end,
1049    NewAcc = case code:load_binary(Module, ?TAG, Binary) of
1050                 {module,Module} ->
1051                     add_compiled(Module, File, Acc);
1052                 _  ->
1053                     do_clear(Module),
1054                     Acc
1055             end,
1056    case Sticky of
1057        true -> code:stick_mod(Module);
1058        false -> ok
1059    end,
1060    load_compiled(Compiled,NewAcc);
1061load_compiled([],Acc) ->
1062    Acc.
1063
1064insert_initial_data([Item|Items]) when is_atom(element(1,Item)) ->
1065    ets:insert(?COVER_CLAUSE_TABLE, Item),
1066    insert_initial_data(Items);
1067insert_initial_data([Item|Items]) ->
1068    ets:insert(?COVER_TABLE, Item),
1069    insert_initial_data(Items);
1070insert_initial_data([]) ->
1071    ok.
1072
1073
1074unload([Module|Modules]) ->
1075    do_clear(Module),
1076    do_reload_original(Module),
1077    unload(Modules);
1078unload([]) ->
1079    ok.
1080
1081%%%----------------------------------------------------------------------
1082%%% Internal functions
1083%%%----------------------------------------------------------------------
1084
1085%%%--Handling of remote nodes--------------------------------------------
1086
1087do_start_nodes(Nodes, State) ->
1088    ThisNode = node(),
1089    StartedNodes =
1090	lists:foldl(
1091	  fun(Node,Acc) ->
1092		  case rpc:call(Node,cover,remote_start,[ThisNode]) of
1093		      {ok,_RPid} ->
1094			  erlang:monitor(process,{?SERVER,Node}),
1095			  [Node|Acc];
1096		      Error ->
1097			  io:format("Could not start cover on ~w: ~tp\n",
1098				    [Node,Error]),
1099			  Acc
1100		  end
1101	  end,
1102	  [],
1103	  Nodes),
1104
1105    %% In case some of the compiled modules have been unloaded they
1106    %% should not be loaded on the new node.
1107    {_LoadedModules,Compiled} =
1108	get_compiled_still_loaded(State#main_state.nodes,
1109				  State#main_state.compiled),
1110    remote_load_compiled(StartedNodes,Compiled),
1111
1112    State1 =
1113	State#main_state{nodes = State#main_state.nodes ++ StartedNodes,
1114			 compiled = Compiled},
1115    {StartedNodes, State1}.
1116
1117%% start the cover_server on a remote node
1118remote_start(MainNode) ->
1119    case whereis(?SERVER) of
1120	undefined ->
1121	    Starter = self(),
1122	    Pid = spawn(fun() ->
1123				?SPAWN_DBG(remote_start,{MainNode}),
1124				init_remote(Starter,MainNode)
1125			end),
1126	    Ref = erlang:monitor(process,Pid),
1127	    Return =
1128		receive
1129		    {Pid,started} ->
1130			{ok,Pid};
1131		    {'DOWN', Ref, _Type, _Object, Info} ->
1132			{error,Info}
1133		end,
1134	    erlang:demonitor(Ref),
1135	    Return;
1136	Pid ->
1137	    {error,{already_started,Pid}}
1138    end.
1139
1140%% If a lost node comes back, ensure that main and remote node has the
1141%% same cover compiled modules. Note that no action is taken if the
1142%% same {Mod,File} eksists on both, i.e. code change is not handled!
1143sync_compiled(Node,State) ->
1144    #main_state{compiled=Compiled0,nodes=Nodes,lost_nodes=Lost}=State,
1145    State1 =
1146	case remote_call(Node,{remote,get_compiled}) of
1147	    {error,node_dead} ->
1148		{_,S} = do_start_nodes([Node],State),
1149		S;
1150	    {error,_} ->
1151		State;
1152	    RemoteCompiled ->
1153		{_,Compiled} =  get_compiled_still_loaded(Nodes,Compiled0),
1154		Unload = [UM || {UM,_}=U <- RemoteCompiled,
1155			       false == lists:member(U,Compiled)],
1156		remote_unload([Node],Unload),
1157		Load = [L || L <- Compiled,
1158			     false == lists:member(L,RemoteCompiled)],
1159		remote_load_compiled([Node],Load),
1160		State#main_state{compiled=Compiled, nodes=[Node|Nodes]}
1161	end,
1162    State1#main_state{lost_nodes=Lost--[Node]}.
1163
1164%% Load a set of cover compiled modules on remote nodes,
1165%% We do it ?MAX_MODS modules at a time so that we don't
1166%% run out of memory on the cover_server node.
1167-define(MAX_MODS, 10).
1168remote_load_compiled(Nodes,Compiled) ->
1169    remote_load_compiled(Nodes, Compiled, [], 0).
1170remote_load_compiled(_Nodes, [], [], _ModNum) ->
1171    ok;
1172remote_load_compiled(Nodes, Compiled, Acc, ModNum)
1173  when Compiled == []; ModNum == ?MAX_MODS ->
1174    RemoteLoadData = get_downs_r(Acc),
1175    lists:foreach(
1176      fun(Node) ->
1177	      remote_call(Node,{remote,load_compiled,RemoteLoadData})
1178      end,
1179      Nodes),
1180    remote_load_compiled(Nodes, Compiled, [], 0);
1181remote_load_compiled(Nodes, [MF | Rest], Acc, ModNum) ->
1182    remote_load_compiled(
1183      Nodes, Rest,
1184      [spawn_job_r(fun() -> get_data_for_remote_loading(MF) end) | Acc],
1185      ModNum + 1).
1186
1187spawn_job_r(Fun) ->
1188    spawn_monitor(fun() -> exit(Fun()) end).
1189
1190get_downs_r([]) ->
1191    [];
1192get_downs_r(Mons) ->
1193    receive
1194	{'DOWN', Ref, _Type, Pid, R={_,_,_,_}} ->
1195	    [R|get_downs_r(lists:delete({Pid,Ref},Mons))];
1196	{'DOWN', Ref, _Type, Pid, Reason} = Down ->
1197	    case lists:member({Pid,Ref},Mons) of
1198		true ->
1199		    %% Something went really wrong - don't hang!
1200		    exit(Reason);
1201		false ->
1202		    %% This should be handled somewhere else
1203		    self() ! Down,
1204		    get_downs_r(Mons)
1205	    end
1206    end.
1207
1208
1209%% Read all data needed for loading a cover compiled module on a remote node
1210%% Binary is the beam code for the module and InitialTable is the initial
1211%% data to insert in ?COVER_TABLE.
1212get_data_for_remote_loading({Module,File}) ->
1213    [{Module,Binary}] = ets:lookup(?BINARY_TABLE,Module),
1214    %%! The InitialTable list will be long if the module is big - what to do??
1215    InitialBumps = ets:select(?COVER_TABLE,ms(Module)),
1216    InitialClauses = ets:lookup(?COVER_CLAUSE_TABLE,Module),
1217
1218    {Module,File,Binary,InitialBumps ++ InitialClauses}.
1219
1220%% Create a match spec which returns the clause info {Module,InitInfo} and
1221%% all #bump keys for the given module with 0 number of calls.
1222ms(Module) ->
1223    ets:fun2ms(fun({Key,_}) when Key#bump.module=:=Module ->
1224		       {Key,0}
1225	       end).
1226
1227%% Unload modules on remote nodes
1228remote_unload(Nodes,UnloadedModules) ->
1229    lists:foreach(
1230      fun(Node) ->
1231	      remote_call(Node,{remote,unload,UnloadedModules})
1232      end,
1233      Nodes).
1234
1235%% Reset one or all modules on remote nodes
1236remote_reset(Module,Nodes) ->
1237    lists:foreach(
1238      fun(Node) ->
1239	      remote_call(Node,{remote,reset,Module})
1240      end,
1241      Nodes).
1242
1243%% Collect data from remote nodes - used for analyse or stop(Node)
1244remote_collect(Modules,Nodes,Stop) ->
1245    _ = pmap(
1246          fun(Node) ->
1247                  ?SPAWN_DBG(remote_collect,
1248                             {Modules, Nodes, Stop}),
1249                  do_collection(Node, Modules, Stop)
1250          end, Nodes),
1251    ok.
1252
1253do_collection(Node, Module, Stop) ->
1254    CollectorPid = spawn(fun collector_proc/0),
1255    case remote_call(Node,{remote,collect,Module,CollectorPid, self()}) of
1256	{error,node_dead} ->
1257	    CollectorPid ! done,
1258	    ok;
1259	ok when Stop ->
1260	    remote_call(Node,{remote,stop});
1261	ok ->
1262	    ok
1263    end.
1264
1265%% Process which receives chunks of data from remote nodes - either when
1266%% analysing or when stopping cover on the remote nodes.
1267collector_proc() ->
1268    ?SPAWN_DBG(collector_proc, []),
1269    receive
1270	{chunk,Chunk,From} ->
1271	    insert_in_collection_table(Chunk),
1272	    From ! continue,
1273	    collector_proc();
1274	done ->
1275	    ok
1276    end.
1277
1278insert_in_collection_table([{Key,Val}|Chunk]) ->
1279    insert_in_collection_table(Key,Val),
1280    insert_in_collection_table(Chunk);
1281insert_in_collection_table([]) ->
1282    ok.
1283
1284insert_in_collection_table(Key,Val) ->
1285    case ets:member(?COLLECTION_TABLE,Key) of
1286	true ->
1287	    _ = ets:update_counter(?COLLECTION_TABLE, Key,Val),
1288            ok;
1289	false ->
1290	    %% Make sure that there are no race conditions from ets:member
1291	    case ets:insert_new(?COLLECTION_TABLE,{Key,Val}) of
1292		false ->
1293		    insert_in_collection_table(Key,Val);
1294		_ ->
1295		    ok
1296	    end
1297    end.
1298
1299
1300remove_myself([Node|Nodes],Acc) when Node=:=node() ->
1301    remove_myself(Nodes,Acc);
1302remove_myself([Node|Nodes],Acc) ->
1303    remove_myself(Nodes,[Node|Acc]);
1304remove_myself([],Acc) ->
1305    Acc.
1306
1307%%%--Handling of modules state data--------------------------------------
1308
1309analyse_info(_Module,[]) ->
1310    ok;
1311analyse_info(Module,Imported) ->
1312    imported_info("Analysis",Module,Imported).
1313
1314export_info(_Module,[]) ->
1315    ok;
1316export_info(_Module,_Imported) ->
1317    %% Do not print that the export includes imported modules
1318    ok.
1319
1320export_info([]) ->
1321    ok;
1322export_info(_Imported) ->
1323    %% Do not print that the export includes imported modules
1324    ok.
1325
1326get_all_importfiles([{_M,_F,ImportFiles}|Imported],Acc) ->
1327    NewAcc = do_get_all_importfiles(ImportFiles,Acc),
1328    get_all_importfiles(Imported,NewAcc);
1329get_all_importfiles([],Acc) ->
1330    Acc.
1331
1332do_get_all_importfiles([ImportFile|ImportFiles],Acc) ->
1333    case lists:member(ImportFile,Acc) of
1334	true ->
1335	    do_get_all_importfiles(ImportFiles,Acc);
1336	false ->
1337	    do_get_all_importfiles(ImportFiles,[ImportFile|Acc])
1338    end;
1339do_get_all_importfiles([],Acc) ->
1340    Acc.
1341
1342imported_info(Text,Module,Imported) ->
1343    case lists:keysearch(Module,1,Imported) of
1344	{value,{Module,_File,ImportFiles}} ->
1345	    io:format("~ts includes data from imported files\n~tp\n",
1346		      [Text,ImportFiles]);
1347	false ->
1348	    ok
1349    end.
1350
1351
1352
1353add_imported(Module, File, ImportFile, Imported) ->
1354    add_imported(Module, File, filename:absname(ImportFile), Imported, []).
1355
1356add_imported(M, F1, ImportFile, [{M,_F2,ImportFiles}|Imported], Acc) ->
1357    case lists:member(ImportFile,ImportFiles) of
1358	true ->
1359	    io:fwrite("WARNING: Module ~w already imported from ~tp~n"
1360		      "Not importing again!~n",[M,ImportFile]),
1361	    dont_import;
1362	false ->
1363	    NewEntry = {M, F1, [ImportFile | ImportFiles]},
1364	    {ok, lists:reverse([NewEntry | Acc]) ++ Imported}
1365    end;
1366add_imported(M, F, ImportFile, [H|Imported], Acc) ->
1367    add_imported(M, F, ImportFile, Imported, [H|Acc]);
1368add_imported(M, F, ImportFile, [], Acc) ->
1369    {ok, lists:reverse([{M, F, [ImportFile]} | Acc])}.
1370
1371%% Removes a module from the list of imported modules and writes a warning
1372%% This is done when a module is compiled.
1373remove_imported(Module,Imported) ->
1374    case lists:keysearch(Module,1,Imported) of
1375	{value,{Module,_,ImportFiles}} ->
1376	    io:fwrite("WARNING: Deleting data for module ~w imported from~n"
1377		      "~tp~n",[Module,ImportFiles]),
1378	    lists:keydelete(Module,1,Imported);
1379	false ->
1380	    Imported
1381    end.
1382
1383%% Adds information to the list of compiled modules, preserving time order
1384%% and without adding duplicate entries.
1385add_compiled(Module, File1, [{Module,_File2}|Compiled]) ->
1386    [{Module,File1}|Compiled];
1387add_compiled(Module, File, [H|Compiled]) ->
1388    [H|add_compiled(Module, File, Compiled)];
1389add_compiled(Module, File, []) ->
1390    [{Module,File}].
1391
1392are_loaded([Module|Modules], State, Loaded, Imported, Error) ->
1393    try is_loaded(Module,State) of
1394	{loaded,File} ->
1395	    are_loaded(Modules, State, [{Module,File}|Loaded], Imported, Error);
1396	{imported,File,_} ->
1397	    are_loaded(Modules, State, Loaded, [{Module,File}|Imported], Error)
1398    catch throw:_ ->
1399	    are_loaded(Modules, State, Loaded, Imported,
1400		       [{not_cover_compiled,Module}|Error])
1401    end;
1402are_loaded([], _State, Loaded, Imported, Error) ->
1403    {Loaded, Imported, Error}.
1404
1405is_loaded(Module, State) ->
1406    case get_file(Module, State#main_state.compiled) of
1407	{ok, File} ->
1408	    case code:which(Module) of
1409		?TAG -> {loaded, File};
1410		_ -> throw(unloaded)
1411	    end;
1412	false ->
1413	    case get_file(Module,State#main_state.imported) of
1414		{ok,File,ImportFiles} ->
1415		    {imported, File, ImportFiles};
1416		false ->
1417		    throw(not_loaded)
1418	    end
1419    end.
1420
1421get_file(Module, [{Module, File}|_T]) ->
1422    {ok, File};
1423get_file(Module, [{Module, File, ImportFiles}|_T]) ->
1424    {ok, File, ImportFiles};
1425get_file(Module, [_H|T]) ->
1426    get_file(Module, T);
1427get_file(_Module, []) ->
1428    false.
1429
1430get_beam_file(Module,?TAG,Compiled) ->
1431    {value,{Module,File}} = lists:keysearch(Module,1,Compiled),
1432    case filename:extension(File) of
1433	".erl" -> {error,no_beam};
1434	".beam" -> {ok,File}
1435    end;
1436get_beam_file(_Module,BeamFile,_Compiled) ->
1437    {ok,BeamFile}.
1438
1439get_modules(Compiled) ->
1440    lists:map(fun({Module, _File}) -> Module end, Compiled).
1441
1442update_compiled([Module|Modules], [{Module,_File}|Compiled]) ->
1443    update_compiled(Modules, Compiled);
1444update_compiled(Modules, [H|Compiled]) ->
1445    [H|update_compiled(Modules, Compiled)];
1446update_compiled(_Modules, []) ->
1447    [].
1448
1449%% Get all compiled modules which are still loaded, and possibly an
1450%% updated version of the Compiled list.
1451get_compiled_still_loaded(Nodes,Compiled0) ->
1452    %% Find all Cover compiled modules which are still loaded
1453    CompiledModules = get_modules(Compiled0),
1454    LoadedModules = lists:filter(fun(Module) ->
1455					 case code:which(Module) of
1456					     ?TAG -> true;
1457					     _ -> false
1458					 end
1459				 end,
1460				 CompiledModules),
1461
1462    %% If some Cover compiled modules have been unloaded, update the database.
1463    UnloadedModules = CompiledModules--LoadedModules,
1464    Compiled =
1465	case UnloadedModules of
1466	    [] ->
1467		Compiled0;
1468	    _ ->
1469		lists:foreach(fun(Module) -> do_clear(Module) end,
1470			      UnloadedModules),
1471		remote_unload(Nodes,UnloadedModules),
1472		update_compiled(UnloadedModules, Compiled0)
1473	end,
1474    {LoadedModules,Compiled}.
1475
1476
1477%%%--Compilation---------------------------------------------------------
1478
1479do_compile_beams(ModsAndFiles, State) ->
1480    Result0 = pmap(fun({ok,Module,File}) ->
1481			  do_compile_beam(Module,File,State);
1482		     (Error) ->
1483			  Error
1484		  end,
1485		  ModsAndFiles),
1486    Compiled = [{M,F} || {ok,M,F} <- Result0],
1487    remote_load_compiled(State#main_state.nodes,Compiled),
1488    fix_state_and_result(Result0,State,[]).
1489
1490do_compile_beam(Module,BeamFile0,State) ->
1491    case get_beam_file(Module,BeamFile0,State#main_state.compiled) of
1492	{ok,BeamFile} ->
1493	    UserOptions = get_compile_options(Module,BeamFile),
1494	    case do_compile_beam1(Module,BeamFile,UserOptions) of
1495		{ok, Module} ->
1496		    {ok,Module,BeamFile};
1497		error ->
1498		    {error, BeamFile};
1499		{error,Reason} -> % no abstract code or no 'file' attribute
1500		    {error, {Reason, BeamFile}}
1501	    end;
1502	{error,no_beam} ->
1503	    %% The module has first been compiled from .erl, and now
1504	    %% someone tries to compile it from .beam
1505	    {error,{already_cover_compiled,no_beam_found,Module}}
1506    end.
1507
1508fix_state_and_result([{ok,Module,BeamFile}|Rest],State,Acc) ->
1509    Compiled = add_compiled(Module,BeamFile,State#main_state.compiled),
1510    Imported = remove_imported(Module,State#main_state.imported),
1511    NewState = State#main_state{compiled=Compiled,imported=Imported},
1512    fix_state_and_result(Rest,NewState,[{ok,Module}|Acc]);
1513fix_state_and_result([Error|Rest],State,Acc) ->
1514    fix_state_and_result(Rest,State,[Error|Acc]);
1515fix_state_and_result([],State,Acc) ->
1516    {lists:reverse(Acc),State}.
1517
1518
1519do_compile(Files, Options, State) ->
1520    Result0 = pmap(fun(File) ->
1521			   do_compile(File, Options)
1522		   end,
1523		   Files),
1524    Compiled = [{M,F} || {ok,M,F} <- Result0],
1525    remote_load_compiled(State#main_state.nodes,Compiled),
1526    fix_state_and_result(Result0,State,[]).
1527
1528do_compile(File, Options) ->
1529    case do_compile1(File, Options) of
1530	{ok, Module} ->
1531	    {ok,Module,File};
1532	error ->
1533	    {error,File}
1534    end.
1535
1536%% do_compile1(File, Options) -> {ok,Module} | error
1537do_compile1(File, UserOptions) ->
1538    Options = [debug_info,binary,report_errors,report_warnings] ++ UserOptions,
1539    case compile:file(File, Options) of
1540	{ok, Module, Binary} ->
1541	    do_compile_beam1(Module,Binary,UserOptions);
1542	error ->
1543	    error
1544    end.
1545
1546%% Beam is a binary or a .beam file name
1547do_compile_beam1(Module,Beam,UserOptions) ->
1548    %% Clear database
1549    do_clear(Module),
1550
1551    %% Extract the abstract format and insert calls to bump/6 at
1552    %% every executable line and, as a side effect, initiate
1553    %% the database
1554
1555    case get_abstract_code(Module, Beam) of
1556	no_abstract_code=E ->
1557	    {error,E};
1558	encrypted_abstract_code=E ->
1559	    {error,E};
1560	{raw_abstract_v1,Code} ->
1561            Forms0 = epp:interpret_file_attribute(Code),
1562	    case find_main_filename(Forms0) of
1563		{ok,MainFile} ->
1564		    do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile);
1565		Error ->
1566		    Error
1567	    end;
1568	{_VSN,_Code} ->
1569	    %% Wrong version of abstract code. Just report that there
1570	    %% is no abstract code.
1571	    {error,no_abstract_code}
1572    end.
1573
1574get_abstract_code(Module, Beam) ->
1575    case beam_lib:chunks(Beam, [abstract_code]) of
1576	{ok, {Module, [{abstract_code, AbstractCode}]}} ->
1577	    AbstractCode;
1578	{error,beam_lib,{key_missing_or_invalid,_,_}} ->
1579	    encrypted_abstract_code;
1580	Error -> Error
1581    end.
1582
1583do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile) ->
1584    {Forms,Vars} = transform(Forms0, Module, MainFile),
1585
1586    %% We need to recover the source from the compilation
1587    %% info otherwise the newly compiled module will have
1588    %% source pointing to the current directory
1589    SourceInfo = get_source_info(Module, Beam),
1590
1591    %% Compile and load the result
1592    %% It's necessary to check the result of loading since it may
1593    %% fail, for example if Module resides in a sticky directory
1594    {ok, Module, Binary} = compile:forms(Forms, SourceInfo ++ UserOptions),
1595    case code:load_binary(Module, ?TAG, Binary) of
1596	{module, Module} ->
1597
1598	    %% Store info about all function clauses in database
1599	    InitInfo = lists:reverse(Vars#vars.init_info),
1600	    ets:insert(?COVER_CLAUSE_TABLE, {Module, InitInfo}),
1601
1602	    %% Store binary code so it can be loaded on remote nodes
1603	    ets:insert(?BINARY_TABLE, {Module, Binary}),
1604
1605	    {ok, Module};
1606
1607	_Error ->
1608	    do_clear(Module),
1609	    error
1610    end.
1611
1612get_source_info(Module, Beam) ->
1613    Compile = get_compile_info(Module, Beam),
1614    case lists:keyfind(source, 1, Compile) of
1615        { source, _ } = Tuple -> [Tuple];
1616        false -> []
1617    end.
1618
1619get_compile_options(Module, Beam) ->
1620    Compile = get_compile_info(Module, Beam),
1621    case lists:keyfind(options, 1, Compile) of
1622        {options, Options } -> filter_options(Options);
1623        false -> []
1624    end.
1625
1626get_compile_info(Module, Beam) ->
1627    case beam_lib:chunks(Beam, [compile_info]) of
1628	{ok, {Module, [{compile_info, Compile}]}} ->
1629		Compile;
1630	_ ->
1631		[]
1632    end.
1633
1634transform(Code, Module, MainFile) ->
1635    Vars0 = #vars{module=Module},
1636    {ok,MungedForms,Vars} = transform_2(Code,[],Vars0,MainFile,on),
1637    {MungedForms,Vars}.
1638
1639%% Helpfunction which returns the first found file-attribute, which can
1640%% be interpreted as the name of the main erlang source file.
1641find_main_filename([{attribute,_,file,{MainFile,_}}|_]) ->
1642    {ok,MainFile};
1643find_main_filename([_|Rest]) ->
1644    find_main_filename(Rest);
1645find_main_filename([]) ->
1646    {error, no_file_attribute}.
1647
1648
1649transform_2([Form0|Forms],MungedForms,Vars,MainFile,Switch) ->
1650    Form = expand(Form0),
1651    case munge(Form,Vars,MainFile,Switch) of
1652	ignore ->
1653	    transform_2(Forms,MungedForms,Vars,MainFile,Switch);
1654	{MungedForm,Vars2,NewSwitch} ->
1655	    transform_2(Forms,[MungedForm|MungedForms],Vars2,MainFile,NewSwitch)
1656    end;
1657transform_2([],MungedForms,Vars,_,_) ->
1658    {ok, lists:reverse(MungedForms), Vars}.
1659
1660%% Expand short-circuit Boolean expressions.
1661expand(Expr) ->
1662    AllVars = sets:from_list(ordsets:to_list(vars([], Expr))),
1663    {Expr1,_} = expand(Expr, AllVars, 1),
1664    Expr1.
1665
1666expand({clause,Line,Pattern,Guards,Body}, Vs, N) ->
1667    {ExpandedBody,N2} = expand(Body, Vs, N),
1668    {{clause,Line,Pattern,Guards,ExpandedBody},N2};
1669expand({op,_Line,'andalso',ExprL,ExprR}, Vs, N) ->
1670    {ExpandedExprL,N2} = expand(ExprL, Vs, N),
1671    {ExpandedExprR,N3} = expand(ExprR, Vs, N2),
1672    Anno = element(2, ExpandedExprL),
1673    {bool_switch(ExpandedExprL,
1674                 ExpandedExprR,
1675                 {atom,Anno,false},
1676                 Vs, N3),
1677     N3 + 1};
1678expand({op,_Line,'orelse',ExprL,ExprR}, Vs, N) ->
1679    {ExpandedExprL,N2} = expand(ExprL, Vs, N),
1680    {ExpandedExprR,N3} = expand(ExprR, Vs, N2),
1681    Anno = element(2, ExpandedExprL),
1682    {bool_switch(ExpandedExprL,
1683                 {atom,Anno,true},
1684                 ExpandedExprR,
1685                 Vs, N3),
1686     N3 + 1};
1687expand(T, Vs, N) when is_tuple(T) ->
1688    {TL,N2} = expand(tuple_to_list(T), Vs, N),
1689    {list_to_tuple(TL),N2};
1690expand([E|Es], Vs, N) ->
1691    {E2,N2} = expand(E, Vs, N),
1692    {Es2,N3} = expand(Es, Vs, N2),
1693    {[E2|Es2],N3};
1694expand(T, _Vs, N) ->
1695    {T,N}.
1696
1697vars(A, {var,_,V}) when V =/= '_' ->
1698    [V|A];
1699vars(A, T) when is_tuple(T) ->
1700    vars(A, tuple_to_list(T));
1701vars(A, [E|Es]) ->
1702    vars(vars(A, E), Es);
1703vars(A, _T) ->
1704    A.
1705
1706bool_switch(E, T, F, AllVars, AuxVarN) ->
1707    Line = element(2, E),
1708    AuxVar = {var,Line,aux_var(AllVars, AuxVarN)},
1709    {'case',Line,E,
1710     [{clause,Line,[{atom,Line,true}],[],[T]},
1711      {clause,Line,[{atom,Line,false}],[],[F]},
1712      {clause,Line,[AuxVar],[],
1713       [{call,Line,
1714         {remote,Line,{atom,Line,erlang},{atom,Line,error}},
1715         [{tuple,Line,[{atom,Line,badarg},AuxVar]}]}]}]}.
1716
1717aux_var(Vars, N) ->
1718    Name = list_to_atom(lists:concat(['_', N])),
1719    case sets:is_element(Name, Vars) of
1720        true -> aux_var(Vars, N + 1);
1721        false -> Name
1722    end.
1723
1724%% This code traverses the abstract code, stored as the abstract_code
1725%% chunk in the BEAM file, as described in absform(3).
1726%% The switch is turned off when we encounter other files than the main file.
1727%% This way we will be able to exclude functions defined in include files.
1728munge({function,Line,Function,Arity,Clauses},Vars,_MainFile,on) ->
1729    Vars2 = Vars#vars{function=Function,
1730		      arity=Arity,
1731		      clause=1,
1732		      lines=[],
1733                      no_bump_lines=[],
1734		      depth=1},
1735    {MungedClauses, Vars3} = munge_clauses(Clauses, Vars2),
1736    {{function,Line,Function,Arity,MungedClauses},Vars3,on};
1737munge(Form={attribute,_,file,{MainFile,_}},Vars,MainFile,_Switch) ->
1738    {Form,Vars,on};                     % Switch on tranformation!
1739munge(Form={attribute,_,file,{_InclFile,_}},Vars,_MainFile,_Switch) ->
1740    {Form,Vars,off};                    % Switch off transformation!
1741munge({attribute,_,compile,{parse_transform,_}},_Vars,_MainFile,_Switch) ->
1742    %% Don't want to run parse transforms more than once.
1743    ignore;
1744munge(Form,Vars,_MainFile,Switch) ->    % Other attributes and skipped includes.
1745    {Form,Vars,Switch}.
1746
1747munge_clauses(Clauses, Vars) ->
1748    munge_clauses(Clauses, Vars, Vars#vars.lines, []).
1749
1750munge_clauses([Clause|Clauses], Vars, Lines, MClauses) ->
1751    {clause,Line,Pattern,Guards,Body} = Clause,
1752    {MungedGuards, _Vars} = munge_exprs(Guards, Vars#vars{is_guard=true},[]),
1753
1754    case Vars#vars.depth of
1755	1 -> % function clause
1756	    {MungedBody, Vars2} = munge_body(Body, Vars#vars{depth=2}),
1757	    ClauseInfo = {Vars2#vars.module,
1758			  Vars2#vars.function,
1759			  Vars2#vars.arity,
1760			  Vars2#vars.clause,
1761			  length(Vars2#vars.lines)}, % Not used?
1762	    InitInfo = [ClauseInfo | Vars2#vars.init_info],
1763	    Vars3 = Vars2#vars{init_info=InitInfo,
1764			       clause=(Vars2#vars.clause)+1,
1765			       lines=[],
1766                               no_bump_lines=[],
1767			       depth=1},
1768            NewBumps = Vars2#vars.lines,
1769            NewLines = NewBumps ++ Lines,
1770	    munge_clauses(Clauses, Vars3, NewLines,
1771			  [{clause,Line,Pattern,MungedGuards,MungedBody}|
1772			   MClauses]);
1773
1774	2 -> % receive-,  case-, if-, or try-clause
1775            Lines0 = Vars#vars.lines,
1776	    {MungedBody, Vars2} = munge_body(Body, Vars),
1777            NewBumps = new_bumps(Vars2, Vars),
1778            NewLines = NewBumps ++ Lines,
1779	    munge_clauses(Clauses, Vars2#vars{lines=Lines0},
1780                          NewLines,
1781			  [{clause,Line,Pattern,MungedGuards,MungedBody}|
1782			   MClauses])
1783    end;
1784munge_clauses([], Vars, Lines, MungedClauses) ->
1785    {lists:reverse(MungedClauses), Vars#vars{lines = Lines}}.
1786
1787munge_body(Expr, Vars) ->
1788    munge_body(Expr, Vars, [], []).
1789
1790munge_body([Expr|Body], Vars, MungedBody, LastExprBumpLines) ->
1791    %% Here is the place to add a call to cover:bump/6!
1792    Line = erl_anno:line(element(2, Expr)),
1793    Lines = Vars#vars.lines,
1794    case lists:member(Line,Lines) of
1795	true -> % already a bump at this line
1796	    {MungedExpr, Vars2} = munge_expr(Expr, Vars),
1797            NewBumps = new_bumps(Vars2, Vars),
1798            NoBumpLines = [Line|Vars#vars.no_bump_lines],
1799            Vars3 = Vars2#vars{no_bump_lines = NoBumpLines},
1800            MungedBody1 =
1801                maybe_fix_last_expr(MungedBody, Vars3, LastExprBumpLines),
1802            MungedExprs1 = [MungedExpr|MungedBody1],
1803	    munge_body(Body, Vars3, MungedExprs1, NewBumps);
1804	false ->
1805	    ets:insert(?COVER_TABLE, {#bump{module   = Vars#vars.module,
1806					    function = Vars#vars.function,
1807					    arity    = Vars#vars.arity,
1808					    clause   = Vars#vars.clause,
1809					    line     = Line},
1810				      0}),
1811            Bump = bump_call(Vars, Line),
1812%	    Bump = {call, 0, {remote, 0, {atom,0,cover}, {atom,0,bump}},
1813%		    [{atom, 0, Vars#vars.module},
1814%		     {atom, 0, Vars#vars.function},
1815%		     {integer, 0, Vars#vars.arity},
1816%		     {integer, 0, Vars#vars.clause},
1817%		     {integer, 0, Line}]},
1818	    Lines2 = [Line|Lines],
1819	    {MungedExpr, Vars2} = munge_expr(Expr, Vars#vars{lines=Lines2}),
1820            NewBumps = new_bumps(Vars2, Vars),
1821            NoBumpLines = subtract(Vars2#vars.no_bump_lines, NewBumps),
1822            Vars3 = Vars2#vars{no_bump_lines = NoBumpLines},
1823            MungedBody1 =
1824                maybe_fix_last_expr(MungedBody, Vars3, LastExprBumpLines),
1825            MungedExprs1 = [MungedExpr,Bump|MungedBody1],
1826	    munge_body(Body, Vars3, MungedExprs1, NewBumps)
1827    end;
1828munge_body([], Vars, MungedBody, _LastExprBumpLines) ->
1829    {lists:reverse(MungedBody), Vars}.
1830
1831%%% Fix last expression (OTP-8188). A typical example:
1832%%%
1833%%%  3:   case X of
1834%%%  4:       1 -> a; % Bump line 5 after "a" has been evaluated!
1835%%%  5:       2 -> b; 3 -> c end, F()
1836%%%
1837%%% Line 5 wasn't bumped just before "F()" since it was already bumped
1838%%% before "b" (and before "c") (one mustn't bump a line more than
1839%%% once in a single "evaluation"). The expression "case X ... end" is
1840%%% now traversed again ("fixed"), this time adding bumps of line 5
1841%%% where appropriate, in this case when X matches 1.
1842%%%
1843%%% This doesn't solve all problems with expressions on the same line,
1844%%% though. 'case' and 'try' are tricky. An example:
1845%%%
1846%%% 7:    case case X of 1 -> foo(); % ?
1847%%% 8:                   2 -> bar() end of a -> 1;
1848%%% 9:                                     b -> 2 end.
1849%%%
1850%%% If X matches 1 and foo() evaluates to a then line 8 should be
1851%%% bumped, but not if foo() evaluates to b. In other words, line 8
1852%%% cannot be bumped after "foo()" on line 7, so one has to bump line
1853%%% 8 before "begin 1 end". But if X matches 2 and bar evaluates to a
1854%%% then line 8 would be bumped twice (there has to be a bump before
1855%%% "bar()". It is like one would have to have two copies of the inner
1856%%% clauses, one for each outer clause. Maybe the munging should be
1857%%% done on some of the compiler's "lower level" format.
1858%%%
1859%%% 'fun' is also problematic since a bump inside the body "shadows"
1860%%% the rest of the line.
1861
1862maybe_fix_last_expr(MungedExprs, Vars, LastExprBumpLines) ->
1863    case last_expr_needs_fixing(Vars, LastExprBumpLines) of
1864        {yes, Line} ->
1865            fix_last_expr(MungedExprs, Line, Vars);
1866        no ->
1867            MungedExprs
1868    end.
1869
1870last_expr_needs_fixing(Vars, LastExprBumpLines) ->
1871    case common_elems(Vars#vars.no_bump_lines, LastExprBumpLines) of
1872        [Line] -> {yes, Line};
1873        _ -> no
1874    end.
1875
1876fix_last_expr([MungedExpr|MungedExprs], Line, Vars) ->
1877    %% No need to update ?COVER_TABLE.
1878    Bump = bump_call(Vars, Line),
1879    [fix_expr(MungedExpr, Line, Bump)|MungedExprs].
1880
1881fix_expr({'if',L,Clauses}, Line, Bump) ->
1882    FixedClauses = fix_clauses(Clauses, Line, Bump),
1883    {'if',L,FixedClauses};
1884fix_expr({'case',L,Expr,Clauses}, Line, Bump) ->
1885    FixedExpr = fix_expr(Expr, Line, Bump),
1886    FixedClauses = fix_clauses(Clauses, Line, Bump),
1887    {'case',L,FixedExpr,FixedClauses};
1888fix_expr({'receive',L,Clauses}, Line, Bump) ->
1889    FixedClauses = fix_clauses(Clauses, Line, Bump),
1890    {'receive',L,FixedClauses};
1891fix_expr({'receive',L,Clauses,Expr,Body}, Line, Bump) ->
1892    FixedClauses = fix_clauses(Clauses, Line, Bump),
1893    FixedExpr = fix_expr(Expr, Line, Bump),
1894    FixedBody = fix_expr(Body, Line, Bump),
1895    {'receive',L,FixedClauses,FixedExpr,FixedBody};
1896fix_expr({'try',L,Exprs,Clauses,CatchClauses,After}, Line, Bump) ->
1897    FixedExprs = fix_expr(Exprs, Line, Bump),
1898    FixedClauses = fix_clauses(Clauses, Line, Bump),
1899    FixedCatchClauses = fix_clauses(CatchClauses, Line, Bump),
1900    FixedAfter = fix_expr(After, Line, Bump),
1901    {'try',L,FixedExprs,FixedClauses,FixedCatchClauses,FixedAfter};
1902fix_expr([E | Es], Line, Bump) ->
1903    [fix_expr(E, Line, Bump) | fix_expr(Es, Line, Bump)];
1904fix_expr(T, Line, Bump) when is_tuple(T) ->
1905    list_to_tuple(fix_expr(tuple_to_list(T), Line, Bump));
1906fix_expr(E, _Line, _Bump) ->
1907    E.
1908
1909fix_clauses([], _Line, _Bump) ->
1910    [];
1911fix_clauses(Cs, Line, Bump) ->
1912    case bumps_line(lists:last(Cs), Line) of
1913        true ->
1914            fix_cls(Cs, Line, Bump);
1915        false ->
1916            Cs
1917    end.
1918
1919fix_cls([], _Line, _Bump) ->
1920    [];
1921fix_cls([Cl | Cls], Line, Bump) ->
1922    case bumps_line(Cl, Line) of
1923        true ->
1924            [fix_expr(C, Line, Bump) || C <- [Cl | Cls]];
1925        false ->
1926            {clause,CL,P,G,Body} = Cl,
1927            UniqueVarName = list_to_atom(lists:concat(["$cover$ ",Line])),
1928            A = erl_anno:new(0),
1929            V = {var,A,UniqueVarName},
1930            [Last|Rest] = lists:reverse(Body),
1931            Body1 = lists:reverse(Rest, [{match,A,V,Last},Bump,V]),
1932            [{clause,CL,P,G,Body1} | fix_cls(Cls, Line, Bump)]
1933    end.
1934
1935bumps_line(E, L) ->
1936    try bumps_line1(E, L) catch true -> true end.
1937
1938bumps_line1({call,_,{remote,_,{atom,_,ets},{atom,_,update_counter}},
1939             [{atom,_,?COVER_TABLE},{tuple,_,[_,_,_,_,_,{integer,_,Line}]},_]},
1940            Line) ->
1941    throw(true);
1942bumps_line1([E | Es], Line) ->
1943    bumps_line1(E, Line),
1944    bumps_line1(Es, Line);
1945bumps_line1(T, Line) when is_tuple(T) ->
1946    bumps_line1(tuple_to_list(T), Line);
1947bumps_line1(_, _) ->
1948    false.
1949
1950%%% End of fix of last expression.
1951
1952bump_call(Vars, Line) ->
1953    A = erl_anno:new(0),
1954    {call,A,{remote,A,{atom,A,ets},{atom,A,update_counter}},
1955     [{atom,A,?COVER_TABLE},
1956      {tuple,A,[{atom,A,?BUMP_REC_NAME},
1957                {atom,A,Vars#vars.module},
1958                {atom,A,Vars#vars.function},
1959                {integer,A,Vars#vars.arity},
1960                {integer,A,Vars#vars.clause},
1961                {integer,A,Line}]},
1962      {integer,A,1}]}.
1963
1964munge_expr({match,Line,ExprL,ExprR}, Vars) ->
1965    {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
1966    {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
1967    {{match,Line,MungedExprL,MungedExprR}, Vars3};
1968munge_expr({tuple,Line,Exprs}, Vars) ->
1969    {MungedExprs, Vars2} = munge_exprs(Exprs, Vars, []),
1970    {{tuple,Line,MungedExprs}, Vars2};
1971munge_expr({record,Line,Name,Exprs}, Vars) ->
1972    {MungedExprFields, Vars2} = munge_exprs(Exprs, Vars, []),
1973    {{record,Line,Name,MungedExprFields}, Vars2};
1974munge_expr({record,Line,Arg,Name,Exprs}, Vars) ->
1975    {MungedArg, Vars2} = munge_expr(Arg, Vars),
1976    {MungedExprFields, Vars3} = munge_exprs(Exprs, Vars2, []),
1977    {{record,Line,MungedArg,Name,MungedExprFields}, Vars3};
1978munge_expr({record_field,Line,ExprL,ExprR}, Vars) ->
1979    {MungedExprR, Vars2} = munge_expr(ExprR, Vars),
1980    {{record_field,Line,ExprL,MungedExprR}, Vars2};
1981munge_expr({map,Line,Fields}, Vars) ->
1982    %% EEP 43
1983    {MungedFields, Vars2} = munge_exprs(Fields, Vars, []),
1984    {{map,Line,MungedFields}, Vars2};
1985munge_expr({map,Line,Arg,Fields}, Vars) ->
1986    %% EEP 43
1987    {MungedArg, Vars2} = munge_expr(Arg, Vars),
1988    {MungedFields, Vars3} = munge_exprs(Fields, Vars2, []),
1989    {{map,Line,MungedArg,MungedFields}, Vars3};
1990munge_expr({map_field_assoc,Line,Name,Value}, Vars) ->
1991    %% EEP 43
1992    {MungedName, Vars2} = munge_expr(Name, Vars),
1993    {MungedValue, Vars3} = munge_expr(Value, Vars2),
1994    {{map_field_assoc,Line,MungedName,MungedValue}, Vars3};
1995munge_expr({map_field_exact,Line,Name,Value}, Vars) ->
1996    %% EEP 43
1997    {MungedName, Vars2} = munge_expr(Name, Vars),
1998    {MungedValue, Vars3} = munge_expr(Value, Vars2),
1999    {{map_field_exact,Line,MungedName,MungedValue}, Vars3};
2000munge_expr({cons,Line,ExprH,ExprT}, Vars) ->
2001    {MungedExprH, Vars2} = munge_expr(ExprH, Vars),
2002    {MungedExprT, Vars3} = munge_expr(ExprT, Vars2),
2003    {{cons,Line,MungedExprH,MungedExprT}, Vars3};
2004munge_expr({op,Line,Op,ExprL,ExprR}, Vars) ->
2005    {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
2006    {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
2007    {{op,Line,Op,MungedExprL,MungedExprR}, Vars3};
2008munge_expr({op,Line,Op,Expr}, Vars) ->
2009    {MungedExpr, Vars2} = munge_expr(Expr, Vars),
2010    {{op,Line,Op,MungedExpr}, Vars2};
2011munge_expr({'catch',Line,Expr}, Vars) ->
2012    {MungedExpr, Vars2} = munge_expr(Expr, Vars),
2013    {{'catch',Line,MungedExpr}, Vars2};
2014munge_expr({call,Line1,{remote,Line2,ExprM,ExprF},Exprs},
2015	   Vars) ->
2016    {MungedExprM, Vars2} = munge_expr(ExprM, Vars),
2017    {MungedExprF, Vars3} = munge_expr(ExprF, Vars2),
2018    {MungedExprs, Vars4} = munge_exprs(Exprs, Vars3, []),
2019    {{call,Line1,{remote,Line2,MungedExprM,MungedExprF},MungedExprs}, Vars4};
2020munge_expr({call,Line,Expr,Exprs}, Vars) ->
2021    {MungedExpr, Vars2} = munge_expr(Expr, Vars),
2022    {MungedExprs, Vars3} = munge_exprs(Exprs, Vars2, []),
2023    {{call,Line,MungedExpr,MungedExprs}, Vars3};
2024munge_expr({lc,Line,Expr,Qs}, Vars) ->
2025    {MungedExpr, Vars2} = munge_expr(?BLOCK1(Expr), Vars),
2026    {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2),
2027    {{lc,Line,MungedExpr,MungedQs}, Vars3};
2028munge_expr({bc,Line,Expr,Qs}, Vars) ->
2029    {MungedExpr,Vars2} = munge_expr(?BLOCK1(Expr), Vars),
2030    {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2),
2031    {{bc,Line,MungedExpr,MungedQs}, Vars3};
2032munge_expr({block,Line,Body}, Vars) ->
2033    {MungedBody, Vars2} = munge_body(Body, Vars),
2034    {{block,Line,MungedBody}, Vars2};
2035munge_expr({'if',Line,Clauses}, Vars) ->
2036    {MungedClauses,Vars2} = munge_clauses(Clauses, Vars),
2037    {{'if',Line,MungedClauses}, Vars2};
2038munge_expr({'case',Line,Expr,Clauses}, Vars) ->
2039    {MungedExpr,Vars2} = munge_expr(Expr, Vars),
2040    {MungedClauses,Vars3} = munge_clauses(Clauses, Vars2),
2041    {{'case',Line,MungedExpr,MungedClauses}, Vars3};
2042munge_expr({'receive',Line,Clauses}, Vars) ->
2043    {MungedClauses,Vars2} = munge_clauses(Clauses, Vars),
2044    {{'receive',Line,MungedClauses}, Vars2};
2045munge_expr({'receive',Line,Clauses,Expr,Body}, Vars) ->
2046    {MungedExpr, Vars1} = munge_expr(Expr, Vars),
2047    {MungedClauses,Vars2} = munge_clauses(Clauses, Vars1),
2048    {MungedBody,Vars3} =
2049        munge_body(Body, Vars2#vars{lines = Vars1#vars.lines}),
2050    Vars4 = Vars3#vars{lines = Vars2#vars.lines ++ new_bumps(Vars3, Vars2)},
2051    {{'receive',Line,MungedClauses,MungedExpr,MungedBody}, Vars4};
2052munge_expr({'try',Line,Body,Clauses,CatchClauses,After}, Vars) ->
2053    {MungedBody, Vars1} = munge_body(Body, Vars),
2054    {MungedClauses, Vars2} = munge_clauses(Clauses, Vars1),
2055    {MungedCatchClauses, Vars3} = munge_clauses(CatchClauses, Vars2),
2056    {MungedAfter, Vars4} = munge_body(After, Vars3),
2057    {{'try',Line,MungedBody,MungedClauses,MungedCatchClauses,MungedAfter},
2058     Vars4};
2059munge_expr({'fun',Line,{clauses,Clauses}}, Vars) ->
2060    {MungedClauses,Vars2}=munge_clauses(Clauses, Vars),
2061    {{'fun',Line,{clauses,MungedClauses}}, Vars2};
2062munge_expr({named_fun,Line,Name,Clauses}, Vars) ->
2063    {MungedClauses,Vars2}=munge_clauses(Clauses, Vars),
2064    {{named_fun,Line,Name,MungedClauses}, Vars2};
2065munge_expr({bin,Line,BinElements}, Vars) ->
2066    {MungedBinElements,Vars2} = munge_exprs(BinElements, Vars, []),
2067    {{bin,Line,MungedBinElements}, Vars2};
2068munge_expr({bin_element,Line,Value,Size,TypeSpecifierList}, Vars) ->
2069    {MungedValue,Vars2} = munge_expr(Value, Vars),
2070    {MungedSize,Vars3} = munge_expr(Size, Vars2),
2071    {{bin_element,Line,MungedValue,MungedSize,TypeSpecifierList},Vars3};
2072munge_expr(Form, Vars) ->
2073    {Form, Vars}.
2074
2075munge_exprs([Expr|Exprs], Vars, MungedExprs) when Vars#vars.is_guard=:=true,
2076						  is_list(Expr) ->
2077    {MungedExpr, _Vars} = munge_exprs(Expr, Vars, []),
2078    munge_exprs(Exprs, Vars, [MungedExpr|MungedExprs]);
2079munge_exprs([Expr|Exprs], Vars, MungedExprs) ->
2080    {MungedExpr, Vars2} = munge_expr(Expr, Vars),
2081    munge_exprs(Exprs, Vars2, [MungedExpr|MungedExprs]);
2082munge_exprs([], Vars, MungedExprs) ->
2083    {lists:reverse(MungedExprs), Vars}.
2084
2085%% Every qualifier is decorated with a counter.
2086munge_qualifiers(Qualifiers, Vars) ->
2087    munge_qs(Qualifiers, Vars, []).
2088
2089munge_qs([{generate,Line,Pattern,Expr}|Qs], Vars, MQs) ->
2090    L = element(2, Expr),
2091    {MungedExpr, Vars2} = munge_expr(Expr, Vars),
2092    munge_qs1(Qs, L, {generate,Line,Pattern,MungedExpr}, Vars, Vars2, MQs);
2093munge_qs([{b_generate,Line,Pattern,Expr}|Qs], Vars, MQs) ->
2094    L = element(2, Expr),
2095    {MExpr, Vars2} = munge_expr(Expr, Vars),
2096    munge_qs1(Qs, L, {b_generate,Line,Pattern,MExpr}, Vars, Vars2, MQs);
2097munge_qs([Expr|Qs], Vars, MQs) ->
2098    L = element(2, Expr),
2099    {MungedExpr, Vars2} = munge_expr(Expr, Vars),
2100    munge_qs1(Qs, L, MungedExpr, Vars, Vars2, MQs);
2101munge_qs([], Vars, MQs) ->
2102    {lists:reverse(MQs), Vars}.
2103
2104munge_qs1(Qs, Line, NQ, Vars, Vars2, MQs) ->
2105    case new_bumps(Vars2, Vars) of
2106        [_] ->
2107            munge_qs(Qs, Vars2, [NQ | MQs]);
2108        _ ->
2109            {MungedTrue, Vars3} = munge_expr(?BLOCK({atom,Line,true}), Vars2),
2110            munge_qs(Qs, Vars3, [NQ, MungedTrue | MQs])
2111    end.
2112
2113new_bumps(#vars{lines = New}, #vars{lines = Old}) ->
2114    subtract(New, Old).
2115
2116subtract(L1, L2) ->
2117    [E || E <- L1, not lists:member(E, L2)].
2118
2119common_elems(L1, L2) ->
2120    [E || E <- L1, lists:member(E, L2)].
2121
2122%%%--Analysis------------------------------------------------------------
2123
2124%% Collect data for all modules
2125collect(Nodes) ->
2126    %% local node
2127    AllClauses = ets:tab2list(?COVER_CLAUSE_TABLE),
2128    Mon1 = spawn_monitor(fun() -> pmap(fun move_modules/1,AllClauses) end),
2129
2130    %% remote nodes
2131    Mon2 = spawn_monitor(fun() -> remote_collect('_',Nodes,false) end),
2132    get_downs([Mon1,Mon2]).
2133
2134%% Collect data for a list of modules
2135collect(Modules,Nodes) ->
2136    MS = [{{'$1','_'},[{'==','$1',M}],['$_']} || M <- Modules],
2137    Clauses = ets:select(?COVER_CLAUSE_TABLE,MS),
2138    Mon1 = spawn_monitor(fun() -> pmap(fun move_modules/1,Clauses) end),
2139
2140    %% remote nodes
2141    Mon2 = spawn_monitor(fun() -> remote_collect('_',Nodes,false) end),
2142    get_downs([Mon1,Mon2]).
2143
2144%% Collect data for one module
2145collect(Module,Clauses,Nodes) ->
2146    %% local node
2147    move_modules({Module,Clauses}),
2148
2149    %% remote nodes
2150    remote_collect([Module],Nodes,false).
2151
2152
2153%% When analysing, the data from the local ?COVER_TABLE is moved to the
2154%% ?COLLECTION_TABLE. Resetting data in ?COVER_TABLE
2155move_modules({Module,Clauses}) ->
2156    ets:insert(?COLLECTION_CLAUSE_TABLE,{Module,Clauses}),
2157    Pattern = {#bump{module=Module, _='_'}, '_'},
2158    MatchSpec = [{Pattern,[],['$_']}],
2159    Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE),
2160    do_move_module(Match).
2161
2162do_move_module({Bumps,Continuation}) ->
2163    lists:foreach(fun({Key,Val}) ->
2164			  ets:insert(?COVER_TABLE, {Key,0}),
2165			  insert_in_collection_table(Key,Val)
2166		  end,
2167		  Bumps),
2168    do_move_module(ets:select(Continuation));
2169do_move_module('$end_of_table') ->
2170    ok.
2171
2172%% Given a .beam file, find the .erl file. Look first in same directory as
2173%% the .beam file, then in ../src, then in compile info.
2174find_source(Module, File0) ->
2175    try
2176        Root = filename:rootname(File0, ".beam"),
2177        Root == File0 andalso throw(File0),  %% not .beam
2178        %% Look for .erl in pwd.
2179        File = Root ++ ".erl",
2180        throw_file(File),
2181        %% Not in pwd: look in ../src.
2182        BeamDir = filename:dirname(File),
2183        Base = filename:basename(File),
2184        throw_file(filename:join([BeamDir, "..", "src", Base])),
2185        %% Not in ../src: look for source path in compile info, but
2186        %% first look relative the beam directory.
2187        Info =
2188            try lists:keyfind(source, 1, Module:module_info(compile))
2189            catch error:undef ->
2190                    %% The module might have been imported
2191                    %% and the beam not available
2192                    throw({beam, File0})
2193            end,
2194        false == Info andalso throw({beam, File0}),  %% stripped
2195        {source, SrcFile} = Info,
2196        throw_file(splice(BeamDir, SrcFile)),  %% below ../src
2197        throw_file(SrcFile),                   %% or absolute
2198        %% No success means that source is either not under ../src or
2199        %% its relative path differs from that of compile info. (For
2200        %% example, compiled under src/x but installed under src/y.)
2201        %% An option to specify an arbitrary source path explicitly is
2202        %% probably a better solution than either more heuristics or a
2203        %% potentially slow filesystem search.
2204        {beam, File0}
2205    catch
2206        Path -> Path
2207    end.
2208
2209throw_file(Path) ->
2210    false /= Path andalso filelib:is_file(Path) andalso throw(Path).
2211
2212%% Splice the tail of a source path, starting from the last "src"
2213%% component, onto the parent of a beam directory, or return false if
2214%% no "src" component is found.
2215%%
2216%% Eg. splice("/path/to/app-1.0/ebin", "/compiled/path/to/app/src/x/y.erl")
2217%%        --> "/path/to/app-1.0/ebin/../src/x/y.erl"
2218%%
2219%% This handles the case of source in subdirectories of ../src with
2220%% beams that have moved since compilation.
2221%%
2222splice(BeamDir, SrcFile) ->
2223    case lists:splitwith(fun(C) -> C /= "src" end, revsplit(SrcFile)) of
2224        {T, [_|_]} ->  %% found src component
2225            filename:join([BeamDir, "..", "src" | lists:reverse(T)]);
2226        {_, []} ->     %% or not
2227            false
2228    end.
2229
2230revsplit(Path) ->
2231    lists:reverse(filename:split(Path)).
2232
2233analyse_list(Modules, Analysis, Level, State) ->
2234    {LoadedMF, ImportedMF, Error} = are_loaded(Modules, State, [], [], []),
2235    Loaded = [M || {M,_} <- LoadedMF],
2236    Imported = [M || {M,_} <- ImportedMF],
2237    collect(Loaded, State#main_state.nodes),
2238    MS = [{{'$1','_'},[{'==','$1',M}],['$_']} || M <- Loaded ++ Imported],
2239    AllClauses = ets:select(?COLLECTION_CLAUSE_TABLE,MS),
2240    Fun = fun({Module,Clauses}) ->
2241		  do_analyse(Module, Analysis, Level, Clauses)
2242	  end,
2243    {result, lists:flatten(pmap(Fun, AllClauses)), Error}.
2244
2245analyse_all(Analysis, Level, State) ->
2246    collect(State#main_state.nodes),
2247    AllClauses = ets:tab2list(?COLLECTION_CLAUSE_TABLE),
2248    Fun = fun({Module,Clauses}) ->
2249		  do_analyse(Module, Analysis, Level, Clauses)
2250	  end,
2251    {result, lists:flatten(pmap(Fun, AllClauses)), []}.
2252
2253do_parallel_analysis(Module, Analysis, Level, Loaded, From, State) ->
2254    analyse_info(Module,State#main_state.imported),
2255    C = case Loaded of
2256	    {loaded, _File} ->
2257		[{Module,Clauses}] =
2258		    ets:lookup(?COVER_CLAUSE_TABLE,Module),
2259		collect(Module,Clauses,State#main_state.nodes),
2260		Clauses;
2261	    _ ->
2262		[{Module,Clauses}] =
2263		    ets:lookup(?COLLECTION_CLAUSE_TABLE,Module),
2264		Clauses
2265	end,
2266    R = do_analyse(Module, Analysis, Level, C),
2267    reply(From, {ok,R}).
2268
2269%% do_analyse(Module, Analysis, Level, Clauses)-> {ok,Answer} | {error,Error}
2270%%   Clauses = [{Module,Function,Arity,Clause,Lines}]
2271do_analyse(Module, Analysis, line, _Clauses) ->
2272    Pattern = {#bump{module=Module},'_'},
2273    Bumps = ets:match_object(?COLLECTION_TABLE, Pattern),
2274    Fun = case Analysis of
2275	      coverage ->
2276		  fun({#bump{line=L}, 0}) ->
2277			  {{Module,L}, {0,1}};
2278		     ({#bump{line=L}, _N}) ->
2279			  {{Module,L}, {1,0}}
2280		  end;
2281	      calls ->
2282		  fun({#bump{line=L}, N}) ->
2283			  {{Module,L}, N}
2284		  end
2285	  end,
2286    lists:keysort(1, lists:map(Fun, Bumps));
2287do_analyse(Module, Analysis, clause, _Clauses) ->
2288    Pattern = {#bump{module=Module},'_'},
2289    Bumps = lists:keysort(1,ets:match_object(?COLLECTION_TABLE, Pattern)),
2290    analyse_clause(Analysis,Bumps);
2291do_analyse(Module, Analysis, function, Clauses) ->
2292    ClauseResult = do_analyse(Module, Analysis, clause, Clauses),
2293    merge_clauses(ClauseResult, merge_fun(Analysis));
2294do_analyse(Module, Analysis, module, Clauses) ->
2295    FunctionResult = do_analyse(Module, Analysis, function, Clauses),
2296    Result = merge_functions(FunctionResult, merge_fun(Analysis)),
2297    {Module,Result}.
2298
2299analyse_clause(_,[]) ->
2300    [];
2301analyse_clause(coverage,
2302	       [{#bump{module=M,function=F,arity=A,clause=C},_}|_]=Bumps) ->
2303    analyse_clause_cov(Bumps,{M,F,A,C},0,0,[]);
2304analyse_clause(calls,Bumps) ->
2305    analyse_clause_calls(Bumps,{x,x,x,x},[]).
2306
2307analyse_clause_cov([{#bump{module=M,function=F,arity=A,clause=C},N}|Bumps],
2308		   {M,F,A,C}=Clause,Ls,NotCov,Acc) ->
2309    analyse_clause_cov(Bumps,Clause,Ls+1,if N==0->NotCov+1; true->NotCov end,Acc);
2310analyse_clause_cov([{#bump{module=M1,function=F1,arity=A1,clause=C1},_}|_]=Bumps,
2311		    Clause,Ls,NotCov,Acc) ->
2312    analyse_clause_cov(Bumps,{M1,F1,A1,C1},0,0,[{Clause,{Ls-NotCov,NotCov}}|Acc]);
2313analyse_clause_cov([],Clause,Ls,NotCov,Acc) ->
2314    lists:reverse(Acc,[{Clause,{Ls-NotCov,NotCov}}]).
2315
2316analyse_clause_calls([{#bump{module=M,function=F,arity=A,clause=C},_}|Bumps],
2317		     {M,F,A,C}=Clause,Acc) ->
2318    analyse_clause_calls(Bumps,Clause,Acc);
2319analyse_clause_calls([{#bump{module=M1,function=F1,arity=A1,clause=C1},N}|Bumps],
2320		     _Clause,Acc) ->
2321    analyse_clause_calls(Bumps,{M1,F1,A1,C1},[{{M1,F1,A1,C1},N}|Acc]);
2322analyse_clause_calls([],_Clause,Acc) ->
2323    lists:reverse(Acc).
2324
2325merge_fun(coverage) ->
2326    fun({Cov1,NotCov1}, {Cov2,NotCov2}) ->
2327	    {Cov1+Cov2, NotCov1+NotCov2}
2328    end;
2329merge_fun(calls) ->
2330    fun(Calls1, Calls2) ->
2331	    Calls1+Calls2
2332    end.
2333
2334merge_clauses(Clauses, MFun) -> merge_clauses(Clauses, MFun, []).
2335merge_clauses([{{M,F,A,_C1},R1},{{M,F,A,C2},R2}|Clauses], MFun, Result) ->
2336    merge_clauses([{{M,F,A,C2},MFun(R1,R2)}|Clauses], MFun, Result);
2337merge_clauses([{{M,F,A,_C},R}|Clauses], MFun, Result) ->
2338    merge_clauses(Clauses, MFun, [{{M,F,A},R}|Result]);
2339merge_clauses([], _Fun, Result) ->
2340    lists:reverse(Result).
2341
2342merge_functions([{_MFA,R}|Functions], MFun) ->
2343    merge_functions(Functions, MFun, R);
2344merge_functions([],_MFun) ->         % There are no clauses.
2345    {0,0}.                           % No function can be covered or notcov.
2346
2347merge_functions([{_MFA,R}|Functions], MFun, Result) ->
2348    merge_functions(Functions, MFun, MFun(Result, R));
2349merge_functions([], _MFun, Result) ->
2350    Result.
2351
2352analyse_list_to_file(Modules, Opts, State) ->
2353    {LoadedMF, ImportedMF, Error} = are_loaded(Modules, State, [], [], []),
2354    collect([M || {M,_} <- LoadedMF], State#main_state.nodes),
2355    OutDir = proplists:get_value(outdir,Opts),
2356    HTML = lists:member(html,Opts),
2357    Fun = fun({Module,File}) ->
2358		  OutFile = outfilename(OutDir,Module,HTML),
2359		  do_analyse_to_file(Module,File,OutFile,HTML,State)
2360	  end,
2361    {Ok,Error1} = split_ok_error(pmap(Fun, LoadedMF++ImportedMF),[],[]),
2362    {result,Ok,Error ++ Error1}.
2363
2364analyse_all_to_file(Opts, State) ->
2365    collect(State#main_state.nodes),
2366    AllModules = get_all_modules(State),
2367    OutDir = proplists:get_value(outdir,Opts),
2368    HTML = lists:member(html,Opts),
2369    Fun = fun({Module,File}) ->
2370		  OutFile = outfilename(OutDir,Module,HTML),
2371		  do_analyse_to_file(Module,File,OutFile,HTML,State)
2372	  end,
2373    {Ok,Error} = split_ok_error(pmap(Fun, AllModules),[],[]),
2374    {result,Ok,Error}.
2375
2376get_all_modules(State) ->
2377    get_all_modules(State#main_state.compiled ++ State#main_state.imported,[]).
2378get_all_modules([{Module,File}|Rest],Acc) ->
2379    get_all_modules(Rest,[{Module,File}|Acc]);
2380get_all_modules([{Module,File,_}|Rest],Acc) ->
2381    case lists:keymember(Module,1,Acc) of
2382	true -> get_all_modules(Rest,Acc);
2383	false -> get_all_modules(Rest,[{Module,File}|Acc])
2384    end;
2385get_all_modules([],Acc) ->
2386    Acc.
2387
2388split_ok_error([{ok,R}|Result],Ok,Error) ->
2389    split_ok_error(Result,[R|Ok],Error);
2390split_ok_error([{error,R}|Result],Ok,Error) ->
2391    split_ok_error(Result,Ok,[R|Error]);
2392split_ok_error([],Ok,Error) ->
2393    {Ok,Error}.
2394
2395do_parallel_analysis_to_file(Module, Opts, Loaded, From, State) ->
2396    File = case Loaded of
2397	       {loaded, File0} ->
2398		   [{Module,Clauses}] =
2399		       ets:lookup(?COVER_CLAUSE_TABLE,Module),
2400		   collect(Module, Clauses,
2401			   State#main_state.nodes),
2402		   File0;
2403	       {imported, File0, _} ->
2404		   File0
2405	   end,
2406    HTML = lists:member(html,Opts),
2407    OutFile =
2408	case proplists:get_value(outfile,Opts) of
2409	    undefined ->
2410		outfilename(proplists:get_value(outdir,Opts),Module,HTML);
2411	    F ->
2412		F
2413	end,
2414    reply(From, do_analyse_to_file(Module,File,OutFile,HTML,State)).
2415
2416do_analyse_to_file(Module,File,OutFile,HTML,State) ->
2417    case find_source(Module, File) of
2418	{beam,_BeamFile} ->
2419	    {error,{no_source_code_found,Module}};
2420	ErlFile ->
2421	    analyse_info(Module,State#main_state.imported),
2422	    do_analyse_to_file1(Module,OutFile,ErlFile,HTML)
2423    end.
2424
2425%% do_analyse_to_file1(Module,OutFile,ErlFile) -> {ok,OutFile} | {error,Error}
2426%%   Module = atom()
2427%%   OutFile = ErlFile = string()
2428do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
2429    case file:open(ErlFile, [read,raw,read_ahead]) of
2430	{ok, InFd} ->
2431	    case file:open(OutFile, [write,raw,delayed_write]) of
2432		{ok, OutFd} ->
2433                    Enc = encoding(ErlFile),
2434		    if HTML ->
2435                            Header = create_header(OutFile, Enc),
2436                            H1Bin = unicode:characters_to_binary(Header,Enc,Enc),
2437                            ok = file:write(OutFd,H1Bin);
2438		       true -> ok
2439		    end,
2440
2441		    %% Write some initial information to the output file
2442		    {{Y,Mo,D},{H,Mi,S}} = calendar:local_time(),
2443                   Timestamp =
2444                       io_lib:format("~p-~s-~s at ~s:~s:~s",
2445                                     [Y,
2446                                      string:pad(integer_to_list(Mo), 2, leading, $0),
2447                                      string:pad(integer_to_list(D),  2, leading, $0),
2448                                      string:pad(integer_to_list(H),  2, leading, $0),
2449                                      string:pad(integer_to_list(Mi), 2, leading, $0),
2450                                      string:pad(integer_to_list(S),  2, leading, $0)]),
2451
2452                   OutFileInfo =
2453                       if HTML ->
2454                            create_footer(ErlFile, Timestamp);
2455                          true ->
2456                            ["File generated from ",ErlFile," by COVER ",
2457                             Timestamp, "\n\n",
2458                             "**************************************"
2459                             "**************************************"
2460                             "\n\n"]
2461                          end,
2462
2463                   H2Bin = unicode:characters_to_binary(OutFileInfo,Enc,Enc),
2464                   ok = file:write(OutFd, H2Bin),
2465
2466		    Pattern = {#bump{module=Module,line='$1',_='_'},'$2'},
2467		    MS = [{Pattern,[{is_integer,'$1'},{'>','$1',0}],[{{'$1','$2'}}]}],
2468                    CovLines0 =
2469                        lists:keysort(1, ets:select(?COLLECTION_TABLE, MS)),
2470                    CovLines = merge_dup_lines(CovLines0),
2471		    print_lines(Module, CovLines, InFd, OutFd, 1, HTML),
2472
2473		    if HTML ->
2474                           ok = file:write(OutFd, close_html());
2475		       true -> ok
2476		    end,
2477
2478		    ok = file:close(OutFd),
2479		    ok = file:close(InFd),
2480
2481		    {ok, OutFile};
2482
2483		{error, Reason} ->
2484		    {error, {file, OutFile, Reason}}
2485	    end;
2486
2487	{error, Reason} ->
2488	    {error, {file, ErlFile, Reason}}
2489    end.
2490
2491merge_dup_lines(CovLines) ->
2492    merge_dup_lines(CovLines, []).
2493merge_dup_lines([{L, N}|T], [{L, NAcc}|TAcc]) ->
2494    merge_dup_lines(T, [{L, NAcc + N}|TAcc]);
2495merge_dup_lines([{L, N}|T], Acc) ->
2496    merge_dup_lines(T, [{L, N}|Acc]);
2497merge_dup_lines([], Acc) ->
2498    lists:reverse(Acc).
2499
2500print_lines(Module, CovLines, InFd, OutFd, L, HTML) ->
2501    case file:read_line(InFd) of
2502	eof ->
2503	    ignore;
2504	{ok,RawLine} ->
2505	    Line = escape_lt_and_gt(RawLine,HTML),
2506	    case CovLines of
2507	       [{L,N}|CovLines1] ->
2508                    if N=:=0, HTML=:=true ->
2509                           MissedLine = table_row("miss", Line, L, N),
2510                           ok = file:write(OutFd, MissedLine);
2511                       HTML=:=true ->
2512                           HitLine = table_row("hit", Line, L, N),
2513                           ok = file:write(OutFd, HitLine);
2514                       N < 1000000 ->
2515                           Str = string:pad(integer_to_list(N), 6, leading, $\s),
2516                           ok = file:write(OutFd, [Str,fill1(),Line]);
2517                       N < 10000000 ->
2518                           Str = integer_to_list(N),
2519                           ok = file:write(OutFd, [Str,fill2(),Line]);
2520                       true ->
2521                           Str = integer_to_list(N),
2522                           ok = file:write(OutFd, [Str,fill3(),Line])
2523                    end,
2524		    print_lines(Module, CovLines1, InFd, OutFd, L+1, HTML);
2525		_ ->                            %Including comment lines
2526        NonCoveredContent =
2527                    if HTML -> table_row(Line, L);
2528                    true -> [tab(),Line]
2529                    end,
2530		    ok = file:write(OutFd, NonCoveredContent),
2531		    print_lines(Module, CovLines, InFd, OutFd, L+1, HTML)
2532	    end
2533    end.
2534
2535tab() ->  "        |  ".
2536fill1() ->      "..|  ".
2537fill2() ->       ".|  ".
2538fill3() ->        "|  ".
2539
2540%% HTML sections
2541create_header(OutFile, Enc) ->
2542    ["<!doctype html>\n"
2543    "<html>\n"
2544    "<head>\n"
2545    "<meta charset=\"",html_encoding(Enc),"\">\n"
2546    "<title>",OutFile,"</title>\n"
2547    "<style>"] ++
2548    read_stylesheet() ++
2549    ["</style>\n",
2550    "</head>\n"
2551    "<body>\n"
2552    "<h1><code>",OutFile,"</code></h1>\n"].
2553
2554create_footer(ErlFile, Timestamp) ->
2555    ["<footer><p>File generated from <code>",ErlFile,
2556    "</code> by <a href=\"http://erlang.org/doc/man/cover.html\">cover</a> at ",
2557    Timestamp,"</p></footer>\n<table>\n<tbody>\n"].
2558
2559close_html() ->
2560    ["</tbody>\n",
2561     "<thead>\n",
2562     "<tr>\n",
2563     "<th>Line</th>\n",
2564     "<th>Hits</th>\n",
2565     "<th>Source</th>\n",
2566     "</tr>\n",
2567     "</thead>\n",
2568     "</table>\n",
2569     "</body>\n"
2570     "</html>\n"].
2571
2572table_row(CssClass, Line, L, N) ->
2573    ["<tr class=\"",CssClass,"\">\n", table_data(Line, L, N)].
2574table_row(Line, L) ->
2575    ["<tr>\n", table_data(Line, L, "")].
2576
2577table_data(Line, L, N) ->
2578   LineNoNL = Line -- "\n",
2579   ["<td class=\"line\" id=\"L",integer_to_list(L),"\">",
2580    "<a href=\"#L",integer_to_list(L),"\">",
2581    integer_to_list(L),
2582    "</a></td>\n",
2583   "<td class=\"hits\">",maybe_integer_to_list(N),"</td>\n",
2584   "<td class=\"source\"><code>",LineNoNL,"</code></td>\n</tr>\n"].
2585
2586maybe_integer_to_list(0) -> "<pre style=\"display: inline;\">:-(</pre>";
2587maybe_integer_to_list(N) when is_integer(N) -> integer_to_list(N);
2588maybe_integer_to_list(_) -> "".
2589
2590read_stylesheet() ->
2591    PrivDir = code:priv_dir(?TOOLS_APP),
2592    {ok, Css} = file:read_file(filename:join(PrivDir, ?STYLESHEET)),
2593    [Css].
2594
2595%%%--Export--------------------------------------------------------------
2596do_export(Module, OutFile, From, State) ->
2597    case file:open(OutFile,[write,binary,raw,delayed_write]) of
2598	{ok,Fd} ->
2599	    Reply =
2600		case Module of
2601		    '_' ->
2602			export_info(State#main_state.imported),
2603			collect(State#main_state.nodes),
2604			do_export_table(State#main_state.compiled,
2605					State#main_state.imported,
2606					Fd);
2607		    _ ->
2608			export_info(Module,State#main_state.imported),
2609			try is_loaded(Module, State) of
2610			    {loaded, File} ->
2611				[{Module,Clauses}] =
2612				    ets:lookup(?COVER_CLAUSE_TABLE,Module),
2613				collect(Module, Clauses,
2614					State#main_state.nodes),
2615				do_export_table([{Module,File}],[],Fd);
2616			    {imported, File, ImportFiles} ->
2617				%% don't know if I should allow this -
2618				%% export a module which is only imported
2619				Imported = [{Module,File,ImportFiles}],
2620				do_export_table([],Imported,Fd)
2621			catch throw:_ ->
2622				{error,{not_cover_compiled,Module}}
2623			end
2624		end,
2625	    ok = file:close(Fd),
2626	    reply(From, Reply);
2627	{error,Reason} ->
2628	    reply(From, {error, {cant_open_file,OutFile,Reason}})
2629
2630    end.
2631
2632do_export_table(Compiled, Imported, Fd) ->
2633    ModList = merge(Imported,Compiled),
2634    write_module_data(ModList,Fd).
2635
2636merge([{Module,File,_ImportFiles}|Imported],ModuleList) ->
2637    case lists:keymember(Module,1,ModuleList) of
2638	true ->
2639	    merge(Imported,ModuleList);
2640	false ->
2641	    merge(Imported,[{Module,File}|ModuleList])
2642    end;
2643merge([],ModuleList) ->
2644    ModuleList.
2645
2646write_module_data([{Module,File}|ModList],Fd) ->
2647    write({file,Module,File},Fd),
2648    [Clauses] = ets:lookup(?COLLECTION_CLAUSE_TABLE,Module),
2649    write(Clauses,Fd),
2650    ModuleData = ets:match_object(?COLLECTION_TABLE,{#bump{module=Module},'_'}),
2651    do_write_module_data(ModuleData,Fd),
2652    write_module_data(ModList,Fd);
2653write_module_data([],_Fd) ->
2654    ok.
2655
2656do_write_module_data([H|T],Fd) ->
2657    write(H,Fd),
2658    do_write_module_data(T,Fd);
2659do_write_module_data([],_Fd) ->
2660    ok.
2661
2662write(Element,Fd) ->
2663    Bin = term_to_binary(Element,[compressed]),
2664    case byte_size(Bin) of
2665	Size when Size > 255 ->
2666	    SizeBin = term_to_binary({'$size',Size}),
2667	    ok = file:write(Fd, <<(byte_size(SizeBin)):8,SizeBin/binary,Bin/binary>>);
2668	Size ->
2669	    ok = file:write(Fd,<<Size:8,Bin/binary>>)
2670    end,
2671    ok.
2672
2673%%%--Import--------------------------------------------------------------
2674do_import_to_table(Fd,ImportFile,Imported) ->
2675    do_import_to_table(Fd,ImportFile,Imported,[]).
2676do_import_to_table(Fd,ImportFile,Imported,DontImport) ->
2677    case get_term(Fd) of
2678	{file,Module,File} ->
2679	    case add_imported(Module, File, ImportFile, Imported) of
2680		{ok,NewImported} ->
2681		    do_import_to_table(Fd,ImportFile,NewImported,DontImport);
2682		dont_import ->
2683		    do_import_to_table(Fd,ImportFile,Imported,
2684				       [Module|DontImport])
2685	    end;
2686	{Key=#bump{module=Module},Val} ->
2687	    case lists:member(Module,DontImport) of
2688		false ->
2689		    insert_in_collection_table(Key,Val);
2690		true ->
2691		    ok
2692	    end,
2693	    do_import_to_table(Fd,ImportFile,Imported,DontImport);
2694	{Module,Clauses} ->
2695	    case lists:member(Module,DontImport) of
2696		false ->
2697		    ets:insert(?COLLECTION_CLAUSE_TABLE,{Module,Clauses});
2698		true ->
2699			    ok
2700	    end,
2701	    do_import_to_table(Fd,ImportFile,Imported,DontImport);
2702	eof ->
2703	    Imported
2704    end.
2705
2706
2707get_term(Fd) ->
2708    case file:read(Fd,1) of
2709	{ok,<<Size1:8>>} ->
2710	    {ok,Bin1} = file:read(Fd,Size1),
2711	    case binary_to_term(Bin1) of
2712		{'$size',Size2} ->
2713		    {ok,Bin2} = file:read(Fd,Size2),
2714		    binary_to_term(Bin2);
2715		Term ->
2716		    Term
2717	    end;
2718	eof ->
2719	    eof
2720    end.
2721
2722%%%--Reset---------------------------------------------------------------
2723
2724%% Reset main node and all remote nodes
2725do_reset_main_node(Module,Nodes) ->
2726    do_reset(Module),
2727    do_reset_collection_table(Module),
2728    remote_reset(Module,Nodes).
2729
2730do_reset_collection_table(Module) ->
2731    ets:delete(?COLLECTION_CLAUSE_TABLE,Module),
2732    ets:match_delete(?COLLECTION_TABLE, {#bump{module=Module},'_'}).
2733
2734%% do_reset(Module) -> ok
2735%% The reset is done on ?CHUNK_SIZE number of bumps to avoid building
2736%% long lists in the case of very large modules
2737do_reset(Module) ->
2738    Pattern = {#bump{module=Module, _='_'}, '$1'},
2739    MatchSpec = [{Pattern,[{'=/=','$1',0}],['$_']}],
2740    Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE),
2741    do_reset2(Match).
2742
2743do_reset2({Bumps,Continuation}) ->
2744    lists:foreach(fun({Bump,_N}) ->
2745			  ets:insert(?COVER_TABLE, {Bump,0})
2746		  end,
2747		  Bumps),
2748    do_reset2(ets:select(Continuation));
2749do_reset2('$end_of_table') ->
2750    ok.
2751
2752do_clear(Module) ->
2753    ets:match_delete(?COVER_CLAUSE_TABLE, {Module,'_'}),
2754    ets:match_delete(?COVER_TABLE, {#bump{module=Module},'_'}),
2755    case lists:member(?COLLECTION_TABLE, ets:all()) of
2756	true ->
2757	    %% We're on the main node
2758	    ets:match_delete(?COLLECTION_TABLE, {#bump{module=Module},'_'});
2759	false ->
2760	    ok
2761    end.
2762
2763not_loaded(Module, unloaded, State) ->
2764    do_clear(Module),
2765    remote_unload(State#main_state.nodes,[Module]),
2766    Compiled = update_compiled([Module],
2767			       State#main_state.compiled),
2768    State#main_state{ compiled = Compiled };
2769not_loaded(_Module,_Else, State) ->
2770    State.
2771
2772
2773
2774%%%--Div-----------------------------------------------------------------
2775
2776escape_lt_and_gt(Rawline,HTML) when HTML =/= true ->
2777    Rawline;
2778escape_lt_and_gt(Rawline,_HTML) ->
2779    escape_lt_and_gt1(Rawline,[]).
2780
2781escape_lt_and_gt1([$<|T],Acc) ->
2782    escape_lt_and_gt1(T,[$;,$t,$l,$&|Acc]);
2783escape_lt_and_gt1([$>|T],Acc) ->
2784    escape_lt_and_gt1(T,[$;,$t,$g,$&|Acc]);
2785escape_lt_and_gt1([$&|T],Acc) ->
2786    escape_lt_and_gt1(T,[$;,$p,$m,$a,$&|Acc]);
2787escape_lt_and_gt1([],Acc) ->
2788    lists:reverse(Acc);
2789escape_lt_and_gt1([H|T],Acc) ->
2790    escape_lt_and_gt1(T,[H|Acc]).
2791
2792%%%--Internal functions for parallelization------------------------------
2793pmap(Fun,List) ->
2794    NTot = length(List),
2795    NProcs = erlang:system_info(schedulers) * 2,
2796    NPerProc = (NTot div NProcs) + 1,
2797    Mons = pmap_spawn(Fun,NPerProc,List,[]),
2798    pmap_collect(Mons,[]).
2799
2800pmap_spawn(_,_,[],Mons) ->
2801    Mons;
2802pmap_spawn(Fun,NPerProc,List,Mons) ->
2803    {L1,L2} = if length(List)>=NPerProc -> lists:split(NPerProc,List);
2804		 true -> {List,[]} % last chunk
2805	      end,
2806    Mon =
2807	spawn_monitor(
2808	  fun() ->
2809		  exit({pmap_done,lists:map(Fun,L1)})
2810	  end),
2811    pmap_spawn(Fun,NPerProc,L2,[Mon|Mons]).
2812
2813pmap_collect([],Acc) ->
2814    lists:append(Acc);
2815pmap_collect(Mons,Acc) ->
2816    receive
2817	{'DOWN', Ref, process, Pid, {pmap_done,Result}} ->
2818	    pmap_collect(lists:delete({Pid,Ref},Mons),[Result|Acc]);
2819	{'DOWN', Ref, process, Pid, Reason} = Down ->
2820	    case lists:member({Pid,Ref},Mons) of
2821		true ->
2822		    %% Something went really wrong - don't hang!
2823		    exit(Reason);
2824		false ->
2825		    %% This should be handled somewhere else
2826		    self() ! Down,
2827		    pmap_collect(Mons,Acc)
2828	    end
2829    end.
2830
2831%%%-----------------------------------------------------------------
2832%%% Decide which encoding to use when analyzing to file.
2833%%% The target file contains the file path, so if either the file name
2834%%% encoding or the encoding of the source file is utf8, then we need
2835%%% to use utf8.
2836encoding(File) ->
2837    case file:native_name_encoding() of
2838        latin1 ->
2839            case epp:read_encoding(File) of
2840                none ->
2841                    epp:default_encoding();
2842                E ->
2843                    E
2844            end;
2845        utf8 ->
2846            utf8
2847    end.
2848
2849html_encoding(latin1) ->
2850    "iso-8859-1";
2851html_encoding(utf8) ->
2852    "utf-8".
2853