1
%% -*- erlang-indent-level: 2 -*-
5
%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
7
%% The contents of this file are subject to the Erlang Public License,
8
%% Version 1.1, (the "License"); you may not use this file except in
9
%% compliance with the License. You should have received a copy of the
10
%% Erlang Public License along with this software. If not, it can be
11
%% retrieved online at http://www.erlang.org/.
13
%% Software distributed under the License is distributed on an "AS IS"
14
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
15
%% the License for the specific language governing rights and limitations
25
-type func_info() :: {non_neg_integer(), atom(), arity()}.
26
-type inc_file_info() :: {string(), func_info()}.
28
-record(tmpAcc, {file :: string(),
30
funcAcc=[] :: [func_info()],
31
incFuncAcc=[] :: [inc_file_info()],
32
dialyzerObj=[] :: [{mfa(), {_, _}}]}).
34
-include("typer.hrl").
36
-spec collect(#typer_analysis{}) -> #typer_analysis{}.
40
try get_dialyzer_plt(Analysis) of
42
dialyzer_plt:merge_plts([Analysis#typer_analysis.trust_plt, DialyzerPlt])
44
throw:{dialyzer_error,_Reason} ->
45
typer:error("Dialyzer's PLT is missing or is not up-to-date; please (re)create it")
47
NewAnalysis = lists:foldl(fun collect_one_file_info/2,
48
Analysis#typer_analysis{trust_plt = NewPlt},
49
Analysis#typer_analysis.ana_files),
50
%% Process Remote Types
51
TmpCServer = NewAnalysis#typer_analysis.code_server,
54
NewRecords = dialyzer_codeserver:get_temp_records(TmpCServer),
55
OldRecords = dialyzer_plt:get_types(NewPlt),
56
MergedRecords = dialyzer_utils:merge_records(NewRecords, OldRecords),
57
%% io:format("Merged Records ~p",[MergedRecords]),
58
TmpCServer1 = dialyzer_codeserver:set_temp_records(MergedRecords, TmpCServer),
59
TmpCServer2 = dialyzer_utils:process_record_remote_types(TmpCServer1),
60
dialyzer_contracts:process_contract_remote_types(TmpCServer2)
62
throw:{error, ErrorMsg} ->
65
NewAnalysis#typer_analysis{code_server = NewCServer}.
67
collect_one_file_info(File, Analysis) ->
68
Ds = [{d,Name,Val} || {Name,Val} <- Analysis#typer_analysis.macros],
69
%% Current directory should also be included in "Includes".
70
Includes = [filename:dirname(File)|Analysis#typer_analysis.includes],
71
Is = [{i,Dir} || Dir <- Includes],
72
Options = dialyzer_utils:src_compiler_opts() ++ Is ++ Ds,
73
case dialyzer_utils:get_abstract_code_from_src(File, Options) of
75
%% io:format("File=~p\n,Options=~p\n,Error=~p\n", [File,Options,Reason]),
76
typer:compile_error(Reason);
78
case dialyzer_utils:get_core_from_abstract_code(AbstractCode, Options) of
79
error -> typer:compile_error(["Could not get core erlang for "++File]);
81
case dialyzer_utils:get_record_and_type_info(AbstractCode) of
82
{error, Reason} -> typer:compile_error([Reason]);
84
Mod = list_to_atom(filename:basename(File, ".erl")),
85
case dialyzer_utils:get_spec_info(Mod, AbstractCode, Records) of
86
{error, Reason} -> typer:compile_error([Reason]);
88
analyze_core_tree(Core, Records, SpecInfo, Analysis, File)
94
analyze_core_tree(Core, Records, SpecInfo, Analysis, File) ->
95
Module = list_to_atom(filename:basename(File, ".erl")),
96
TmpTree = cerl:from_records(Core),
97
CS1 = Analysis#typer_analysis.code_server,
98
NextLabel = dialyzer_codeserver:get_next_core_label(CS1),
99
{Tree, NewLabel} = cerl_trees:label(TmpTree, NextLabel),
100
CS2 = dialyzer_codeserver:insert(Module, Tree, CS1),
101
CS3 = dialyzer_codeserver:set_next_core_label(NewLabel, CS2),
102
CS4 = dialyzer_codeserver:store_temp_records(Module, Records, CS3),
103
CS5 = dialyzer_codeserver:store_temp_contracts(Module, SpecInfo, CS4),
104
Ex_Funcs = [{0,F,A} || {_,_,{F,A}} <- cerl:module_exports(Tree)],
105
TmpCG = Analysis#typer_analysis.callgraph,
106
CG = dialyzer_callgraph:scan_core_tree(Tree, TmpCG),
107
Fun = fun analyze_one_function/2,
108
All_Defs = cerl:module_defs(Tree),
109
Acc = lists:foldl(Fun, #tmpAcc{file=File, module=Module}, All_Defs),
110
Exported_FuncMap = typer_map:insert({File, Ex_Funcs},
111
Analysis#typer_analysis.ex_func),
112
%% NOTE: we must sort all functions in the file which
113
%% originate from this file by *numerical order* of lineNo
114
Sorted_Functions = lists:keysort(1, Acc#tmpAcc.funcAcc),
115
FuncMap = typer_map:insert({File, Sorted_Functions},
116
Analysis#typer_analysis.func),
117
%% NOTE: However we do not need to sort functions
118
%% which are imported from included files.
119
IncFuncMap = typer_map:insert({File, Acc#tmpAcc.incFuncAcc},
120
Analysis#typer_analysis.inc_func),
121
Final_Files = Analysis#typer_analysis.final_files ++ [{File, Module}],
122
RecordMap = typer_map:insert({File, Records}, Analysis#typer_analysis.record),
123
Analysis#typer_analysis{final_files=Final_Files,
126
ex_func=Exported_FuncMap,
131
analyze_one_function({Var, FunBody} = Function, Acc) ->
132
F = cerl:fname_id(Var),
133
A = cerl:fname_arity(Var),
134
TmpDialyzerObj = {{Acc#tmpAcc.module, F, A}, Function},
135
NewDialyzerObj = Acc#tmpAcc.dialyzerObj ++ [TmpDialyzerObj],
136
[_, LineNo, {file, FileName}] = cerl:get_ann(FunBody),
137
BaseName = filename:basename(FileName),
138
FuncInfo = {LineNo, F, A},
139
OriginalName = Acc#tmpAcc.file,
140
{FuncAcc, IncFuncAcc} =
141
case (FileName =:= OriginalName) orelse (BaseName =:= OriginalName) of
142
true -> %% Coming from original file
143
%% io:format("Added function ~p\n", [{LineNo, F, A}]),
144
{Acc#tmpAcc.funcAcc ++ [FuncInfo], Acc#tmpAcc.incFuncAcc};
146
%% Coming from other sourses, including:
147
%% -- .yrl (yecc-generated file)
148
%% -- yeccpre.hrl (yecc-generated file)
150
{Acc#tmpAcc.funcAcc, Acc#tmpAcc.incFuncAcc ++ [{FileName, FuncInfo}]}
152
Acc#tmpAcc{funcAcc = FuncAcc,
153
incFuncAcc = IncFuncAcc,
154
dialyzerObj = NewDialyzerObj}.
156
get_dialyzer_plt(#typer_analysis{plt = PltFile0}) ->
158
case PltFile0 =:= none of
159
true -> dialyzer_plt:get_default_plt();
162
dialyzer_plt:from_file(PltFile).