aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/typer/src/typer.erl39
-rw-r--r--lib/typer/src/typer.hrl27
-rw-r--r--lib/typer/src/typer_info.erl48
-rw-r--r--lib/typer/src/typer_options.erl43
-rw-r--r--lib/typer/src/typer_preprocess.erl72
5 files changed, 134 insertions, 95 deletions
diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl
index e19614f911..206ce8e797 100644
--- a/lib/typer/src/typer.erl
+++ b/lib/typer/src/typer.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -26,11 +26,12 @@
-module(typer).
-%% Avoid warning for local function error/1 clashing with autoimported BIF.
--compile({no_auto_import,[error/1]}).
-export([start/0]).
-export([error/1, compile_error/1]). % for error reporting
+%% Avoid warning for local function error/1 clashing with autoimported BIF.
+-compile({no_auto_import, [error/1]}).
+
-include("typer.hrl").
%%--------------------------------------------------------------------
@@ -143,7 +144,13 @@ remove_external(CallGraph, PLT) ->
case get_external(Ext, PLT) of
[] -> ok;
Externals ->
- msg(io_lib:format(" Unknown functions: ~p\n", [lists:usort(Externals)]))
+ msg(io_lib:format(" Unknown functions: ~p\n", [lists:usort(Externals)])),
+ ExtTypes = rcv_ext_types(),
+ case ExtTypes of
+ [] -> ok;
+ _ ->
+ msg(io_lib:format(" Unknown types: ~p\n", [ExtTypes]))
+ end
end,
StrippedCG.
@@ -197,3 +204,19 @@ msg(Msg) ->
end.
%%--------------------------------------------------------------------
+%% Handle messages.
+%%--------------------------------------------------------------------
+
+rcv_ext_types() ->
+ Self = self(),
+ Self ! {Self, done},
+ rcv_ext_types(Self, []).
+
+rcv_ext_types(Self, ExtTypes) ->
+ receive
+ {Self, ext_types, ExtType} ->
+ rcv_ext_types(Self, [ExtType|ExtTypes]);
+ {Self, done} -> lists:usort(ExtTypes)
+ end.
+
+%%--------------------------------------------------------------------
diff --git a/lib/typer/src/typer.hrl b/lib/typer/src/typer.hrl
index c331dd82db..2e4ec4f894 100644
--- a/lib/typer/src/typer.hrl
+++ b/lib/typer/src/typer.hrl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -28,18 +28,18 @@
-record(typer_analysis,
{mode :: mode(),
macros = [] :: [{atom(), _}], % {macro_name, value}
- includes = [] :: [string()],
+ includes = [] :: [file:filename()],
%% Esp for Dialyzer
%% ----------------------
code_server = dialyzer_codeserver:new():: dialyzer_codeserver:codeserver(),
callgraph = dialyzer_callgraph:new() :: dialyzer_callgraph:callgraph(),
- ana_files = [] :: [string()], % absolute filenames
- plt = none :: 'none' | string(),
+ ana_files = [] :: [file:filename()], % absolute filenames
+ plt = none :: 'none' | file:filename(),
%% Esp for TypEr
%% ----------------------
- t_files = [] :: [string()],
+ t_files = [] :: [file:filename()],
%% For choosing between contracts or comments
contracts = true :: boolean(),
@@ -47,7 +47,7 @@
%% Any file in 'final_files' is compilable.
%% And we need to keep it as {FileName,ModuleName}
%% in case filename does NOT match with moduleName
- final_files = [] :: [{string(), atom()}],
+ final_files = [] :: [{file:filename(), module()}],
ex_func = typer_map:new() :: dict(),
record = typer_map:new() :: dict(),
@@ -58,7 +58,6 @@
inc_func = typer_map:new() :: dict(),
trust_plt = dialyzer_plt:new() :: dialyzer_plt:plt()}).
--record(args,
- {analyze = [] :: [string()],
- analyzed_dir_r = [] :: [string()],
- trust = [] :: [string()]}).
+-record(args, {files = [] :: [file:filename()],
+ files_r = [] :: [file:filename()],
+ trusted = [] :: [file:filename()]}).
diff --git a/lib/typer/src/typer_info.erl b/lib/typer/src/typer_info.erl
index ea25fa6f68..615d2b4796 100644
--- a/lib/typer/src/typer_info.erl
+++ b/lib/typer/src/typer_info.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -52,12 +52,18 @@ collect(Analysis) ->
NewCServer =
try
NewRecords = dialyzer_codeserver:get_temp_records(TmpCServer),
+ NewExpTypes = dialyzer_codeserver:get_temp_exported_types(TmpCServer),
OldRecords = dialyzer_plt:get_types(NewPlt),
+ OldExpTypes = dialyzer_plt:get_exported_types(NewPlt),
MergedRecords = dialyzer_utils:merge_records(NewRecords, OldRecords),
+ MergedExpTypes = sets:union(NewExpTypes, OldExpTypes),
%% io:format("Merged Records ~p",[MergedRecords]),
TmpCServer1 = dialyzer_codeserver:set_temp_records(MergedRecords, TmpCServer),
- TmpCServer2 = dialyzer_utils:process_record_remote_types(TmpCServer1),
- dialyzer_contracts:process_contract_remote_types(TmpCServer2)
+ TmpCServer2 =
+ dialyzer_codeserver:insert_temp_exported_types(MergedExpTypes,
+ TmpCServer1),
+ TmpCServer3 = dialyzer_utils:process_record_remote_types(TmpCServer2),
+ dialyzer_contracts:process_contract_remote_types(TmpCServer3)
catch
throw:{error, ErrorMsg} ->
typer:error(ErrorMsg)
@@ -80,18 +86,20 @@ collect_one_file_info(File, Analysis) ->
{ok, Core} ->
case dialyzer_utils:get_record_and_type_info(AbstractCode) of
{error, Reason} -> typer:compile_error([Reason]);
- {ok, Records} ->
+ {ok, Records} ->
Mod = list_to_atom(filename:basename(File, ".erl")),
case dialyzer_utils:get_spec_info(Mod, AbstractCode, Records) of
{error, Reason} -> typer:compile_error([Reason]);
- {ok, SpecInfo} ->
- analyze_core_tree(Core, Records, SpecInfo, Analysis, File)
+ {ok, SpecInfo} ->
+ ExpTypes = get_exported_types_from_core(Core),
+ analyze_core_tree(Core, Records, SpecInfo, ExpTypes,
+ Analysis, File)
end
end
end
end.
-analyze_core_tree(Core, Records, SpecInfo, Analysis, File) ->
+analyze_core_tree(Core, Records, SpecInfo, ExpTypes, Analysis, File) ->
Module = list_to_atom(filename:basename(File, ".erl")),
TmpTree = cerl:from_records(Core),
CS1 = Analysis#typer_analysis.code_server,
@@ -101,6 +109,9 @@ analyze_core_tree(Core, Records, SpecInfo, Analysis, File) ->
CS3 = dialyzer_codeserver:set_next_core_label(NewLabel, CS2),
CS4 = dialyzer_codeserver:store_temp_records(Module, Records, CS3),
CS5 = dialyzer_codeserver:store_temp_contracts(Module, SpecInfo, CS4),
+ OldExpTypes = dialyzer_codeserver:get_temp_exported_types(CS5),
+ MergedExpTypes = sets:union(ExpTypes, OldExpTypes),
+ CS6 = dialyzer_codeserver:insert_temp_exported_types(MergedExpTypes, CS5),
Ex_Funcs = [{0,F,A} || {_,_,{F,A}} <- cerl:module_exports(Tree)],
TmpCG = Analysis#typer_analysis.callgraph,
CG = dialyzer_callgraph:scan_core_tree(Tree, TmpCG),
@@ -122,7 +133,7 @@ analyze_core_tree(Core, Records, SpecInfo, Analysis, File) ->
RecordMap = typer_map:insert({File, Records}, Analysis#typer_analysis.record),
Analysis#typer_analysis{final_files=Final_Files,
callgraph=CG,
- code_server=CS5,
+ code_server=CS6,
ex_func=Exported_FuncMap,
inc_func=IncFuncMap,
record=RecordMap,
@@ -160,3 +171,16 @@ get_dialyzer_plt(#typer_analysis{plt = PltFile0}) ->
false -> PltFile0
end,
dialyzer_plt:from_file(PltFile).
+
+
+%% Exported Types
+
+get_exported_types_from_core(Core) ->
+ Attrs = cerl:module_attrs(Core),
+ ExpTypes1 = [cerl:concrete(L2) || {L1, L2} <- Attrs,
+ cerl:is_literal(L1),
+ cerl:is_literal(L2),
+ cerl:concrete(L1) =:= 'export_type'],
+ ExpTypes2 = lists:flatten(ExpTypes1),
+ M = cerl:atom_val(cerl:module_name(Core)),
+ sets:from_list([{M, F, A} || {F, A} <- ExpTypes2]).
diff --git a/lib/typer/src/typer_options.erl b/lib/typer/src/typer_options.erl
index 1e53b1b305..f149c937c7 100644
--- a/lib/typer/src/typer_options.erl
+++ b/lib/typer/src/typer_options.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%===========================================================================
@@ -39,7 +39,7 @@
process() ->
ArgList = init:get_plain_arguments(),
- %% io:format("Args is ~p\n",[Args]),
+ %% io:format("Args is ~p\n", [ArgList]),
{Args, Analysis} = analyze_args(ArgList, #args{}, #typer_analysis{}),
%% if the mode has not been set, set it to the default mode (show)
{Args, case Analysis#typer_analysis.mode of
@@ -73,11 +73,10 @@ cl(["-D"++Def|Opts]) ->
case Def of
"" -> typer:error("no variable name specified after -D");
_ ->
- L = re:split(Def, "=", [{return, list}]),
- DefPair = process_def_list(L),
+ DefPair = process_def_list(re:split(Def, "=", [{return, list}])),
{{def, DefPair}, Opts}
end;
-cl(["-I",Dir|Opts]) -> {{inc,Dir}, Opts};
+cl(["-I",Dir|Opts]) -> {{inc, Dir}, Opts};
cl(["-I"++Dir|Opts]) ->
case Dir of
"" -> typer:error("no include directory specified after -I");
@@ -87,15 +86,15 @@ cl(["-T"|Opts]) ->
{Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
case Files of
[] -> typer:error("no file or directory specified after -T");
- [_|_] -> {{trust, Files}, RestOpts}
+ [_|_] -> {{trusted, Files}, RestOpts}
end;
cl(["-r"|Opts]) ->
{Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
- {{a_dir_r, Files}, RestOpts};
+ {{files_r, Files}, RestOpts};
cl(["-"++H|_]) -> typer:error("unknown option -"++H);
cl(Opts) ->
- {Args, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
- {{analyze, Args}, RestOpts}.
+ {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
+ {{files, Files}, RestOpts}.
process_def_list(L) ->
case L of
@@ -108,15 +107,15 @@ process_def_list(L) ->
end.
%% Get information about files that the user trusts and wants to analyze
-analyze_result({analyze, Val}, Args, Analysis) ->
- NewVal = Args#args.analyze ++ Val,
- {Args#args{analyze = NewVal}, Analysis};
-analyze_result({a_dir_r, Val}, Args, Analysis) ->
- NewVal = Args#args.analyzed_dir_r ++ Val,
- {Args#args{analyzed_dir_r = NewVal}, Analysis};
-analyze_result({trust, Val}, Args, Analysis) ->
- NewVal = Args#args.trust ++ Val,
- {Args#args{trust = NewVal}, Analysis};
+analyze_result({files, Val}, Args, Analysis) ->
+ NewVal = Args#args.files ++ Val,
+ {Args#args{files = NewVal}, Analysis};
+analyze_result({files_r, Val}, Args, Analysis) ->
+ NewVal = Args#args.files_r ++ Val,
+ {Args#args{files_r = NewVal}, Analysis};
+analyze_result({trusted, Val}, Args, Analysis) ->
+ NewVal = Args#args.trusted ++ Val,
+ {Args#args{trusted = NewVal}, Analysis};
analyze_result(comments, Args, Analysis) ->
{Args, Analysis#typer_analysis{contracts = false}};
%% Get useful information for actual analysis
diff --git a/lib/typer/src/typer_preprocess.erl b/lib/typer/src/typer_preprocess.erl
index 7cb0b9932b..27660e849e 100644
--- a/lib/typer/src/typer_preprocess.erl
+++ b/lib/typer/src/typer_preprocess.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -26,19 +26,17 @@
%%----------------------------------------------------------------------------
--spec get_all_files(#args{}, 'analysis' | 'trust') -> [string()].
+-spec get_all_files(#args{}, 'analysis' | 'trust') -> [file:filename()].
-get_all_files(Args, analysis) ->
- case internal_get_all_files(Args#args.analyze,
- Args#args.analyzed_dir_r,
- fun test_erl_file_exclude_ann/1) of
+get_all_files(#args{files=Fs,files_r=Ds}, analysis) ->
+ case files_and_dirs(Fs, Ds, fun test_erl_file_exclude_ann/1) of
[] -> typer:error("no file(s) to analyze");
AllFiles -> AllFiles
end;
-get_all_files(Args, trust) ->
- internal_get_all_files(Args#args.trust, [], fun test_erl_file/1).
+get_all_files(#args{trusted=Fs}, trust) ->
+ files_and_dirs(Fs, [], fun test_erl_file/1).
--spec test_erl_file_exclude_ann(string()) -> boolean().
+-spec test_erl_file_exclude_ann(file:filename()) -> boolean().
test_erl_file_exclude_ann(File) ->
case filename:extension(File) of
@@ -50,57 +48,53 @@ test_erl_file_exclude_ann(File) ->
_ -> false
end.
--spec test_erl_file(string()) -> boolean().
+-spec test_erl_file(file:filename()) -> boolean().
test_erl_file(File) ->
filename:extension(File) =:= ".erl".
--spec internal_get_all_files([string()], [string()],
- fun((string()) -> boolean())) -> [string()].
+-spec files_and_dirs([file:filename()], [file:filename()],
+ fun((file:filename()) -> boolean())) -> [file:filename()].
-internal_get_all_files(File_Dir, Dir_R, Fun) ->
+files_and_dirs(File_Dir, Dir_R, Fun) ->
All_File_1 = process_file_and_dir(File_Dir, Fun),
- All_File_2 = process_dir_recursively(Dir_R, Fun),
+ All_File_2 = process_dir_rec(Dir_R, Fun),
remove_dup(All_File_1 ++ All_File_2).
--spec process_file_and_dir([string()],
- fun((string()) -> boolean())) -> [string()].
+-spec process_file_and_dir([file:filename()],
+ fun((file:filename()) -> boolean())) -> [file:filename()].
process_file_and_dir(File_Dir, TestFun) ->
Fun =
fun (Elem, Acc) ->
case filelib:is_regular(Elem) of
true -> process_file(Elem, TestFun, Acc);
- false -> check_dir(Elem, non_recursive, Acc, TestFun)
+ false -> check_dir(Elem, false, Acc, TestFun)
end
end,
lists:foldl(Fun, [], File_Dir).
--spec process_dir_recursively([string()],
- fun((string()) -> boolean())) -> [string()].
+-spec process_dir_rec([file:filename()],
+ fun((file:filename()) -> boolean())) -> [file:filename()].
-process_dir_recursively(Dirs, TestFun) ->
- Fun = fun (Dir, Acc) ->
- check_dir(Dir, recursive, Acc, TestFun)
- end,
+process_dir_rec(Dirs, TestFun) ->
+ Fun = fun (Dir, Acc) -> check_dir(Dir, true, Acc, TestFun) end,
lists:foldl(Fun, [], Dirs).
--spec check_dir(string(),
- 'non_recursive' | 'recursive',
- [string()],
- fun((string()) -> boolean())) -> [string()].
+-spec check_dir(file:filename(), boolean(), [file:filename()],
+ fun((file:filename()) -> boolean())) -> [file:filename()].
-check_dir(Dir, Mode, Acc, Fun) ->
+check_dir(Dir, Recursive, Acc, Fun) ->
case file:list_dir(Dir) of
{ok, Files} ->
{TmpDirs, TmpFiles} = split_dirs_and_files(Files, Dir),
- case Mode of
- non_recursive ->
+ case Recursive of
+ false ->
FinalFiles = process_file_and_dir(TmpFiles, Fun),
Acc ++ FinalFiles;
- recursive ->
+ true ->
TmpAcc1 = process_file_and_dir(TmpFiles, Fun),
- TmpAcc2 = process_dir_recursively(TmpDirs, Fun),
+ TmpAcc2 = process_dir_rec(TmpDirs, Fun),
Acc ++ TmpAcc1 ++ TmpAcc2
end;
{error, eacces} ->
@@ -112,7 +106,7 @@ check_dir(Dir, Mode, Acc, Fun) ->
end.
%% Same order as the input list
--spec process_file(string(), fun((string()) -> boolean()), string()) -> [string()].
+-spec process_file(file:filename(), fun((file:filename()) -> boolean()), [file:filename()]) -> [file:filename()].
process_file(File, TestFun, Acc) ->
case TestFun(File) of
@@ -121,7 +115,7 @@ process_file(File, TestFun, Acc) ->
end.
%% Same order as the input list
--spec split_dirs_and_files([string()], string()) -> {[string()], [string()]}.
+-spec split_dirs_and_files([file:filename()], file:filename()) -> {[file:filename()], [file:filename()]}.
split_dirs_and_files(Elems, Dir) ->
Test_Fun =
@@ -141,7 +135,7 @@ split_dirs_and_files(Elems, Dir) ->
%% Removes duplicate filenames but it keeps the order of the input list
--spec remove_dup([string()]) -> [string()].
+-spec remove_dup([file:filename()]) -> [file:filename()].
remove_dup(Files) ->
Test_Dup = fun (File, Acc) ->