aboutsummaryrefslogtreecommitdiffstats
path: root/lib/typer/src/typer_preprocess.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/typer/src/typer_preprocess.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/typer/src/typer_preprocess.erl')
-rw-r--r--lib/typer/src/typer_preprocess.erl154
1 files changed, 154 insertions, 0 deletions
diff --git a/lib/typer/src/typer_preprocess.erl b/lib/typer/src/typer_preprocess.erl
new file mode 100644
index 0000000000..7cb0b9932b
--- /dev/null
+++ b/lib/typer/src/typer_preprocess.erl
@@ -0,0 +1,154 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. 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%
+%%
+
+-module(typer_preprocess).
+
+-export([get_all_files/2]).
+
+-include("typer.hrl").
+
+%%----------------------------------------------------------------------------
+
+-spec get_all_files(#args{}, 'analysis' | 'trust') -> [string()].
+
+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
+ [] -> 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).
+
+-spec test_erl_file_exclude_ann(string()) -> boolean().
+
+test_erl_file_exclude_ann(File) ->
+ case filename:extension(File) of
+ ".erl" -> %% Exclude files ending with ".ann.erl"
+ case re:run(File, "[\.]ann[\.]erl$") of
+ {match, _} -> false;
+ nomatch -> true
+ end;
+ _ -> false
+ end.
+
+-spec test_erl_file(string()) -> boolean().
+
+test_erl_file(File) ->
+ filename:extension(File) =:= ".erl".
+
+-spec internal_get_all_files([string()], [string()],
+ fun((string()) -> boolean())) -> [string()].
+
+internal_get_all_files(File_Dir, Dir_R, Fun) ->
+ All_File_1 = process_file_and_dir(File_Dir, Fun),
+ All_File_2 = process_dir_recursively(Dir_R, Fun),
+ remove_dup(All_File_1 ++ All_File_2).
+
+-spec process_file_and_dir([string()],
+ fun((string()) -> boolean())) -> [string()].
+
+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)
+ end
+ end,
+ lists:foldl(Fun, [], File_Dir).
+
+-spec process_dir_recursively([string()],
+ fun((string()) -> boolean())) -> [string()].
+
+process_dir_recursively(Dirs, TestFun) ->
+ Fun = fun (Dir, Acc) ->
+ check_dir(Dir, recursive, Acc, TestFun)
+ end,
+ lists:foldl(Fun, [], Dirs).
+
+-spec check_dir(string(),
+ 'non_recursive' | 'recursive',
+ [string()],
+ fun((string()) -> boolean())) -> [string()].
+
+check_dir(Dir, Mode, Acc, Fun) ->
+ case file:list_dir(Dir) of
+ {ok, Files} ->
+ {TmpDirs, TmpFiles} = split_dirs_and_files(Files, Dir),
+ case Mode of
+ non_recursive ->
+ FinalFiles = process_file_and_dir(TmpFiles, Fun),
+ Acc ++ FinalFiles;
+ recursive ->
+ TmpAcc1 = process_file_and_dir(TmpFiles, Fun),
+ TmpAcc2 = process_dir_recursively(TmpDirs, Fun),
+ Acc ++ TmpAcc1 ++ TmpAcc2
+ end;
+ {error, eacces} ->
+ typer:error("no access permission to dir \""++Dir++"\"");
+ {error, enoent} ->
+ typer:error("cannot access "++Dir++": No such file or directory");
+ {error, _Reason} ->
+ typer:error("error involving a use of file:list_dir/1")
+ end.
+
+%% Same order as the input list
+-spec process_file(string(), fun((string()) -> boolean()), string()) -> [string()].
+
+process_file(File, TestFun, Acc) ->
+ case TestFun(File) of
+ true -> Acc ++ [File];
+ false -> Acc
+ end.
+
+%% Same order as the input list
+-spec split_dirs_and_files([string()], string()) -> {[string()], [string()]}.
+
+split_dirs_and_files(Elems, Dir) ->
+ Test_Fun =
+ fun (Elem, {DirAcc, FileAcc}) ->
+ File = filename:join(Dir, Elem),
+ case filelib:is_regular(File) of
+ false -> {[File|DirAcc], FileAcc};
+ true -> {DirAcc, [File|FileAcc]}
+ end
+ end,
+ {Dirs, Files} = lists:foldl(Test_Fun, {[], []}, Elems),
+ {lists:reverse(Dirs), lists:reverse(Files)}.
+
+%%-----------------------------------------------------------------------
+%% Utilities
+%%-----------------------------------------------------------------------
+
+%% Removes duplicate filenames but it keeps the order of the input list
+
+-spec remove_dup([string()]) -> [string()].
+
+remove_dup(Files) ->
+ Test_Dup = fun (File, Acc) ->
+ case lists:member(File, Acc) of
+ true -> Acc;
+ false -> [File|Acc]
+ end
+ end,
+ Reversed_Elems = lists:foldl(Test_Dup, [], Files),
+ lists:reverse(Reversed_Elems).