aboutsummaryrefslogblamecommitdiffstats
path: root/lib/typer/src/typer_preprocess.erl
blob: 27660e849e6baa36b943119375d53ce73deefd6d (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


                                 


                                                        




                                                                      
  



                                                                         
  










                                                                              
                                                                        
 

                                                                 


                                               

                                              
 
                                                              










                                                     
                                                  



                                      

                                                                               
 
                                       
                                                   
                                           

                                       

                                                                                     





                                                    
                                                       



                                 

                                                                                
 

                                                                 

                             

                                                                          
 
                                      


                                                             

                       

                                                           
               
                                                        
                                                  










                                                                        
                                                                                                                 







                                   
                                                                                                         


















                                                                         
                                                         









                                                    
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
%% 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%
%%

-module(typer_preprocess).

-export([get_all_files/2]).

-include("typer.hrl").

%%----------------------------------------------------------------------------

-spec get_all_files(#args{}, 'analysis' | 'trust') -> [file:filename()].

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{trusted=Fs}, trust) -> 
  files_and_dirs(Fs, [], fun test_erl_file/1).

-spec test_erl_file_exclude_ann(file:filename()) -> 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(file:filename()) -> boolean().

test_erl_file(File) ->
  filename:extension(File) =:= ".erl".

-spec files_and_dirs([file:filename()], [file:filename()],
		     fun((file:filename()) -> boolean())) -> [file:filename()].

files_and_dirs(File_Dir, Dir_R, Fun) ->
  All_File_1 = process_file_and_dir(File_Dir, Fun),
  All_File_2 = process_dir_rec(Dir_R, Fun),
  remove_dup(All_File_1 ++ All_File_2).

-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, false, Acc, TestFun)
	end
    end,
  lists:foldl(Fun, [], File_Dir).

-spec process_dir_rec([file:filename()],
		      fun((file:filename()) -> boolean())) -> [file:filename()].

process_dir_rec(Dirs, TestFun) ->
  Fun = fun (Dir, Acc) -> check_dir(Dir, true, Acc, TestFun) end,
  lists:foldl(Fun, [], Dirs).

-spec check_dir(file:filename(), boolean(), [file:filename()],
		fun((file:filename()) -> boolean())) -> [file:filename()].

check_dir(Dir, Recursive, Acc, Fun) ->
  case file:list_dir(Dir) of
    {ok, Files} ->
      {TmpDirs, TmpFiles} = split_dirs_and_files(Files, Dir),
      case Recursive of
	false ->
	  FinalFiles = process_file_and_dir(TmpFiles, Fun),
	  Acc ++ FinalFiles;
	true ->
	  TmpAcc1 = process_file_and_dir(TmpFiles, Fun),
	  TmpAcc2 = process_dir_rec(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(file:filename(), fun((file:filename()) -> boolean()), [file:filename()]) -> [file:filename()].

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([file:filename()], file:filename()) -> {[file:filename()], [file:filename()]}.

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([file:filename()]) -> [file:filename()].

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).