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 ++++-- lib/erl_docgen/priv/xsl/db_html.xsl | 556 +++++++++++++++++++++--------- lib/erl_docgen/priv/xsl/db_man.xsl | 424 +++++++++++++++-------- lib/erl_docgen/priv/xsl/db_pdf.xsl | 451 ++++++++++++++++-------- lib/erl_docgen/src/otp_specs.erl | 14 +- 5 files changed, 1066 insertions(+), 480 deletions(-) (limited to 'lib/erl_docgen') 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. diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index c6375ea621..982572aeef 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -22,12 +22,15 @@ @@ -38,49 +41,58 @@ + - Error : - /: + Error in : + : + + /: - + - + - - + + + + + + ambiguous spec + unknown spec + + + - unknown spec + + + - - - - / - - - - - + + + + + + @@ -89,72 +101,189 @@ - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + - + + + +
- - + + + + + + + + + + + + + + + + + + + + +

Types:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + -

Types:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unknown type variable + + + + - - + + + + -
+
+ + + -
- + + + +
- + +
+
+ + + + + + + +
+ + + + + +
+ + +
@@ -193,130 +322,175 @@
- - - -
-
- - - -
- - -
-
- - -
- - - -
-
+ + + + - - - - - - - - - - + + + + ambiguous type + unknown type + + + - unknown type + - + + + + + + + + + + + - + - + + + + +
+
+ + + + + + + + + +
+
+ + + + +
+ + +
+
+ + + +
+ + + +
+
+ + select="ancestor::type_desc/preceding-sibling::name + | ancestor::desc/preceding-sibling::name"/> - cannot find 'name' () + + cannot find tag 'name' (anno ) - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + unknown annotation + + + + + + + + + + + + + + + + "$spec0[string-length($clause_i) = 0 + or position() = $clause_i]/anno[.=$anno]"/> - - - - - - - - - - - - - - - - - unknown annotation - - + + - @@ -324,6 +498,50 @@  
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1178,14 +1396,7 @@ - - - / - - - - - + @@ -1221,11 +1432,19 @@ -
  • - - / - -
  • + + + + + +
  • + + / + +
  • +
    +
    @@ -1470,7 +1689,10 @@ -

    +

    +

    @@ -1478,7 +1700,6 @@
    - @@ -1488,6 +1709,11 @@ + + + Error : arity is mandatory when referring to specifications! + + @@ -1556,12 +1782,17 @@ -

    Types:

    + + - - - -
    +

    Types:

    + + + + +
    + +
    @@ -1612,7 +1843,10 @@
    + + + @@ -1633,16 +1867,16 @@ --> - + - + - + diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl index 2a8fb9fe3e..25b62f68c5 100644 --- a/lib/erl_docgen/priv/xsl/db_man.xsl +++ b/lib/erl_docgen/priv/xsl/db_man.xsl @@ -3,7 +3,7 @@ # # %CopyrightBegin% # - # Copyright Ericsson AB 2009-2010. All Rights Reserved. + # Copyright Ericsson AB 2009-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 @@ -21,13 +21,16 @@ --> + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:exsl="http://exslt.org/common" + extension-element-prefixes="exsl"> - @@ -35,38 +38,58 @@ + - Error : - /: + Error in : + : + + /: - + - + - - + + + + + + ambiguous spec + unknown spec + + + - unknown spec + + + + + + + + + + + @@ -75,42 +98,12 @@ - - - - - - - - - - + .br - - - - - - - - - - - - - - - - - - - - - .nf .B @@ -119,29 +112,141 @@ .fi - - + + + + + + + + + + + + + + + + + + + + .RS + .TP + Types + + + + + + + + + + + + + + + + + + + + + + + + + + .RE + + + + + + + - .RS - .TP - Types - - - - - .RE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unknown type variable + + + + + + + + + + - - - - .br - + + + .br + + + + + + + + + + + + + + .br + + + @@ -164,59 +269,46 @@ - - .nf - .B - - .br - .fi - - - - .RS - - .RE - - - - - - .br - - + - - - - - - - - - - + + + + ambiguous type + unknown type + + + - unknown type + - + + + + + + + + - + .nf .B @@ -226,68 +318,109 @@ + + .nf + .B + + .br + .fi + + + + .nf + + .fi + + + + + .RS + + .RE + + + + + + .br + + + select="ancestor::type_desc/preceding-sibling::name + | ancestor::desc/preceding-sibling::name"/> - cannot find 'name' () + + cannot find tag 'name' (anno ) - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + unknown annotation + + + + + + + + + + + + + + + + "$spec0[string-length($clause_i) = 0 + or position() = $clause_i]/anno[.=$anno]"/> - - - - - - - - - - - - - - - - - unknown annotation - - + + - @@ -542,6 +675,9 @@ .LP + @@ -554,6 +690,11 @@ + + + Error : arity is mandatory when referring to specifications! + + @@ -569,11 +710,14 @@ - .RS - .TP - Types - - .RE + + + .RS + .TP + Types + + .RE + @@ -622,7 +766,7 @@ > - + diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl index f500cd3fee..5119e3e36a 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl @@ -21,6 +21,8 @@ --> @@ -28,45 +30,66 @@ + - Error : - /: + Error in : + : + + /: - + - + - - + + + + + + ambiguous spec + unknown spec + + + - unknown spec + + + + + + + + + + + @@ -76,78 +99,175 @@ - - - - - - - - - - + - - - - - + + + + - - + + + + + + + + + + - - - - - + + + + + + + + + + Types: + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unknown type variable + + + - - - Types: - - - - + + - + + + - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -182,6 +302,53 @@ + + + + + + + + + + + + + + + ambiguous type + unknown type + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -189,6 +356,20 @@ + + + + + + + + + @@ -211,108 +392,82 @@ - - - - - - - - - - - - - - - - - - - - - - - - - unknown type - - - - - - - - - - - - + select="ancestor::type_desc/preceding-sibling::name + | ancestor::desc/preceding-sibling::name"/> - cannot find 'name' () + + cannot find tag 'name' (anno ) - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + unknown annotation + + + + + + + + + + + + + + + + "$spec0[string-length($clause_i) = 0 + or position() = $clause_i]/anno[.=$anno]"/> - - - - - - - - - - - - - - - - - unknown annotation - - + + - @@ -1227,6 +1382,9 @@ + @@ -1245,6 +1403,11 @@ + + + Error : arity is mandatory when referring to specifications! + + @@ -1276,15 +1439,20 @@ - - Types: - + + - - - - - + + Types: + + + + + + + + + @@ -1431,6 +1599,7 @@ + diff --git a/lib/erl_docgen/src/otp_specs.erl b/lib/erl_docgen/src/otp_specs.erl index 728ddb2e6e..edb437a942 100644 --- a/lib/erl_docgen/src/otp_specs.erl +++ b/lib/erl_docgen/src/otp_specs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-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 @@ -380,6 +380,8 @@ t_type([E=#xmlElement{name = float}]) -> t_float(E); t_type([#xmlElement{name = nil}]) -> t_nil(); +t_type([#xmlElement{name = paren, content = Es}]) -> + t_paren(Es); t_type([#xmlElement{name = list, content = Es}]) -> t_list(Es); t_type([#xmlElement{name = nonempty_list, content = Es}]) -> @@ -416,6 +418,9 @@ t_float(E) -> t_nil() -> ["[]"]. +t_paren(Es) -> + ["("] ++ t_utype(get_elem(type, Es)) ++ [")"]. + t_list(Es) -> ["["] ++ t_utype(get_elem(type, Es)) ++ ["]"]. @@ -532,6 +537,8 @@ ot_type([E=#xmlElement{name = float}]) -> ot_float(E); ot_type([#xmlElement{name = nil}]) -> ot_nil(); +ot_type([#xmlElement{name = paren, content = Es}]) -> + ot_paren(Es); ot_type([#xmlElement{name = list, content = Es}]) -> ot_list(Es); ot_type([#xmlElement{name = nonempty_list, content = Es}]) -> @@ -582,6 +589,9 @@ ot_float(E) -> ot_nil() -> {nil,0}. +ot_paren(Es) -> + {paren_type,0,[ot_utype(get_elem(type, Es))]}. + ot_list(Es) -> {type,0,list,[ot_utype(get_elem(type, Es))]}. @@ -697,5 +707,7 @@ annos_type([#xmlElement{name = union, content = Es}]) -> lists:flatmap(fun annos_elem/1, Es); annos_type([E=#xmlElement{name = typevar}]) -> annos_elem(E); +annos_type([#xmlElement{name = paren, content = Es}]) -> + annos(get_elem(type, Es)); annos_type(_) -> []. -- cgit v1.2.3