1
1
%% -*- erlang-indent-level: 2 -*-
2
2
%%-------------------------------------------------------------------
5
%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
5
%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
7
7
%% The contents of this file are subject to the Erlang Public License,
8
8
%% Version 1.1, (the "License"); you may not use this file except in
9
9
%% compliance with the License. You should have received a copy of the
10
10
%% Erlang Public License along with this software. If not, it can be
11
11
%% retrieved online at http://www.erlang.org/.
13
13
%% Software distributed under the License is distributed on an "AS IS"
14
14
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
15
15
%% the License for the specific language governing rights and limitations
16
16
%% under the License.
38
42
{backend_pid :: pid(),
39
43
erlang_mode = false :: boolean(),
40
44
external_calls = [] :: [mfa()],
45
external_types = [] :: [mfa()],
41
46
legal_warnings = ordsets:new() :: [dial_warn_tag()],
42
47
mod_deps = dict:new() :: dict(),
43
48
output = standard_io :: io:device(),
44
output_format = formatted :: 'raw' | 'formatted',
49
output_format = formatted :: format(),
50
filename_opt = basename :: fopt(),
45
51
output_plt = none :: 'none' | file:filename(),
46
52
plt_info = none :: 'none' | dialyzer_plt:plt_info(),
47
53
report_mode = normal :: rep_mode(),
48
54
return_status= ?RET_NOTHING_SUSPICIOUS :: dial_ret(),
49
stored_warnings = [] :: [dial_warning()]
55
stored_warnings = [] :: [dial_warning()],
56
unknown_behaviours = [] :: [dialyzer_behaviours:behaviour()]
52
59
%%--------------------------------------------------------------------
75
82
init_opts_for_build(Opts) ->
76
83
case Opts#options.output_plt =:= none of
78
case Opts#options.init_plt of
79
none -> Opts#options{init_plt = none, output_plt = get_default_plt()};
80
Plt -> Opts#options{init_plt = none, output_plt = Plt}
85
case Opts#options.init_plts of
86
[] -> Opts#options{output_plt = get_default_output_plt()};
87
[Plt] -> Opts#options{init_plts = [], output_plt = Plt};
89
Msg = io_lib:format("Could not build multiple PLT files: ~s\n",
82
false -> Opts#options{init_plt = none}
93
false -> Opts#options{init_plts = []}
85
96
%%--------------------------------------------------------------------
92
103
init_opts_for_add(Opts) ->
93
104
case Opts#options.output_plt =:= none of
95
case Opts#options.init_plt of
96
none -> Opts#options{output_plt = get_default_plt(),
97
init_plt = get_default_plt()};
98
Plt -> Opts#options{output_plt = Plt}
106
case Opts#options.init_plts of
107
[] -> Opts#options{output_plt = get_default_output_plt(),
108
init_plts = get_default_init_plt()};
109
[Plt] -> Opts#options{output_plt = Plt};
111
Msg = io_lib:format("Could not add to multiple PLT files: ~s\n",
112
[format_plts(Plts)]),
101
case Opts#options.init_plt =:= none of
102
true -> Opts#options{init_plt = get_default_plt()};
116
case Opts#options.init_plts =:= [] of
117
true -> Opts#options{init_plts = get_default_init_plt()};
107
122
%%--------------------------------------------------------------------
124
check_plt(#options{init_plts = []} = Opts) ->
110
125
Opts1 = init_opts_for_check(Opts),
112
plt_common(Opts1, [], []).
127
plt_common(Opts1, [], []);
128
check_plt(#options{init_plts = Plts} = Opts) ->
129
check_plt_aux(Plts, Opts).
131
check_plt_aux([_] = Plt, Opts) ->
132
Opts1 = Opts#options{init_plts = Plt},
133
Opts2 = init_opts_for_check(Opts1),
135
plt_common(Opts2, [], []);
136
check_plt_aux([Plt|Plts], Opts) ->
137
Opts1 = Opts#options{init_plts = [Plt]},
138
Opts2 = init_opts_for_check(Opts1),
140
plt_common(Opts2, [], []),
141
check_plt_aux(Plts, Opts).
114
143
init_opts_for_check(Opts) ->
116
case Opts#options.init_plt of
117
none -> get_default_plt();
145
case Opts#options.init_plts of
146
[]-> get_default_init_plt();
149
[OutputPlt] = InitPlt,
120
150
Opts#options{files = [],
122
152
analysis_type = plt_check,
124
154
from = byte_code,
126
156
include_dirs = [],
157
output_plt = OutputPlt,
128
158
use_contracts = true
138
168
init_opts_for_remove(Opts) ->
139
169
case Opts#options.output_plt =:= none of
141
case Opts#options.init_plt of
142
none -> Opts#options{output_plt = get_default_plt(),
143
init_plt = get_default_plt()};
144
Plt -> Opts#options{output_plt = Plt}
171
case Opts#options.init_plts of
172
[] -> Opts#options{output_plt = get_default_output_plt(),
173
init_plts = get_default_init_plt()};
174
[Plt] -> Opts#options{output_plt = Plt};
176
Msg = io_lib:format("Could not remove from multiple PLT files: ~s\n",
177
[format_plts(Plts)]),
147
case Opts#options.init_plt =:= none of
148
true -> Opts#options{init_plt = get_default_plt()};
181
case Opts#options.init_plts =:= [] of
182
true -> Opts#options{init_plts = get_default_init_plt()};
153
187
%%--------------------------------------------------------------------
155
plt_common(Opts, RemoveFiles, AddFiles) ->
189
plt_common(#options{init_plts = [InitPlt]} = Opts, RemoveFiles, AddFiles) ->
156
190
case check_plt(Opts, RemoveFiles, AddFiles) of
192
case Opts#options.output_plt of
195
{ok, Binary} = file:read_file(InitPlt),
196
file:write_file(OutPlt, Binary)
158
198
case Opts#options.report_mode of
160
200
_ -> io:put_chars(" yes\n")
168
208
report_failed_plt_check(Opts, DiffMd5),
169
209
{AnalFiles, RemovedMods, ModDeps1} =
170
210
expand_dependent_modules(Md5, DiffMd5, ModDeps),
171
Plt = clean_plt(Opts#options.init_plt, RemovedMods),
211
Plt = clean_plt(InitPlt, RemovedMods),
172
212
case AnalFiles =:= [] of
174
214
%% Only removed stuff. Just write the PLT.
181
221
{error, no_such_file} ->
182
222
Msg = io_lib:format("Could not find the PLT: ~s\n~s",
183
[Opts#options.init_plt, default_plt_error_msg()]),
223
[InitPlt, default_plt_error_msg()]),
185
225
{error, not_valid} ->
186
226
Msg = io_lib:format("The file: ~s is not a valid PLT file\n~s",
187
[Opts#options.init_plt, default_plt_error_msg()]),
227
[InitPlt, default_plt_error_msg()]),
189
229
{error, read_error} ->
190
230
Msg = io_lib:format("Could not read the PLT: ~s\n~s",
191
[Opts#options.init_plt, default_plt_error_msg()]),
231
[InitPlt, default_plt_error_msg()]),
193
233
{error, {no_file_to_remove, F}} ->
194
234
Msg = io_lib:format("Could not remove the file ~s from the PLT: ~s\n",
195
[F, Opts#options.init_plt]),
213
253
%%--------------------------------------------------------------------
215
check_plt(Opts, RemoveFiles, AddFiles) ->
216
Plt = Opts#options.init_plt,
255
check_plt(#options{init_plts = [Plt]} = Opts, RemoveFiles, AddFiles) ->
217
256
case dialyzer_plt:check_plt(Plt, RemoveFiles, AddFiles) of
218
257
{old_version, _MD5} = OldVersion ->
219
258
report_old_version(Opts),
229
268
%%--------------------------------------------------------------------
231
report_check(#options{report_mode = ReportMode, init_plt = InitPlt}) ->
270
report_check(#options{report_mode = ReportMode, init_plts = [InitPlt]}) ->
232
271
case ReportMode of
235
274
io:format(" Checking whether the PLT ~s is up-to-date...", [InitPlt])
238
report_old_version(#options{report_mode = ReportMode, init_plt = InitPlt}) ->
277
report_old_version(#options{report_mode = ReportMode, init_plts = [InitPlt]}) ->
239
278
case ReportMode of
315
356
%%--------------------------------------------------------------------
358
get_default_init_plt() ->
359
[dialyzer_plt:get_default_plt()].
361
get_default_output_plt() ->
318
362
dialyzer_plt:get_default_plt().
320
364
%%--------------------------------------------------------------------
366
format_plts([Plt]) -> Plt;
367
format_plts([Plt|Plts]) ->
368
Plt ++ ", " ++ format_plts(Plts).
370
%%--------------------------------------------------------------------
322
372
do_analysis(Options) ->
323
373
Files = get_files_from_opts(Options),
324
case Options#options.init_plt of
325
none -> do_analysis(Files, Options, dialyzer_plt:new(), none);
326
File -> do_analysis(Files, Options, dialyzer_plt:from_file(File), none)
374
case Options#options.init_plts of
375
[] -> do_analysis(Files, Options, dialyzer_plt:new(), none);
377
Plts = [dialyzer_plt:from_file(F) || F <- PltFiles],
378
Plt = dialyzer_plt:merge_plts_or_report_conflicts(PltFiles, Plts),
379
do_analysis(Files, Options, Plt, none)
329
382
do_analysis(Files, Options, Plt, PltInfo) ->
440
493
-spec hipe_compile([file:filename()], #options{}) -> 'ok'.
442
495
hipe_compile(Files, #options{erlang_mode = ErlangMode} = Options) ->
443
case (length(Files) < ?MIN_FILES_FOR_NATIVE_COMPILE) orelse ErlangMode of
496
NoNative = (get(dialyzer_options_native) =:= false),
497
FewFiles = (length(Files) < ?MIN_FILES_FOR_NATIVE_COMPILE),
498
case NoNative orelse FewFiles orelse ErlangMode of
446
501
case erlang:system_info(hipe_architecture) of
528
585
{BackendPid, warnings, Warnings} ->
529
586
NewState = store_warnings(State, Warnings),
530
587
cl_loop(NewState, LogCache);
588
{BackendPid, unknown_behaviours, Behaviours} ->
589
NewState = store_unknown_behaviours(State, Behaviours),
590
cl_loop(NewState, LogCache);
531
591
{BackendPid, done, NewPlt, _NewDocPlt} ->
532
592
return_value(State, NewPlt);
533
593
{BackendPid, ext_calls, ExtCalls} ->
534
594
cl_loop(State#cl_state{external_calls = ExtCalls}, LogCache);
595
{BackendPid, ext_types, ExtTypes} ->
596
cl_loop(State#cl_state{external_types = ExtTypes}, LogCache);
535
597
{BackendPid, mod_deps, ModDeps} ->
536
598
NewState = State#cl_state{mod_deps = ModDeps},
537
599
cl_loop(NewState, LogCache);
637
706
do_print_ext_calls(_, [], _) ->
709
print_ext_types(#cl_state{report_mode = quiet}) ->
711
print_ext_types(#cl_state{output = Output,
712
external_calls = Calls,
713
external_types = Types,
714
stored_warnings = Warnings,
715
output_format = Format}) ->
719
case Warnings =:= [] andalso Calls =:= [] of
720
true -> io:nl(Output); %% Need to do a newline first
725
io:put_chars(Output, "Unknown types:\n"),
726
do_print_ext_types(Output, Types, " ");
728
io:put_chars(Output, "%% Unknown types:\n"),
729
do_print_ext_types(Output, Types, "%% ")
733
do_print_ext_types(Output, [{M,F,A}|T], Before) ->
734
io:format(Output, "~s~p:~p/~p\n", [Before,M,F,A]),
735
do_print_ext_types(Output, T, Before);
736
do_print_ext_types(_, [], _) ->
739
%%print_unknown_behaviours(#cl_state{report_mode = quiet}) ->
741
print_unknown_behaviours(#cl_state{output = Output,
742
external_calls = Calls,
743
external_types = Types,
744
stored_warnings = Warnings,
745
unknown_behaviours = DupBehaviours,
746
legal_warnings = LegalWarnings,
747
output_format = Format}) ->
748
case ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings)
749
andalso DupBehaviours =/= [] of
752
Behaviours = lists:usort(DupBehaviours),
753
case Warnings =:= [] andalso Calls =:= [] andalso Types =:= [] of
754
true -> io:nl(Output); %% Need to do a newline first
759
io:put_chars(Output, "Unknown behaviours (behaviour_info(callbacks)"
760
" does not return any specs):\n"),
761
do_print_unknown_behaviours(Output, Behaviours, " ");
763
io:put_chars(Output, "%% Unknown behaviours:\n"),
764
do_print_unknown_behaviours(Output, Behaviours, "%% ")
768
do_print_unknown_behaviours(Output, [B|T], Before) ->
769
io:format(Output, "~s~p\n", [Before,B]),
770
do_print_unknown_behaviours(Output, T, Before);
771
do_print_unknown_behaviours(_, [], _) ->
640
774
print_warnings(#cl_state{stored_warnings = []}) ->
642
776
print_warnings(#cl_state{output = Output,
643
777
output_format = Format,
644
779
stored_warnings = Warnings}) ->
645
780
PrWarnings = process_warnings(Warnings),
646
781
case PrWarnings of