From 38b2f44764e79a34048f686d98b6d741d18738d2 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 5 May 2011 14:22:18 +0200 Subject: Improve erl_docgen's support for Dialyzer specs and types The support for using Dialyzer specifications and types has been improved. --- lib/erl_docgen/priv/bin/specs_gen.escript | 101 +++++++++++++++++++----------- 1 file changed, 64 insertions(+), 37 deletions(-) (limited to 'lib/erl_docgen/priv/bin') diff --git a/lib/erl_docgen/priv/bin/specs_gen.escript b/lib/erl_docgen/priv/bin/specs_gen.escript index 840fed6dd5..982afece7f 100644 --- a/lib/erl_docgen/priv/bin/specs_gen.escript +++ b/lib/erl_docgen/priv/bin/specs_gen.escript @@ -2,7 +2,7 @@ %% -*- erlang -*- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 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 @@ -29,7 +29,7 @@ %%% "-I" Directory to be searched when including a file. %%% "-module Module" %%% Module name to use when there is no File argument. -%%% A temporary file will be created. +%%% A empty specifications file will be created. %%% Exactly one of -module Module and File must be given. %%% %%% The name of the generated file is "specs_.xml". Its exact @@ -67,34 +67,73 @@ usage() -> halt(1). call_edoc(FileSpec, InclFs, Dir) -> - Incl = [{includes, InclFs}], - Pre = [{preprocess, true}], - Choice = [{dialyzer_specs, all}], - DirOpt = [{dir, Dir}], - Pretty = [{pretty_print, erl_pp}], - Layout = [{layout, otp_specs}, - {file_suffix, ".specs"}, - {stylesheet, ""}], - Warn = [{report_missing_type, false}, - {report_type_mismatch, false}], - OptionList = (DirOpt ++ Choice ++ Pre ++ Warn ++ Pretty ++ Layout ++ Incl), - {File, TmpFile} = case FileSpec of - {file, File0} -> - {File0, false}; - {module, Module} -> - {create_tmp_file(Dir, Module), true} - end, - try edoc:files([File], OptionList) of - ok -> - clean_up(Dir, File, TmpFile), - rename(Dir, File) + ReadOpts = [{includes, InclFs}, {preprocess, true}], + ExtractOpts = [{report_missing_type, false}], + LayoutOpts = [{pretty_printer, erl_pp}, {layout, otp_specs}], + File = case FileSpec of + {file, File0} -> File0; + {module, Module0} -> Module0 + end, + try + Fs = case FileSpec of + {file, _} -> + Fs0 = read_file(File, ReadOpts), + clauses(Fs0); + {module, Module} -> + [{attribute,0,module,list_to_atom(Module)}] + end, + Doc = extract(File, Fs, ExtractOpts), + Text = edoc:layout(Doc, LayoutOpts), + ok = write_text(Text, File, Dir), + rename(Dir, File) catch _:_ -> io:format("EDoc could not process file '~s'\n", [File]), - clean_up(Dir, File, TmpFile), + clean_up(Dir), halt(3) end. +read_file(File, Opts) -> + edoc:read_source(File, Opts). + +extract(File, Forms, Opts) -> + Env = edoc_lib:get_doc_env([], [], [], _Opts=[]), + {_Module, Doc} = edoc_extract:source(Forms, File, Env, Opts), + Doc. + +clauses(Fs) -> + clauses(Fs, no). + +clauses([], no) -> + []; +clauses([F | Fs], Spec) -> + case F of + {attribute,_,spec,_} -> + clauses(Fs, F); + {function,_,_N,_A,_Cls} when Spec =/= no-> + {attribute,_,spec,{Name,FunTypes}} = Spec, + %% [throw({no,Name,{_N,_A}}) || Name =/= {_N,_A}], + %% EDoc doesn't care if a function appears more than once; + %% this is how overloaded specs are handled: + (lists:append([[setelement(4, Spec, {Name,[T]}),F] || + T <- FunTypes]) + ++ clauses(Fs, no)); + _ -> + [F | clauses(Fs, Spec)] + end. + +write_text(Text, File, Dir) -> + Base = filename:basename(File, ".erl"), + OutFile = filename:join(Dir, Base) ++ ".specs", + case file:write_file(OutFile, Text) of + ok -> + ok; + {error, R} -> + R1 = file:format_error(R), + io:format("could not write file '~s': ~s\n", [File, R1]), + halt(2) + end. + rename(Dir, F) -> Mod = filename:basename(F, ".erl"), Old = filename:join(Dir, Mod ++ ".specs"), @@ -108,22 +147,10 @@ rename(Dir, F) -> halt(2) end. -clean_up(Dir, File, TmpFile) -> - [file:delete(File) || TmpFile], +clean_up(Dir) -> _ = [file:delete(filename:join(Dir, F)) || F <- ["packages-frame.html", "overview-summary.html", "modules-frame.html", "index.html", "erlang.png", "edoc-info"]], ok. - -create_tmp_file(Dir, Module) -> - TmpFile = filename:join(Dir, Module++".erl"), - case file:write_file(TmpFile, "-module(" ++ Module ++ ").\n") of - ok -> - TmpFile; - {error, R} -> - R1 = file:format_error(R), - io:format("could not write file '~s': ~s\n", [TmpFile, R1]), - halt(2) - end. -- cgit v1.2.3