aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer/src/dialyzer_utils.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/src/dialyzer_utils.erl')
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl138
1 files changed, 89 insertions, 49 deletions
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index fa9ad2eae2..6ea243c26f 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2006-2010. 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%
%%
@@ -47,6 +47,32 @@
-include("dialyzer.hrl").
+%%-define(DEBUG, true).
+
+-ifdef(DEBUG).
+print_types(RecDict) ->
+ Keys = dict:fetch_keys(RecDict),
+ print_types1(Keys, RecDict).
+
+print_types1([], _) ->
+ ok;
+print_types1([{type, _Name} = Key|T], RecDict) ->
+ {ok, {_Mod, Form, _Args}} = dict:find(Key, RecDict),
+ io:format("\n~w: ~w\n", [Key, erl_types:t_from_form(Form, RecDict)]),
+ print_types1(T, RecDict);
+print_types1([{opaque, _Name} = Key|T], RecDict) ->
+ {ok, {_Mod, Form, _Args}} = dict:find(Key, RecDict),
+ io:format("\n~w: ~w\n", [Key, erl_types:t_from_form(Form, RecDict)]),
+ print_types1(T, RecDict);
+print_types1([{record, _Name} = Key|T], RecDict) ->
+ {ok, [{Arity, Fields} = AF]} = dict:find(Key, RecDict),
+ io:format("~w: ~w\n\n", [Key, AF]),
+ print_types1(T, RecDict).
+-define(debug(D_), print_types(D_)).
+-else.
+-define(debug(D_), ok).
+-endif.
+
%%
%% Types that need to be imported from somewhere else
%%
@@ -61,13 +87,13 @@
%% ============================================================================
-spec get_abstract_code_from_src(atom() | file:filename()) ->
- {'ok', abstract_code()} | {'error', [string()]}.
+ {'ok', abstract_code()} | {'error', [string()]}.
get_abstract_code_from_src(File) ->
get_abstract_code_from_src(File, src_compiler_opts()).
-spec get_abstract_code_from_src(atom() | file:filename(), comp_options()) ->
- {'ok', abstract_code()} | {'error', [string()]}.
+ {'ok', abstract_code()} | {'error', [string()]}.
get_abstract_code_from_src(File, Opts) ->
case compile:file(File, [to_pp, binary|Opts]) of
@@ -137,60 +163,60 @@ get_core_from_abstract_code(AbstrCode, Opts) ->
%% ============================================================================
-spec get_record_and_type_info(abstract_code()) ->
- {'ok', dict()} | {'error', string()}.
+ {'ok', dict()} | {'error', string()}.
get_record_and_type_info(AbstractCode) ->
Module = get_module(AbstractCode),
get_record_and_type_info(AbstractCode, Module, dict:new()).
-spec get_record_and_type_info(abstract_code(), atom(), dict()) ->
- {'ok', dict()} | {'error', string()}.
+ {'ok', dict()} | {'error', string()}.
+
+get_record_and_type_info(AbstractCode, Module, RecDict) ->
+ get_record_and_type_info(AbstractCode, Module, [], RecDict).
get_record_and_type_info([{attribute, _, record, {Name, Fields0}}|Left],
- Module, RecDict) ->
- case get_record_fields(Fields0, RecDict) of
- {ok, Fields} ->
- Arity = length(Fields),
- Fun = fun(OldOrdDict) -> orddict:store(Arity, Fields, OldOrdDict) end,
- NewRecDict = dict:update({record, Name}, Fun, [{Arity, Fields}], RecDict),
- get_record_and_type_info(Left, Module, NewRecDict);
- {error, Error} ->
- {error, lists:flatten(io_lib:format(" Error while parsing #~w{}: ~s\n",
- [Name, Error]))}
- end;
+ Module, Records, RecDict) ->
+ {ok, Fields} = get_record_fields(Fields0, RecDict),
+ Arity = length(Fields),
+ NewRecDict = dict:store({record, Name}, [{Arity, Fields}], RecDict),
+ get_record_and_type_info(Left, Module, [{record, Name}|Records], NewRecDict);
get_record_and_type_info([{attribute, _, type, {{record, Name}, Fields0, []}}
- |Left], Module, RecDict) ->
+ |Left], Module, Records, RecDict) ->
%% This overrides the original record declaration.
- case get_record_fields(Fields0, RecDict) of
- {ok, Fields} ->
- Arity = length(Fields),
- Fun = fun(OldOrdDict) -> orddict:store(Arity, Fields, OldOrdDict) end,
- NewRecDict = dict:update({record, Name}, Fun, [{Arity, Fields}], RecDict),
- get_record_and_type_info(Left, Module, NewRecDict);
- {error, Error} ->
- {error, lists:flatten(io_lib:format(" Error while parsing #~w{}: ~s\n",
- [Name, Error]))}
- end;
+ {ok, Fields} = get_record_fields(Fields0, RecDict),
+ Arity = length(Fields),
+ NewRecDict = dict:store({record, Name}, [{Arity, Fields}], RecDict),
+ get_record_and_type_info(Left, Module, Records, NewRecDict);
get_record_and_type_info([{attribute, _, Attr, {Name, TypeForm}}|Left],
- Module, RecDict) when Attr =:= 'type'; Attr =:= 'opaque' ->
+ Module, Records, RecDict) when Attr =:= 'type';
+ Attr =:= 'opaque' ->
try
NewRecDict = add_new_type(Attr, Name, TypeForm, [], Module, RecDict),
- get_record_and_type_info(Left, Module, NewRecDict)
+ get_record_and_type_info(Left, Module, Records, NewRecDict)
catch
throw:{error, _} = Error -> Error
end;
get_record_and_type_info([{attribute, _, Attr, {Name, TypeForm, Args}}|Left],
- Module, RecDict) when Attr =:= 'type'; Attr =:= 'opaque' ->
+ Module, Records, RecDict) when Attr =:= 'type';
+ Attr =:= 'opaque' ->
try
NewRecDict = add_new_type(Attr, Name, TypeForm, Args, Module, RecDict),
- get_record_and_type_info(Left, Module, NewRecDict)
+ get_record_and_type_info(Left, Module, Records, NewRecDict)
catch
throw:{error, _} = Error -> Error
end;
-get_record_and_type_info([_Other|Left], Module, RecDict) ->
- get_record_and_type_info(Left, Module, RecDict);
-get_record_and_type_info([], _Module, RecDict) ->
- {ok, RecDict}.
+get_record_and_type_info([_Other|Left], Module, Records, RecDict) ->
+ get_record_and_type_info(Left, Module, Records, RecDict);
+get_record_and_type_info([], _Module, Records, RecDict) ->
+ case type_record_fields(lists:reverse(Records), RecDict) of
+ {ok, _NewRecDict} = Ok ->
+ ?debug(NewRecDict),
+ Ok;
+ {Name, {error, Error}} ->
+ {error, lists:flatten(io_lib:format(" Error while parsing #~w{}: ~s\n",
+ [Name, Error]))}
+ end.
add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, RecDict) ->
case erl_types:type_is_defined(TypeOrOpaque, Name, RecDict) of
@@ -198,7 +224,6 @@ add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, RecDict) ->
throw({error, io_lib:format("Type already defined: ~w\n", [Name])});
false ->
ArgTypes = [erl_types:t_from_form(X) || X <- ArgForms],
- _Type = erl_types:t_from_form(TypeForm, RecDict),
case lists:all(fun erl_types:t_is_var/1, ArgTypes) of
true ->
ArgNames = [erl_types:t_var_name(X) || X <- ArgTypes],
@@ -219,21 +244,36 @@ get_record_fields([{typed_record_field, OrdRecField, TypeForm}|Left],
{record_field, _Line, Name0} -> erl_parse:normalise(Name0);
{record_field, _Line, Name0, _Init} -> erl_parse:normalise(Name0)
end,
- try
- Type = erl_types:t_from_form(TypeForm, RecDict),
- get_record_fields(Left, RecDict, [{Name, Type}|Acc])
- catch
- throw:{error, _} = Error -> Error
- end;
+ get_record_fields(Left, RecDict, [{Name, TypeForm}|Acc]);
get_record_fields([{record_field, _Line, Name}|Left], RecDict, Acc) ->
- NewAcc = [{erl_parse:normalise(Name), erl_types:t_any()}|Acc],
+ NewAcc = [{erl_parse:normalise(Name), {var, -1, '_'}}|Acc],
get_record_fields(Left, RecDict, NewAcc);
get_record_fields([{record_field, _Line, Name, _Init}|Left], RecDict, Acc) ->
- NewAcc = [{erl_parse:normalise(Name), erl_types:t_any()}|Acc],
+ NewAcc = [{erl_parse:normalise(Name), {var, -1, '_'}}|Acc],
get_record_fields(Left, RecDict, NewAcc);
get_record_fields([], _RecDict, Acc) ->
{ok, lists:reverse(Acc)}.
+type_record_fields([], RecDict) ->
+ {ok, RecDict};
+type_record_fields([RecKey|Recs], RecDict) ->
+ {ok, [{Arity, Fields}]} = dict:find(RecKey, RecDict),
+ try
+ TypedFields =
+ [{FieldName, erl_types:t_from_form(FieldTypeForm, RecDict)}
+ || {FieldName, FieldTypeForm} <- Fields],
+ RecDict1 = dict:store(RecKey, [{Arity, TypedFields}], RecDict),
+ Fun = fun(OldOrdDict) ->
+ orddict:store(Arity, TypedFields, OldOrdDict)
+ end,
+ RecDict2 = dict:update(RecKey, Fun, RecDict1),
+ type_record_fields(Recs, RecDict2)
+ catch
+ throw:{error, _} = Error ->
+ {record, Name} = RecKey,
+ {Name, Error}
+ end.
+
-spec process_record_remote_types(dialyzer_codeserver:codeserver()) -> dialyzer_codeserver:codeserver().
process_record_remote_types(CServer) ->
@@ -269,7 +309,7 @@ merge_records(NewRecords, OldRecords) ->
%% ============================================================================
-spec get_spec_info(module(), abstract_code(), dict()) ->
- {'ok', dict()} | {'error', string()}.
+ {'ok', dict()} | {'error', string()}.
get_spec_info(ModName, AbstractCode, RecordsDict) ->
get_spec_info(AbstractCode, dict:new(), RecordsDict, ModName, "nofile").