aboutsummaryrefslogtreecommitdiffstats
path: root/lib/edoc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/edoc')
-rw-r--r--lib/edoc/Makefile21
-rw-r--r--lib/edoc/doc/Makefile21
-rw-r--r--lib/edoc/doc/overview.edoc32
-rw-r--r--lib/edoc/doc/src/Makefile21
-rw-r--r--lib/edoc/doc/src/book.xml25
-rw-r--r--lib/edoc/doc/src/fascicules.xml2
-rw-r--r--lib/edoc/doc/src/notes.xml180
-rw-r--r--lib/edoc/doc/src/part.xml25
-rw-r--r--lib/edoc/doc/src/part_notes.xml25
-rw-r--r--lib/edoc/doc/src/ref_man.xml25
-rw-r--r--lib/edoc/include/Makefile21
-rw-r--r--lib/edoc/include/edoc_doclet.hrl11
-rw-r--r--lib/edoc/priv/edoc.dtd15
-rw-r--r--lib/edoc/priv/edoc_generate.src21
-rw-r--r--lib/edoc/priv/stylesheet.css4
-rw-r--r--lib/edoc/src/edoc.app.src4
-rw-r--r--lib/edoc/src/edoc.appup.src23
-rw-r--r--lib/edoc/src/edoc.erl245
-rw-r--r--lib/edoc/src/edoc.hrl7
-rw-r--r--lib/edoc/src/edoc_data.erl70
-rw-r--r--lib/edoc/src/edoc_doclet.erl108
-rw-r--r--lib/edoc/src/edoc_extract.erl73
-rw-r--r--lib/edoc/src/edoc_layout.erl98
-rw-r--r--lib/edoc/src/edoc_lib.erl174
-rw-r--r--lib/edoc/src/edoc_macros.erl6
-rw-r--r--lib/edoc/src/edoc_parser.yrl38
-rw-r--r--lib/edoc/src/edoc_refs.erl72
-rw-r--r--lib/edoc/src/edoc_run.erl41
-rw-r--r--lib/edoc/src/edoc_scanner.erl21
-rw-r--r--lib/edoc/src/edoc_specs.erl224
-rw-r--r--lib/edoc/src/edoc_tags.erl34
-rw-r--r--lib/edoc/src/edoc_types.erl66
-rw-r--r--lib/edoc/src/edoc_types.hrl4
-rw-r--r--lib/edoc/src/otpsgml_layout.erl24
-rw-r--r--lib/edoc/test/Makefile2
-rw-r--r--lib/edoc/test/edoc_SUITE.erl102
-rw-r--r--lib/edoc/test/edoc_SUITE_data/map_module.erl67
-rw-r--r--lib/edoc/test/edoc_SUITE_data/myapp/doc/.dummy0
-rw-r--r--lib/edoc/test/edoc_SUITE_data/myapp/src/a.erl1
-rw-r--r--lib/edoc/test/edoc_SUITE_data/myapp/src/src_1/b.erl1
-rw-r--r--lib/edoc/test/edoc_SUITE_data/un1.erl7
-rw-r--r--lib/edoc/test/edoc_SUITE_data/un2.erl8
-rw-r--r--lib/edoc/test/edoc_SUITE_data/un3.erl8
-rw-r--r--lib/edoc/vsn.mk2
44 files changed, 1002 insertions, 977 deletions
diff --git a/lib/edoc/Makefile b/lib/edoc/Makefile
index 1add669398..70bf1f3d48 100644
--- a/lib/edoc/Makefile
+++ b/lib/edoc/Makefile
@@ -1,13 +1,14 @@
-# ``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 via the world wide web 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.
+# ``Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
diff --git a/lib/edoc/doc/Makefile b/lib/edoc/doc/Makefile
index 7a59809d9b..c635f07d78 100644
--- a/lib/edoc/doc/Makefile
+++ b/lib/edoc/doc/Makefile
@@ -1,13 +1,14 @@
-# ``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 via the world wide web 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.
+# ``Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
diff --git a/lib/edoc/doc/overview.edoc b/lib/edoc/doc/overview.edoc
index 2af425272e..d2bba9d744 100644
--- a/lib/edoc/doc/overview.edoc
+++ b/lib/edoc/doc/overview.edoc
@@ -76,11 +76,9 @@ The following are the main functions for running EDoc:
<ul>
<li>{@link edoc:application/2}: Creates documentation for a
typical Erlang application.</li>
- <li>{@link edoc:packages/2}: Creates documentation for one or
- more packages, automatically locating source files.</li>
<li>{@link edoc:files/2}: Creates documentation for a
specified set of source files.</li>
- <li>{@link edoc:run/3}: General interface function; the common
+ <li>{@link edoc:run/2}: General interface function; the common
back-end for the above functions. Options are documented here.</li>
</ul>
@@ -184,7 +182,7 @@ The following tags can be used anywhere within a module:
path (see {@link edoc:read_source/2}).</dd>
<dt><a name="gtag-todo">`@todo' (or `@TODO')</a></dt>
- <dd>Attaches a To-Do note to a function, module, package, or
+ <dd>Attaches a To-Do note to a function, module or
overview-page. The content can be any XHTML text describing
the issue, e.g.:
```%% @TODO Finish writing the documentation.'''
@@ -338,7 +336,7 @@ The following tags can be used before a module declaration:
<dt><a name="mtag-since">`@since'</a></dt>
<dd>Specifies when the module was introduced, with respect to
- the application, package, release or distribution it is part
+ the application, release or distribution it is part
of. The content can be arbitrary text.</dd>
<dt><a name="mtag-version">`@version'</a></dt>
@@ -445,7 +443,6 @@ possible formats for references are:
<table border="1" summary="reference syntax">
<tr><th>Reference syntax</th><th>Example</th><th>Scope</th></tr>
<tr><td>`Module'</td><td>{@link edoc_run}, `erl.lang.list'</td><td>Global</td></tr>
- <tr><td>`Package.*'</td><td>`erl.lang.*'</td><td>Global</td></tr>
<tr><td>`Function/Arity'</td><td>`file/2'</td><td>Within module</td></tr>
<tr><td>`Module:Function/Arity'</td><td>{@link edoc:application/2}</td><td>Global</td></tr>
<tr><td>`Type()'</td><td>`filename()'</td><td>Within module</td></tr>
@@ -531,7 +528,7 @@ after the empty line into separate paragraphs. For example:
```%% @doc This will all be part of the first paragraph.
%% It can stretch over several lines and contain <em>any
%% XHTML markup</em>.
- %%
+ %%
%% This is the second paragraph. The above line is
%% regarded as "empty" by EDoc, even though it ends with
%% a space.'''
@@ -685,17 +682,6 @@ information. User-defined macros override predefined macros.
<dd>Expands to the current date, as "<tt>Month Day Year</tt>",
e.g. "{@date}".</dd>
- <dt><a name="predefmacro-docRoot"><code>@{@docRoot}</code></a></dt>
- <dd>Expands to the relative URL path (such as
- `"../../.."') from the current page to the root
- directory of the generated documentation. This can be used to
- create XHTML references such as `<img
- src="@{@docRoot}/images/logo.jpeg">' that are independent of how
- deep down in a package structure they occur. If packages are not
- used (i.e., if all modules are in the "empty" package),
- <code>@{@docRoot}</code> will always resolve to the empty
- string.</dd>
-
<dt><a name="predefmacro-link"><code>@{@link <em>reference</em>.
<em>description</em>}</code></a></dt>
<dd>This creates a hypertext link; cf. the
@@ -710,9 +696,6 @@ information. User-defined macros override predefined macros.
<dd>Expands to the name of the current module. Only defined when a
module is being processed.</dd>
- <dt><a name="predefmacro-package"><code>@{@package}</code></a></dt>
- <dd>Expands to the name of the current package.</dd>
-
<dt><a name="predefmacro-section"><code>@{@section
<em>heading</em>}</code></a></dt>
<dd>Expands to a hypertext link to the specified section heading;
@@ -772,7 +755,7 @@ following escape sequences may be used: <dl>
=== Function specifications ===
-<note>Although the syntax described in the following can still be used
+Note that although the syntax described in the following can still be used
for specifying functions we recommend that Erlang specifications as
described in <seealso marker="doc/reference_manual:typespec"> Types
and Function Specification</seealso> should be added to the source
@@ -781,7 +764,6 @@ marker="dialyzer:dialyzer">Dialyzer</seealso>'s can be utilized in the
process of keeping the documentation consistent and up-to-date.
Erlang specifications will be used unless there is also a function
specification (a `@spec' tag followed by a type) with the same name.
-</note>
The following grammar describes the form of the specifications following
a `@spec' tag. A '`?'' suffix implies that the element is optional.
@@ -990,12 +972,12 @@ contain any annotations at all.
=== Type definitions ===
-<note>Although the syntax described in the following can still be used
+Note that although the syntax described in the following can still be used
for specifying types we recommend that Erlang types as described in
<seealso marker="doc/reference_manual:typespec"> Types and Function
Specification</seealso> should be added to the source code instead.
Erlang types will be used unless there is a type alias with the same
-name.</note>
+name.
The following grammar (see above for auxiliary definitions) describes
the form of the definitions that may follow a `@type' tag:
diff --git a/lib/edoc/doc/src/Makefile b/lib/edoc/doc/src/Makefile
index 1f92d36f12..ce7945a1bb 100644
--- a/lib/edoc/doc/src/Makefile
+++ b/lib/edoc/doc/src/Makefile
@@ -1,13 +1,14 @@
-# ``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 via the world wide web 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.
+# ``Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
diff --git a/lib/edoc/doc/src/book.xml b/lib/edoc/doc/src/book.xml
index 67b7cdb2d7..cdd7eb6f1a 100644
--- a/lib/edoc/doc/src/book.xml
+++ b/lib/edoc/doc/src/book.xml
@@ -1,23 +1,24 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE book SYSTEM "book.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
- 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.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
</legalnotice>
diff --git a/lib/edoc/doc/src/fascicules.xml b/lib/edoc/doc/src/fascicules.xml
index 1b9d6bc94d..154c8a3b6d 100644
--- a/lib/edoc/doc/src/fascicules.xml
+++ b/lib/edoc/doc/src/fascicules.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
<fascicules>
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index 12f93ab400..ae8147c564 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -1,23 +1,24 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2007</year><year>2013</year>
+ <year>2007</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
- 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.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
</legalnotice>
@@ -31,6 +32,159 @@
<p>This document describes the changes made to the EDoc
application.</p>
+<section><title>Edoc 0.7.19</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Handle typed record fields. </p>
+ <p>
+ Own Id: OTP-13558</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.7.18</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Assign correct names to list arguments. </p>
+ <p>
+ Own Id: OTP-13234 Aux Id: ERL-63 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Unless the <c>sort_functions</c> option is <c>true</c>,
+ <c>edoc_layout</c> does not sort functions.</p>
+ <p>
+ Own Id: OTP-13302</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.7.17</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Remove functionality related to packages</p>
+ <p>
+ Own Id: OTP-12431</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.7.16</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Maps: Properly align union typed assoc values in
+ documentation</p>
+ <p>
+ Own Id: OTP-12190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.7.15</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix spec to doc generation from erl_docgen and edoc for
+ maps</p>
+ <p>
+ Own Id: OTP-12058</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.7.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> The default encoding for Erlang source files is now
+ UTF-8. As a temporary measure to ease the transition from
+ the old default of Latin-1, if EDoc encounters byte
+ sequences that are not valid UTF-8 sequences, EDoc will
+ re-try in Latin-1 mode. This workaround will be removed
+ in a future release. </p>
+ <p>
+ Own Id: OTP-12008</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.7.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.7.12.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The encoding of the <c>notes.xml</c> file has been
+ changed from latin1 to utf-8 to avoid future merge
+ problems.</p>
+ <p>
+ Own Id: OTP-11310</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Edoc 0.7.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -219,7 +373,7 @@
<list>
<item>
<p> Add encoding when parsing Wiki text. EDoc used to
- fail on strings such as "���". (Thanks to Richard
+ fail on strings such as "äåö". (Thanks to Richard
Carlsson.) </p>
<p>
Own Id: OTP-9109</p>
diff --git a/lib/edoc/doc/src/part.xml b/lib/edoc/doc/src/part.xml
index a71b4eda13..389efa902b 100644
--- a/lib/edoc/doc/src/part.xml
+++ b/lib/edoc/doc/src/part.xml
@@ -1,23 +1,24 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
- 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.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
</legalnotice>
diff --git a/lib/edoc/doc/src/part_notes.xml b/lib/edoc/doc/src/part_notes.xml
index 42fc39af42..6a79435ff0 100644
--- a/lib/edoc/doc/src/part_notes.xml
+++ b/lib/edoc/doc/src/part_notes.xml
@@ -1,23 +1,24 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2007</year><year>2009</year>
+ <year>2007</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
- 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.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
</legalnotice>
diff --git a/lib/edoc/doc/src/ref_man.xml b/lib/edoc/doc/src/ref_man.xml
index a9af8740b9..e3460345a0 100644
--- a/lib/edoc/doc/src/ref_man.xml
+++ b/lib/edoc/doc/src/ref_man.xml
@@ -1,23 +1,24 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE application SYSTEM "application.dtd">
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2006</year><year>2011</year>
+ <year>2006</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
- 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.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
</legalnotice>
diff --git a/lib/edoc/include/Makefile b/lib/edoc/include/Makefile
index cf2e051632..6318253c27 100644
--- a/lib/edoc/include/Makefile
+++ b/lib/edoc/include/Makefile
@@ -1,13 +1,14 @@
-# ``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 via the world wide web 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.
+# ``Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
diff --git a/lib/edoc/include/edoc_doclet.hrl b/lib/edoc/include/edoc_doclet.hrl
index 60ec7f44e4..ac6763fb33 100644
--- a/lib/edoc/include/edoc_doclet.hrl
+++ b/lib/edoc/include/edoc_doclet.hrl
@@ -1,6 +1,6 @@
%% =====================================================================
%% Header file for EDoc doclet modules.
-%%
+%%
%% Copyright (C) 2001-2004 Richard Carlsson
%%
%% This library is free software; you can redistribute it and/or modify
@@ -43,16 +43,11 @@
%% @type doclet_gen() = #doclet_gen{sources = [string()],
%% app = no_app() | atom(),
-%% packages = [atom()],
-%% modules = [atom()],
-%% modules = [atom()],
-%% filemap = function()}
+%% modules = [atom()]}
-record(doclet_gen, {sources = [],
app = ?NO_APP,
- packages = [],
- modules = [],
- filemap
+ modules = []
}).
%% @type doclet_toc() = #doclet_gen{paths = [string()],
diff --git a/lib/edoc/priv/edoc.dtd b/lib/edoc/priv/edoc.dtd
index ba4ac0db28..89058f5d85 100644
--- a/lib/edoc/priv/edoc.dtd
+++ b/lib/edoc/priv/edoc.dtd
@@ -2,20 +2,13 @@
<!-- EDoc DTD Version 0.3 -->
<!ELEMENT overview (title, description?, author*, copyright?, version?,
- since?, see*, reference*, todo?, packages, modules)>
+ since?, see*, reference*, todo?, modules)>
<!ATTLIST overview
root CDATA #IMPLIED
encoding CDATA #IMPLIED>
<!ELEMENT title (#PCDATA)>
-<!ELEMENT package (description?, author*, copyright?, version?,
- since?, deprecated?, see*, reference*, todo?,
- modules)>
-<!ATTLIST package
- name CDATA #REQUIRED
- root CDATA #IMPLIED>
-
<!ELEMENT modules (module+)>
@@ -110,7 +103,7 @@
<!ATTLIST type name CDATA #IMPLIED>
<!ELEMENT union (typevar | atom | integer | float | nil | list | tuple |
- fun | record | abstype)+>
+ fun | record | map | abstype)+>
<!ELEMENT typevar EMPTY>
<!ATTLIST typevar name CDATA #REQUIRED>
@@ -136,6 +129,10 @@
<!ELEMENT field (atom, type)>
+<!ELEMENT map (map_field)*>
+
+<!ELEMENT map_field (type, type)>
+
<!ELEMENT abstype (erlangName, type*)>
<!ATTLIST abstype
href CDATA #IMPLIED>
diff --git a/lib/edoc/priv/edoc_generate.src b/lib/edoc/priv/edoc_generate.src
index 7ec89207b0..eeaa20f959 100644
--- a/lib/edoc/priv/edoc_generate.src
+++ b/lib/edoc/priv/edoc_generate.src
@@ -1,14 +1,15 @@
#!/bin/sh
-# ``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 via the world wide web at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# ``Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
# Portions created by Ericsson are Copyright 1999-2000, Ericsson
diff --git a/lib/edoc/priv/stylesheet.css b/lib/edoc/priv/stylesheet.css
index e426a90483..ab170c091f 100644
--- a/lib/edoc/priv/stylesheet.css
+++ b/lib/edoc/priv/stylesheet.css
@@ -27,10 +27,10 @@ div.spec {
margin-left: 2em;
background-color: #eeeeee;
}
-a.module,a.package {
+a.module {
text-decoration:none
}
-a.module:hover,a.package:hover {
+a.module:hover {
background-color: #eeeeee;
}
ul.definitions {
diff --git a/lib/edoc/src/edoc.app.src b/lib/edoc/src/edoc.app.src
index 0c8d5b85f8..e4b9040c78 100644
--- a/lib/edoc/src/edoc.app.src
+++ b/lib/edoc/src/edoc.app.src
@@ -22,4 +22,6 @@
otpsgml_layout]},
{registered,[]},
{applications, [compiler,kernel,stdlib,syntax_tools]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["xmerl-1.3.7","syntax_tools-1.6.14","stdlib-2.5",
+ "kernel-3.0","inets-5.10","erts-6.0"]}]}.
diff --git a/lib/edoc/src/edoc.appup.src b/lib/edoc/src/edoc.appup.src
index 54a63833e6..4765eead70 100644
--- a/lib/edoc/src/edoc.appup.src
+++ b/lib/edoc/src/edoc.appup.src
@@ -1 +1,22 @@
-{"%VSN%",[],[]}.
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+{"%VSN%",
+ [{<<".*">>,[{restart_application, edoc}]}],
+ [{<<".*">>,[{restart_application, edoc}]}]
+}.
diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl
index a87a8471e3..94013bb5ac 100644
--- a/lib/edoc/src/edoc.erl
+++ b/lib/edoc/src/edoc.erl
@@ -24,12 +24,11 @@
%% TODO: option for ignoring functions matching some pattern ('..._test_'/0)
%% TODO: @private_type tag, opaque unless generating private docs?
%% TODO: document the record type syntax
-%% TODO: some 'skip' option for ignoring particular modules/packages?
-%% TODO: intermediate-level packages: document even if no local sources.
+%% TODO: some 'skip' option for ignoring particular modules?
%% TODO: multiline comment support (needs modified comment representation)
%% TODO: config-file for default settings
%% TODO: config: locations of all local docdirs; generate local doc-index page
-%% TODO: config: URL:s of offline packages/apps
+%% TODO: config: URL:s of offline apps
%% TODO: config: default stylesheet
%% TODO: config: default header/footer, etc.
%% TODO: offline linkage
@@ -45,10 +44,10 @@
-module(edoc).
--export([packages/1, packages/2, files/1, files/2,
+-export([files/1, files/2,
application/1, application/2, application/3,
toc/1, toc/2, toc/3,
- run/3,
+ run/2,
file/1, file/2,
read/1, read/2,
layout/1, layout/2,
@@ -68,15 +67,15 @@
file(Name) ->
file(Name, []).
-%% @spec file(filename(), proplist()) -> ok
+%% @spec file(filename(), proplist()) -> ok
%%
%% @type filename() = //kernel/file:filename()
%% @type proplist() = [term()]
%%
%% @deprecated This is part of the old interface to EDoc and is mainly
%% kept for backwards compatibility. The preferred way of generating
-%% documentation is through one of the functions {@link application/2},
-%% {@link packages/2} and {@link files/2}.
+%% documentation is through one of the functions {@link application/2}
+%% and {@link files/2}.
%%
%% @doc Reads a source code file and outputs formatted documentation to
%% a corresponding file.
@@ -121,44 +120,24 @@ file(Name, Options) ->
?DEFAULT_FILE_SUFFIX),
Dir = proplists:get_value(dir, Options, filename:dirname(Name)),
Encoding = [{encoding, edoc_lib:read_encoding(Name, [])}],
- edoc_lib:write_file(Text, Dir, BaseName ++ Suffix, '', Encoding).
+ edoc_lib:write_file(Text, Dir, BaseName ++ Suffix, Encoding).
-%% TODO: better documentation of files/1/2, packages/1/2, application/1/2/3
+%% TODO: better documentation of files/1/2, application/1/2/3
-%% @spec (Files::[filename() | {package(), [filename()]}]) -> ok
-%% @equiv packages(Packages, [])
+%% @spec (Files::[filename()]) -> ok
files(Files) ->
files(Files, []).
-%% @spec (Files::[filename() | {package(), [filename()]}],
+%% @spec (Files::[filename()],
%% Options::proplist()) -> ok
-%% @doc Runs EDoc on a given set of source files. See {@link run/3} for
+%% @doc Runs EDoc on a given set of source files. See {@link run/2} for
%% details, including options.
%% @equiv run([], Files, Options)
files(Files, Options) ->
- run([], Files, Options).
-
-%% @spec (Packages::[package()]) -> ok
-%% @equiv packages(Packages, [])
-
-packages(Packages) ->
- packages(Packages, []).
-
-%% @spec (Packages::[package()], Options::proplist()) -> ok
-%% @type package() = atom() | string()
-%%
-%% @doc Runs EDoc on a set of packages. The `source_path' option is used
-%% to locate the files; see {@link run/3} for details, including
-%% options. This function automatically appends the current directory to
-%% the source path.
-%%
-%% @equiv run(Packages, [], Options)
-
-packages(Packages, Options) ->
- run(Packages, [], Options ++ [{source_path, [?CURRENT_DIR]}]).
+ run(Files, Options).
%% @spec (Application::atom()) -> ok
%% @equiv application(Application, [])
@@ -194,7 +173,7 @@ application(App, Options) when is_atom(App) ->
%% subdirectory, if it exists, or otherwise in the application
%% directory itself.
%% </li>
-%% <li>The {@link run/3. `subpackages'} option is turned on. All found
+%% <li>The {@link run/2. `subpackages'} option is turned on. All found
%% source files will be processed.
%% </li>
%% <li>The `include' subdirectory is automatically added to the
@@ -203,7 +182,7 @@ application(App, Options) when is_atom(App) ->
%% </li>
%% </ul>
%%
-%% See {@link run/3} for details, including options.
+%% See {@link run/2} for details, including options.
%%
%% @see application/2
@@ -219,7 +198,7 @@ application(App, Dir, Options) when is_atom(App) ->
{includes, [filename:join(Dir, "include")]}],
Opts1 = set_app_default(App, Dir, Opts),
%% Recursively document all subpackages of '' - i.e., everything.
- run([''], [], [{application, App} | Opts1]).
+ run([], [{application, App} | Opts1]).
%% Try to set up a default application base URI in a smart way if the
%% user has not specified it explicitly.
@@ -240,31 +219,20 @@ set_app_default(App, Dir0, Opts) ->
Opts
end.
-%% If no source files are found for a (specified) package, no package
-%% documentation will be generated either (even if there is a
-%% package-documentation file). This is the way it should be. For
-%% specified files, use empty package (unless otherwise specified). The
-%% assumed package is always used for creating the output. If the actual
-%% module or package of the source differs from the assumption gathered
-%% from the path and file name, a warning should be issued (since links
-%% are likely to be incorrect).
-
opt_defaults() ->
- [packages].
+ [].
opt_negations() ->
[{no_preprocess, preprocess},
{no_subpackages, subpackages},
- {no_report_missing_types, report_missing_types},
- {no_packages, packages}].
+ {no_report_missing_types, report_missing_types}].
-%% @spec run(Packages::[package()],
-%% Files::[filename() | {package(), [filename()]}],
+%% @spec run(Files::[filename()],
%% Options::proplist()) -> ok
-%% @doc Runs EDoc on a given set of source files and/or packages. Note
+%% @doc Runs EDoc on a given set of source files. Note
%% that the doclet plugin module has its own particular options; see the
%% `doclet' option below.
-%%
+%%
%% Also see {@link layout/2} for layout-related options, and
%% {@link get_doc/2} for options related to reading source
%% files.
@@ -298,11 +266,6 @@ opt_negations() ->
%% The default doclet module is {@link edoc_doclet}; see {@link
%% edoc_doclet:run/2} for doclet-specific options.
%% </dd>
-%% <dt>{@type {exclude_packages, [package()]@}}
-%% </dt>
-%% <dd>Lists packages to be excluded from the documentation. Typically
-%% used in conjunction with the `subpackages' option.
-%% </dd>
%% <dt>{@type {file_suffix, string()@}}
%% </dt>
%% <dd>Specifies the suffix used for output files. The default value is
@@ -314,22 +277,6 @@ opt_negations() ->
%% target directory will be ignored and overwritten. The default
%% value is `false'.
%% </dd>
-%% <dt>{@type {packages, boolean()@}}
-%% </dt>
-%% <dd>If the value is `true', it it assumed that packages (module
-%% namespaces) are being used, and that the source code directory
-%% structure reflects this. The default value is `true'. (Usually,
-%% this does the right thing even if all the modules belong to the
-%% top-level "empty" package.) `no_packages' is an alias for
-%% `{packages, false}'. See the `subpackages' option below for
-%% further details.
-%%
-%% If the source code is organized in a hierarchy of
-%% subdirectories although it does not use packages, use
-%% `no_packages' together with the recursive-search `subpackages'
-%% option (on by default) to automatically generate documentation
-%% for all the modules.
-%% </dd>
%% <dt>{@type {source_path, [filename()]@}}
%% </dt>
%% <dd>Specifies a list of file system paths used to locate the source
@@ -345,7 +292,7 @@ opt_negations() ->
%% <dd>If the value is `true', all subpackages of specified packages
%% will also be included in the documentation. The default value is
%% `false'. `no_subpackages' is an alias for `{subpackages,
-%% false}'. See also the `exclude_packages' option.
+%% false}'.
%%
%% Subpackage source files are found by recursively searching
%% for source code files in subdirectories of the known source code
@@ -358,38 +305,31 @@ opt_negations() ->
%% </dl>
%%
%% @see files/2
-%% @see packages/2
%% @see application/2
%% NEW-OPTIONS: source_path, application
%% INHERIT-OPTIONS: init_context/1
%% INHERIT-OPTIONS: expand_sources/2
%% INHERIT-OPTIONS: target_dir_info/5
-%% INHERIT-OPTIONS: edoc_lib:find_sources/3
+%% INHERIT-OPTIONS: edoc_lib:find_sources/2
%% INHERIT-OPTIONS: edoc_lib:run_doclet/2
-%% INHERIT-OPTIONS: edoc_lib:get_doc_env/4
+%% INHERIT-OPTIONS: edoc_lib:get_doc_env/3
-run(Packages, Files, Opts0) ->
+run(Files, Opts0) ->
Opts = expand_opts(Opts0),
Ctxt = init_context(Opts),
Dir = Ctxt#context.dir,
Path = proplists:append_values(source_path, Opts),
- Ss = sources(Path, Packages, Opts),
+ Ss = sources(Path, Opts),
{Ss1, Ms} = expand_sources(expand_files(Files) ++ Ss, Opts),
- Ps = [P || {_, P, _, _} <- Ss1],
App = proplists:get_value(application, Opts, ?NO_APP),
- {App1, Ps1, Ms1} = target_dir_info(Dir, App, Ps, Ms, Opts),
- %% The "empty package" is never included in the list of packages.
- Ps2 = edoc_lib:unique(lists:sort(Ps1)) -- [''],
+ {App1, Ms1} = target_dir_info(Dir, App, Ms, Opts),
Ms2 = edoc_lib:unique(lists:sort(Ms1)),
- Fs = package_files(Path, Ps2),
- Env = edoc_lib:get_doc_env(App1, Ps2, Ms2, Opts),
+ Env = edoc_lib:get_doc_env(App1, Ms2, Opts),
Ctxt1 = Ctxt#context{env = Env},
Cmd = #doclet_gen{sources = Ss1,
app = App1,
- packages = Ps2,
- modules = Ms2,
- filemap = Fs
+ modules = Ms2
},
F = fun (M) ->
M:run(Cmd, Ctxt1)
@@ -401,42 +341,22 @@ expand_opts(Opts0) ->
Opts0 ++ opt_defaults()).
%% NEW-OPTIONS: dir
-%% DEFER-OPTIONS: run/3
+%% DEFER-OPTIONS: run/2
init_context(Opts) ->
#context{dir = proplists:get_value(dir, Opts, ?CURRENT_DIR),
opts = Opts
}.
-%% INHERIT-OPTIONS: edoc_lib:find_sources/3
-
-sources(Path, Packages, Opts) ->
- lists:foldl(fun (P, Xs) ->
- edoc_lib:find_sources(Path, P, Opts) ++ Xs
- end,
- [], Packages).
-
-package_files(Path, Packages) ->
- Name = ?PACKAGE_FILE, % this is hard-coded for now
- D = lists:foldl(fun (P, D) ->
- F = edoc_lib:find_file(Path, P, Name),
- dict:store(P, F, D)
- end,
- dict:new(), Packages),
- fun (P) ->
- case dict:find(P, D) of
- {ok, F} -> F;
- error -> ""
- end
- end.
+%% INHERIT-OPTIONS: edoc_lib:find_sources/2
+
+sources(Path, Opts) ->
+ edoc_lib:find_sources(Path, Opts).
%% Expand user-specified sets of files.
-expand_files([{P, Fs1} | Fs]) ->
- [{P, filename:basename(F), filename:dirname(F)} || F <- Fs1]
- ++ expand_files(Fs);
expand_files([F | Fs]) ->
- [{'', filename:basename(F), filename:dirname(F)} |
+ [{filename:basename(F), filename:dirname(F)} |
expand_files(Fs)];
expand_files([]) ->
[].
@@ -444,26 +364,23 @@ expand_files([]) ->
%% Create the (assumed) full module names. Keep only the first source
%% for each module, but preserve the order of the list.
-%% NEW-OPTIONS: source_suffix, packages
-%% DEFER-OPTIONS: run/3
+%% NEW-OPTIONS: source_suffix
+%% DEFER-OPTIONS: run/2
expand_sources(Ss, Opts) ->
Suffix = proplists:get_value(source_suffix, Opts,
?DEFAULT_SOURCE_SUFFIX),
- Ss1 = case proplists:get_bool(packages, Opts) of
- true -> Ss;
- false -> [{'',F,D} || {_P,F,D} <- Ss]
- end,
+ Ss1 = [{F,D} || {F,D} <- Ss],
expand_sources(Ss1, Suffix, sets:new(), [], []).
-expand_sources([{'', F, D} | Fs], Suffix, S, As, Ms) ->
+expand_sources([{F, D} | Fs], Suffix, S, As, Ms) ->
M = list_to_atom(filename:rootname(F, Suffix)),
case sets:is_element(M, S) of
true ->
expand_sources(Fs, Suffix, S, As, Ms);
false ->
S1 = sets:add_element(M, S),
- expand_sources(Fs, Suffix, S1, [{M, '', F, D} | As],
+ expand_sources(Fs, Suffix, S1, [{M, F, D} | As],
[M | Ms])
end;
expand_sources([], _Suffix, _S, As, Ms) ->
@@ -471,16 +388,15 @@ expand_sources([], _Suffix, _S, As, Ms) ->
%% NEW-OPTIONS: new
-target_dir_info(Dir, App, Ps, Ms, Opts) ->
+target_dir_info(Dir, App, Ms, Opts) ->
case proplists:get_bool(new, Opts) of
true ->
- {App, Ps, Ms};
+ {App, Ms};
false ->
- {App1, Ps1, Ms1} = edoc_lib:read_info_file(Dir),
+ {App1, Ms1} = edoc_lib:read_info_file(Dir),
{if App == ?NO_APP -> App1;
true -> App
end,
- Ps ++ Ps1,
Ms ++ Ms1}
end.
@@ -505,12 +421,12 @@ toc(Dir, Opts) ->
%% INHERIT-OPTIONS: init_context/1
%% INHERIT-OPTIONS: edoc_lib:run_doclet/2
-%% INHERIT-OPTIONS: edoc_lib:get_doc_env/4
+%% INHERIT-OPTIONS: edoc_lib:get_doc_env/3
toc(Dir, Paths, Opts0) ->
Opts = expand_opts(Opts0 ++ [{dir, Dir}]),
Ctxt = init_context(Opts),
- Env = edoc_lib:get_doc_env('', [], [], Opts),
+ Env = edoc_lib:get_doc_env('', [], Opts),
Ctxt1 = Ctxt#context{env = Env},
F = fun (M) ->
M:run(#doclet_toc{paths=Paths}, Ctxt1)
@@ -562,7 +478,7 @@ layout(Doc) ->
%% </dl>
%%
%% @see layout/1
-%% @see run/3
+%% @see run/2
%% @see read/2
%% @see file/2
@@ -639,7 +555,6 @@ read_source(Name) ->
%% <dd>Specifies a list of pre-defined Erlang preprocessor (`epp')
%% macro definitions, used if the `preprocess' option is turned on.
%% The default value is the empty list.</dd>
-%% </dl>
%% <dt>{@type {report_missing_types, boolean()@}}
%% </dt>
%% <dd>If the value is `true', warnings are issued for missing types.
@@ -647,6 +562,7 @@ read_source(Name) ->
%% `no_report_missing_types' is an alias for
%% `{report_missing_types, false}'.
%% </dd>
+%% </dl>
%%
%% @see get_doc/2
%% @see //syntax_tools/erl_syntax
@@ -696,32 +612,48 @@ read_source_2(Name, Opts) ->
%% The line of the dot token will be copied to the integer token.
parse_file(Name, Includes, Macros) ->
- case epp:open(Name, Includes, Macros) of
- {ok, Epp} ->
- try {ok, parse_file(Epp)}
+ case parse_file(utf8, Name, Includes, Macros) of
+ invalid_unicode ->
+ parse_file(latin1, Name, Includes, Macros);
+ Ret ->
+ Ret
+ end.
+
+parse_file(DefEncoding, Name, Includes, Macros) ->
+ Options = [{name, Name},
+ {includes, Includes},
+ {macros, Macros},
+ {default_encoding, DefEncoding}],
+ case epp:open([extra | Options]) of
+ {ok, Epp, Extra} ->
+ try parse_file(Epp) of
+ Forms ->
+ Encoding = proplists:get_value(encoding, Extra),
+ case find_invalid_unicode(Forms) of
+ invalid_unicode when Encoding =/= utf8 ->
+ invalid_unicode;
+ _ ->
+ {ok, Forms}
+ end
after _ = epp:close(Epp)
end;
Error ->
Error
end.
+find_invalid_unicode([H|T]) ->
+ case H of
+ {error,{_Line,file_io_server,invalid_unicode}} ->
+ invalid_unicode;
+ _Other ->
+ find_invalid_unicode(T)
+ end;
+find_invalid_unicode([]) -> none.
+
parse_file(Epp) ->
case scan_and_parse(Epp) of
{ok, Form} ->
- case Form of
- {attribute,La,record,{Record, Fields}} ->
- case epp:normalize_typed_record_fields(Fields) of
- {typed, NewFields} ->
- [{attribute, La, record, {Record, NewFields}},
- {attribute, La, type,
- {{record, Record}, Fields, []}}
- | parse_file(Epp)];
- not_typed ->
- [Form | parse_file(Epp)]
- end;
- _ ->
- [Form | parse_file(Epp)]
- end;
+ [Form | parse_file(Epp)];
{error, E} ->
[{error, E} | parse_file(Epp)];
{eof, Location} ->
@@ -744,13 +676,12 @@ scan_and_parse(Epp) ->
fix_last_line(Toks0) ->
Toks1 = lists:reverse(Toks0),
- {line, LastLine} = erl_scan:token_info(hd(Toks1), line),
+ LastLine = erl_scan:line(hd(Toks1)),
fll(Toks1, LastLine, []).
-fll([{Category, Attributes0, Symbol} | L], LastLine, Ts) ->
- F = fun(_OldLine) -> LastLine end,
- Attributes = erl_scan:set_attribute(line, Attributes0, F),
- lists:reverse(L, [{Category, Attributes, Symbol} | Ts]);
+fll([{Category, Anno0, Symbol} | L], LastLine, Ts) ->
+ Anno = erl_anno:set_line(LastLine, Anno0),
+ lists:reverse(L, [{Category, Anno, Symbol} | Ts]);
fll([T | L], LastLine, Ts) ->
fll(L, LastLine, [T | Ts]);
fll(L, _LastLine, Ts) ->
@@ -824,16 +755,16 @@ get_doc(File) ->
%% </dl>
%%
%% See {@link read_source/2}, {@link read_comments/2} and {@link
-%% edoc_lib:get_doc_env/4} for further options.
+%% edoc_lib:get_doc_env/3} for further options.
%%
%% @see get_doc/3
-%% @see run/3
+%% @see run/2
%% @see edoc_extract:source/5
%% @see read/2
%% @see layout/2
%% INHERIT-OPTIONS: get_doc/3
-%% INHERIT-OPTIONS: edoc_lib:get_doc_env/4
+%% INHERIT-OPTIONS: edoc_lib:get_doc_env/3
get_doc(File, Opts) ->
Env = edoc_lib:get_doc_env(Opts),
@@ -845,7 +776,7 @@ get_doc(File, Opts) ->
%%
%% @doc Like {@link get_doc/2}, but for a given environment
%% parameter. `Env' is an environment created by {@link
-%% edoc_lib:get_doc_env/4}.
+%% edoc_lib:get_doc_env/3}.
%% INHERIT-OPTIONS: read_source/2, read_comments/2, edoc_extract:source/5
%% DEFER-OPTIONS: get_doc/2
diff --git a/lib/edoc/src/edoc.hrl b/lib/edoc/src/edoc.hrl
index 44c5d6fef4..5b0fb68cf9 100644
--- a/lib/edoc/src/edoc.hrl
+++ b/lib/edoc/src/edoc.hrl
@@ -1,6 +1,6 @@
%% =====================================================================
%% Header file for EDoc
-%%
+%%
%% Copyright (C) 2001-2004 Richard Carlsson
%%
%% This library is free software; you can redistribute it and/or modify
@@ -25,9 +25,7 @@
-define(APPLICATION, edoc).
-define(INFO_FILE, "edoc-info").
--define(PACKAGE_FILE, "package.edoc").
-define(OVERVIEW_FILE, "overview.edoc").
--define(PACKAGE_SUMMARY, "package-summary").
-define(DEFAULT_SOURCE_SUFFIX, ".erl").
-define(DEFAULT_FILE_SUFFIX, ".html").
-define(DEFAULT_DOCLET, edoc_doclet).
@@ -65,13 +63,10 @@
%% Environment for generating documentation data
-record(env, {module = [],
- package = [],
root = "",
file_suffix,
- package_summary,
apps,
modules,
- packages,
app_default,
macros = [],
includes = []
diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl
index f88ba05f4b..b797d74a71 100644
--- a/lib/edoc/src/edoc_data.erl
+++ b/lib/edoc/src/edoc_data.erl
@@ -26,7 +26,7 @@
-module(edoc_data).
--export([module/4, package/4, overview/4, type/2]).
+-export([module/4, overview/4, type/2]).
-export([hidden_filter/2, get_all_tags/1]).
@@ -173,21 +173,34 @@ callbacks(Es, Module, Env, Opts) ->
lists:keymember(callback, 1, Module#module.attributes)
of
true ->
- try (Module#module.name):behaviour_info(callbacks) of
- Fs ->
- Fs1 = [{F,A} || {F,A} <- Fs, is_atom(F), is_integer(A)],
- if Fs1 =:= [] ->
- [];
- true ->
- [{callbacks,
- [callback(F, Env, Opts) || F <- Fs1]}]
- end
- catch
- _:_ -> []
- end;
+ M = Module#module.name,
+ Fs = get_callback_functions(M, callbacks),
+ Os1 = get_callback_functions(M, optional_callbacks),
+ Fs1 = [FA || FA <- Fs, not lists:member(FA, Os1)],
+ Req = if Fs1 =:= [] ->
+ [];
+ true ->
+ [{callbacks,
+ [callback(FA, Env, Opts) || FA <- Fs1]}]
+ end,
+ Opt = if Os1 =:= [] ->
+ [];
+ true ->
+ [{optional_callbacks,
+ [callback(FA, Env, Opts) || FA <- Os1]}]
+ end,
+ Req ++ Opt;
false -> []
end.
+get_callback_functions(M, Callbacks) ->
+ try
+ [FA || {F, A} = FA <- M:behaviour_info(Callbacks),
+ is_atom(F), is_integer(A), A >= 0]
+ catch
+ _:_ -> []
+ end.
+
%% <!ELEMENT callback EMPTY>
%% <!ATTLIST callback
%% name CDATA #REQUIRED
@@ -497,41 +510,14 @@ get_tags(_, []) -> [].
type(T, Env) ->
xmerl_lib:expand_element({type, [edoc_types:to_xml(T, Env)]}).
-%% <!ELEMENT package (description?, author*, copyright?, version?,
-%% since?, deprecated?, see*, reference*, todo?,
-%% modules)>
-%% <!ATTLIST package
-%% name CDATA #REQUIRED
-%% root CDATA #IMPLIED>
-%% <!ELEMENT modules (module+)>
-
-package(Package, Tags, Env, Opts) ->
- Env1 = Env#env{package = Package,
- root = edoc_refs:relative_package_path('', Package)},
- xmerl_lib:expand_element(package_1(Package, Tags, Env1, Opts)).
-
-package_1(Package, Tags, Env, Opts) ->
- {package, [{root, Env#env.root}],
- ([{packageName, [atom_to_list(Package)]}]
- ++ get_doc(Tags)
- ++ authors(Tags)
- ++ get_copyright(Tags)
- ++ get_version(Tags)
- ++ get_since(Tags)
- ++ get_deprecated(Tags)
- ++ sees(Tags, Env)
- ++ references(Tags)
- ++ todos(Tags, Opts))
- }.
-
%% <!ELEMENT overview (title, description?, author*, copyright?, version?,
-%% since?, see*, reference*, todo?, packages, modules)>
+%% since?, see*, reference*, todo?, modules)>
%% <!ATTLIST overview
%% root CDATA #IMPLIED>
%% <!ELEMENT title (#PCDATA)>
overview(Title, Tags, Env, Opts) ->
- Env1 = Env#env{package = '',
+ Env1 = Env#env{
root = ""},
xmerl_lib:expand_element(overview_1(Title, Tags, Env1, Opts)).
diff --git a/lib/edoc/src/edoc_doclet.erl b/lib/edoc/src/edoc_doclet.erl
index ce1e94a26a..5961ca8cc0 100644
--- a/lib/edoc/src/edoc_doclet.erl
+++ b/lib/edoc/src/edoc_doclet.erl
@@ -42,9 +42,7 @@
-define(DEFAULT_FILE_SUFFIX, ".html").
-define(INDEX_FILE, "index.html").
-define(OVERVIEW_FILE, "overview.edoc").
--define(PACKAGE_SUMMARY, "package-summary.html").
-define(OVERVIEW_SUMMARY, "overview-summary.html").
--define(PACKAGES_FRAME, "packages-frame.html").
-define(MODULES_FRAME, "modules-frame.html").
-define(STYLESHEET, "stylesheet.css").
-define(IMAGE, "erlang.png").
@@ -52,11 +50,10 @@
-include_lib("xmerl/include/xmerl.hrl").
-%% Sources is the list of inputs in the order they were found. Packages
-%% and Modules are sorted lists of atoms without duplicates. (They
+%% Sources is the list of inputs in the order they were found.
+%% Modules are sorted lists of atoms without duplicates. (They
%% usually include the data from the edoc-info file in the target
-%% directory, if it exists.) Note that the "empty package" is never
-%% included in Packages!
+%% directory, if it exists.)
%% @spec (Command::doclet_gen() | doclet_toc(), edoc_context()) -> ok
%% @doc Main doclet entry point. See the file <a
@@ -117,14 +114,12 @@
run(#doclet_gen{}=Cmd, Ctxt) ->
gen(Cmd#doclet_gen.sources,
Cmd#doclet_gen.app,
- Cmd#doclet_gen.packages,
Cmd#doclet_gen.modules,
- Cmd#doclet_gen.filemap,
Ctxt);
run(#doclet_toc{}=Cmd, Ctxt) ->
toc(Cmd#doclet_toc.paths, Ctxt).
-gen(Sources, App, Packages, Modules, FileMap, Ctxt) ->
+gen(Sources, App, Modules, Ctxt) ->
Dir = Ctxt#context.dir,
Env = Ctxt#context.env,
Options = Ctxt#context.opts,
@@ -132,11 +127,9 @@ gen(Sources, App, Packages, Modules, FileMap, Ctxt) ->
CSS = stylesheet(Options),
{Modules1, Error} = sources(Sources, Dir, Modules, Env, Options),
modules_frame(Dir, Modules1, Title, CSS),
- packages(Packages, Dir, FileMap, Env, Options),
- packages_frame(Dir, Packages, Title, CSS),
overview(Dir, Title, Env, Options),
- index_file(Dir, length(Packages) > 1, Title),
- edoc_lib:write_info_file(App, Packages, Modules1, Dir),
+ index_file(Dir, Title),
+ edoc_lib:write_info_file(App, Modules1, Dir),
copy_stylesheet(Dir, Options),
copy_image(Dir),
%% handle postponed error during processing of source files
@@ -182,30 +175,29 @@ sources(Sources, Dir, Modules, Env, Options) ->
%% set if it was successful. Errors are just flagged at this stage,
%% allowing all source files to be processed even if some of them fail.
-source({M, P, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden,
+source({M, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden,
Error, Options) ->
File = filename:join(Path, Name),
case catch {ok, edoc:get_doc(File, Env, Options)} of
{ok, {Module, Doc}} ->
- check_name(Module, M, P, File),
+ check_name(Module, M, File),
case ((not is_private(Doc)) orelse Private)
andalso ((not is_hidden(Doc)) orelse Hidden) of
true ->
Text = edoc:layout(Doc, Options),
Name1 = atom_to_list(M) ++ Suffix,
Encoding = [{encoding,encoding(Doc)}],
- edoc_lib:write_file(Text, Dir, Name1, P, Encoding),
+ edoc_lib:write_file(Text, Dir, Name1, Encoding),
{sets:add_element(Module, Set), Error};
false ->
{Set, Error}
end;
R ->
- report("skipping source file '~ts': ~W.", [File, R, 15]),
+ report("skipping source file '~ts': ~P.", [File, R, 15]),
{Set, true}
end.
-check_name(M, M0, P0, File) ->
- P = '',
+check_name(M, M0, File) ->
N = M,
N0 = M0,
case N of
@@ -222,47 +214,12 @@ check_name(M, M0, P0, File) ->
ok
end
end,
- if P =/= P0 ->
- warning("file '~ts' belongs to package '~s', not '~s'.",
- [File, P, P0]);
- true ->
- ok
- end.
-
-
-%% Generating the summary files for packages.
-
-%% INHERIT-OPTIONS: read_file/4
-%% INHERIT-OPTIONS: edoc_lib:run_layout/2
-
-packages(Packages, Dir, FileMap, Env, Options) ->
- lists:foreach(fun (P) ->
- package(P, Dir, FileMap, Env, Options)
- end,
- Packages).
-
-package(P, Dir, FileMap, Env, Opts) ->
- Tags = case FileMap(P) of
- "" ->
- [];
- File ->
- read_file(File, package, Env, Opts)
- end,
- Data = edoc_data:package(P, Tags, Env, Opts),
- F = fun (M) ->
- M:package(Data, Opts)
- end,
- Text = edoc_lib:run_layout(F, Opts),
- edoc_lib:write_file(Text, Dir, ?PACKAGE_SUMMARY, P).
-
+ ok.
%% Creating an index file, with some frames optional.
%% TODO: get rid of frames, or change doctype to Frameset
-index_file(Dir, Packages, Title) ->
- Frame1 = {frame, [{src,?PACKAGES_FRAME},
- {name,"packagesFrame"},{title,""}],
- []},
+index_file(Dir, Title) ->
Frame2 = {frame, [{src,?MODULES_FRAME},
{name,"modulesFrame"},{title,""}],
[]},
@@ -270,16 +227,7 @@ index_file(Dir, Packages, Title) ->
{name,"overviewFrame"},{title,""}],
[]},
Frameset = {frameset, [{cols,"20%,80%"}],
- case Packages of
- true ->
- [?NL,
- {frameset, [{rows,"30%,70%"}],
- [?NL, Frame1, ?NL, Frame2, ?NL]}
- ];
- false ->
- [?NL, Frame2, ?NL]
- end
- ++ [?NL, Frame3, ?NL,
+ [?NL, Frame2, ?NL, ?NL, Frame3, ?NL,
{noframes,
[?NL,
{h2, ["This page uses frames"]},
@@ -296,24 +244,6 @@ index_file(Dir, Packages, Title) ->
Text = xmerl:export_simple([XML], xmerl_html, []),
edoc_lib:write_file(Text, Dir, ?INDEX_FILE).
-packages_frame(Dir, Ps, Title, CSS) ->
- Body = [?NL,
- {h2, [{class, "indextitle"}], ["Packages"]},
- ?NL,
- {table, [{width, "100%"}, {border, 0},
- {summary, "list of packages"}],
- lists:concat(
- [[?NL,
- {tr, [{td, [], [{a, [{href, package_ref(P)},
- {target,"overviewFrame"},
- {class, "package"}],
- [atom_to_list(P)]}]}]}]
- || P <- Ps])},
- ?NL],
- XML = xhtml(Title, CSS, Body),
- Text = xmerl:export_simple([XML], xmerl_html, []),
- edoc_lib:write_file(Text, Dir, ?PACKAGES_FRAME).
-
modules_frame(Dir, Ms, Title, CSS) ->
Body = [?NL,
{h2, [{class, "indextitle"}], ["Modules"]},
@@ -334,11 +264,7 @@ modules_frame(Dir, Ms, Title, CSS) ->
edoc_lib:write_file(Text, Dir, ?MODULES_FRAME).
module_ref(M) ->
- edoc_refs:relative_package_path(M, '') ++ ?DEFAULT_FILE_SUFFIX.
-
-package_ref(P) ->
- edoc_lib:join_uri(edoc_refs:relative_package_path(P, ''),
- ?PACKAGE_SUMMARY).
+ atom_to_list(M) ++ ?DEFAULT_FILE_SUFFIX.
xhtml(Title, CSS, Content) ->
xhtml_1(Title, CSS, {body, [{bgcolor, "white"}], Content}).
@@ -372,7 +298,7 @@ overview(Dir, Title, Env, Opts) ->
end,
Text = edoc_lib:run_layout(F, Opts),
EncOpts = [{encoding,Encoding}],
- edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY, '', EncOpts).
+ edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY, EncOpts).
copy_image(Dir) ->
case code:priv_dir(?EDOC_APP) of
@@ -505,7 +431,7 @@ app_index_file(Paths, Dir, Env, Options) ->
% Priv = proplists:get_bool(private, Options),
CSS = stylesheet(Options),
Apps1 = [{filename:dirname(A),filename:basename(A)} || A <- Paths],
- index_file(Dir, false, Title),
+ index_file(Dir, Title),
application_frame(Dir, Apps1, Title, CSS),
modules_frame(Dir, [], Title, CSS),
overview(Dir, Title, Env, Options),
diff --git a/lib/edoc/src/edoc_extract.erl b/lib/edoc/src/edoc_extract.erl
index 67a95e80aa..e7a4c36ca4 100644
--- a/lib/edoc/src/edoc_extract.erl
+++ b/lib/edoc/src/edoc_extract.erl
@@ -91,7 +91,7 @@ source(Forms, Comments, File, Env, Opts) ->
%% type `form_list', or a list of syntax trees representing
%% "program forms" (cf. {@link edoc:read_source/2}.
%% `Env' is an environment created by {@link
-%% edoc_lib:get_doc_env/4}. The `File' argument is used for
+%% edoc_lib:get_doc_env/3}. The `File' argument is used for
%% error reporting and output file name generation only.
%%
%% See {@link edoc:get_doc/2} for descriptions of the `def',
@@ -121,10 +121,8 @@ source1(Tree, File0, Env, Opts, TypeDocs) ->
Module = get_module_info(Tree, File),
{Header, Footer, Entries} = collect(Forms, Module),
Name = Module#module.name,
- Package = '',
Env1 = Env#env{module = Name,
- package = Package,
- root = edoc_refs:relative_package_path('', Package)},
+ root = ""},
Env2 = add_macro_defs(module_macros(Env1), Opts, Env1),
Entries1 = get_tags([Header, Footer | Entries], Env2, File, TypeDocs),
Entries2 = edoc_specs:add_data(Entries1, Opts, File, Module),
@@ -218,13 +216,13 @@ add_macro_defs(Defs0, Opts, Env) ->
%% @spec file(File::filename(), Context, Env::edoc_env(),
%% Options::proplist()) -> {ok, Tags} | {error, Reason}
-%% Context = overview | package
+%% Context = overview
%% Tags = [term()]
%% Reason = term()
%%
%% @doc Reads a text file and returns the list of tags in the file. Any
%% lines of text before the first tag are ignored. `Env' is an
-%% environment created by {@link edoc_lib:get_doc_env/4}. Upon error,
+%% environment created by {@link edoc_lib:get_doc_env/3}. Upon error,
%% `Reason' is an atom returned from the call to {@link
%% //kernel/file:read_file/1} or the atom 'invalid_unicode'.
%%
@@ -249,12 +247,12 @@ file(File, Context, Env, Opts) ->
%% @spec (Text::string(), Context, Env::edoc_env(),
%% Options::proplist()) -> Tags
-%% Context = overview | package
+%% Context = overview
%% Tags = [term()]
%%
%% @doc Returns the list of tags in the text. Any lines of text before
%% the first tag are ignored. `Env' is an environment created by {@link
-%% edoc_lib:get_doc_env/4}.
+%% edoc_lib:get_doc_env/3}.
%%
%% See {@link source/4} for a description of the `def' option.
@@ -353,12 +351,12 @@ preprocess_forms_2(F, Fs) ->
[F | preprocess_forms_1(Fs)];
{function, _} ->
[F | preprocess_forms_1(Fs)];
- {rule, _} ->
- [F | preprocess_forms_1(Fs)];
{attribute, {module, _}} ->
[F | preprocess_forms_1(Fs)];
text ->
[F | preprocess_forms_1(Fs)];
+ {attribute, {record, _}} ->
+ [F | preprocess_forms_1(Fs)];
{attribute, {N, _}} ->
case edoc_specs:is_tag(N) of
true ->
@@ -377,59 +375,62 @@ preprocess_forms_2(F, Fs) ->
%% in the list.
collect(Fs, Mod) ->
- collect(Fs, [], [], [], [], undefined, Mod).
+ collect(Fs, [], [], [], [], [], undefined, Mod).
-collect([F | Fs], Cs, Ss, Ts, As, Header, Mod) ->
+collect([F | Fs], Cs, Ss, Ts, Rs, As, Header, Mod) ->
case erl_syntax_lib:analyze_form(F) of
comment ->
- collect(Fs, [F | Cs], Ss, Ts, As, Header, Mod);
+ collect(Fs, [F | Cs], Ss, Ts, Rs, As, Header, Mod);
{function, Name} ->
L = erl_syntax:get_pos(F),
Export = ordsets:is_element(Name, Mod#module.exports),
Args = parameters(erl_syntax:function_clauses(F)),
- collect(Fs, [], [], [],
- [#entry{name = Name, args = Args, line = L,
- export = Export,
- data = {comment_text(Cs),Ss,Ts}} | As],
- Header, Mod);
- {rule, Name} ->
- L = erl_syntax:get_pos(F),
- Export = ordsets:is_element(Name, Mod#module.exports),
- Args = parameters(erl_syntax:rule_clauses(F)),
- collect(Fs, [], [], [],
+ collect(Fs, [], [], [], [],
[#entry{name = Name, args = Args, line = L,
export = Export,
- data = {comment_text(Cs),Ss,Ts}} | As],
+ data = {comment_text(Cs),Ss,Ts,Rs}} | As],
Header, Mod);
{attribute, {module, _}} when Header =:= undefined ->
L = erl_syntax:get_pos(F),
- collect(Fs, [], [], [], As,
+ collect(Fs, [], [], [], [], As,
#entry{name = module, line = L,
- data = {comment_text(Cs),Ss,Ts}},
+ data = {comment_text(Cs),Ss,Ts,Rs}},
Mod);
+ {attribute, {record, {_Name, Fields}}} ->
+ case is_typed_record(Fields) of
+ true ->
+ collect(Fs, Cs, Ss, Ts, [F | Rs], As, Header, Mod);
+ false ->
+ collect(Fs, Cs, Ss, Ts, Rs, As, Header, Mod)
+ end;
{attribute, {N, _}} ->
case edoc_specs:tag(N) of
spec ->
- collect(Fs, Cs, [F | Ss], Ts, As, Header, Mod);
+ collect(Fs, Cs, [F | Ss], Ts, Rs, As, Header, Mod);
type ->
- collect(Fs, Cs, Ss, [F | Ts], As, Header, Mod);
+ collect(Fs, Cs, Ss, [F | Ts], Rs, As, Header, Mod);
unknown ->
%% Drop current seen comments.
- collect(Fs, [], [], [], As, Header, Mod)
+ collect(Fs, [], [], [], Rs, As, Header, Mod)
end;
_ ->
%% Drop current seen comments.
- collect(Fs, [], [], [], As, Header, Mod)
+ collect(Fs, [], [], [], [], As, Header, Mod)
end;
-collect([], Cs, Ss, Ts, As, Header, _Mod) ->
- Footer = #entry{name = footer, data = {comment_text(Cs),Ss,Ts}},
+collect([], Cs, Ss, Ts, Rs, As, Header, _Mod) ->
+ Footer = #entry{name = footer, data = {comment_text(Cs),Ss,Ts,Rs}},
As1 = lists:reverse(As),
if Header =:= undefined ->
- {#entry{name = module, data = {[],[],[]}}, Footer, As1};
+ {#entry{name = module, data = {[],[],[],[]}}, Footer, As1};
true ->
{Header, Footer, As1}
end.
+is_typed_record([]) ->
+ false;
+is_typed_record([{_, {_, Type}} | Fs]) ->
+ Type =/= none orelse is_typed_record(Fs).
+
%% Returns a list of simplified comment information (position and text)
%% for a list of abstract comments. The order of elements is reversed.
@@ -562,8 +563,8 @@ get_tags(Es, Env, File, TypeDocs) ->
How = dict:from_list(edoc_tags:tag_parsers()),
get_tags(Es, Tags, Env, How, File, TypeDocs).
-get_tags([#entry{name = Name, data = {Cs,Specs,Types}} = E | Es], Tags, Env,
- How, File, TypeDocs) ->
+get_tags([#entry{name = Name, data = {Cs,Specs,Types,Records}} = E | Es],
+ Tags, Env, How, File, TypeDocs) ->
Where = {File, Name},
Ts0 = scan_tags(Cs),
{Ts1,Specs1} = select_spec(Ts0, Where, Specs),
@@ -571,7 +572,7 @@ get_tags([#entry{name = Name, data = {Cs,Specs,Types}} = E | Es], Tags, Env,
Ts3 = edoc_macros:expand_tags(Ts2, Env, Where),
Ts4 = edoc_tags:parse_tags(Ts3, How, Env, Where),
Ts = selected_specs(Specs1, Ts4),
- ETypes = [edoc_specs:type(Type, TypeDocs) || Type <- Types],
+ ETypes = [edoc_specs:type(Type, TypeDocs) || Type <- Types ++ Records],
[E#entry{data = Ts++ETypes} | get_tags(Es, Tags, Env, How, File, TypeDocs)];
get_tags([], _, _, _, _, _) ->
[].
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index 7bd0615f5c..ef57b7b084 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -27,7 +27,7 @@
-module(edoc_layout).
--export([module/2, package/2, overview/2, type/1]).
+-export([module/2, overview/2, type/1]).
-import(edoc_report, [report/2]).
@@ -180,7 +180,9 @@ layout_module(#xmlElement{name = module, content = Es}=E, Opts) ->
FullDesc = get_content(fullDescription, Desc),
Functions = [{function_name(E), E} || E <- get_content(functions, Es)],
Types = [{type_name(E), E} || E <- get_content(typedecls, Es)],
- SortedFs = lists:sort(Functions),
+ SortedFs = if Opts#opts.sort_functions -> lists:sort(Functions);
+ true -> Functions
+ end,
Body = (navigation("top")
++ [?NL, hr, ?NL, ?NL, {h1, Title}, ?NL]
++ doc_index(FullDesc, Functions, Types)
@@ -204,9 +206,7 @@ layout_module(#xmlElement{name = module, content = Es}=E, Opts) ->
end
++ types(lists:sort(Types), Opts)
++ function_index(SortedFs, Opts#opts.index_columns)
- ++ if Opts#opts.sort_functions -> functions(SortedFs, Opts);
- true -> functions(Functions, Opts)
- end
+ ++ functions(SortedFs, Opts)
++ [hr, ?NL]
++ navigation("bottom")
++ timestamp()),
@@ -520,7 +520,7 @@ format_spec(Name, Type, Defs, #opts{pretty_printer = erl_pp}=Opts) ->
{R, ".\n"} = etypef(L, O),
[{pre, R}]
catch _:_ ->
- %% Example: "@spec ... -> record(a)"
+ %% Should not happen.
format_spec(Name, Type, Defs, Opts#opts{pretty_printer=''})
end;
format_spec(Sep, Type, Defs, _Opts) ->
@@ -535,7 +535,8 @@ t_clause(Name, Type) ->
pp_clause(Pre, Type) ->
Types = ot_utype([Type]),
Atom = lists:duplicate(iolist_size(Pre), $a),
- L1 = erl_pp:attribute({attribute,0,spec,{{list_to_atom(Atom),0},[Types]}}),
+ Attr = {attribute,0,spec,{{list_to_atom(Atom),0},[Types]}},
+ L1 = erl_pp:attribute(erl_parse:new_anno(Attr)),
"-spec " ++ L2 = lists:flatten(L1),
L3 = Pre ++ lists:nthtail(length(Atom), L2),
re:replace(L3, "\n ", "\n", [{return,list},global]).
@@ -555,7 +556,8 @@ format_type(Prefix, _Name, Type, Last, _Opts) ->
pp_type(Prefix, Type) ->
Atom = list_to_atom(lists:duplicate(iolist_size(Prefix), $a)),
- L1 = erl_pp:attribute({attribute,0,type,{Atom,ot_utype(Type),[]}}),
+ Attr = {attribute,0,type,{Atom,ot_utype(Type),[]}},
+ L1 = erl_pp:attribute(erl_parse:new_anno(Attr)),
{L2,N} = case lists:dropwhile(fun(C) -> C =/= $: end, lists:flatten(L1)) of
":: " ++ L3 -> {L3,9}; % compensation for extra "()" and ":"
"::\n" ++ L3 -> {"\n"++L3,6}
@@ -701,6 +703,8 @@ deprecated(Es, S) ->
end.
behaviours(Es, Name) ->
+ CBs = get_content(callbacks, Es),
+ OCBs = get_content(optional_callbacks, Es),
(case get_elem(behaviour, Es) of
[] -> [];
Es1 ->
@@ -709,13 +713,24 @@ behaviours(Es, Name) ->
?NL]
end
++
- case get_content(callbacks, Es) of
- [] -> [];
- Es1 ->
+ if CBs =:= [], OCBs =:= [] ->
+ [];
+ true ->
+ Req = if CBs =:= [] ->
+ [];
+ true ->
+ [br, " Required callback functions: "]
+ ++ seq(fun callback/1, CBs, ["."])
+ end,
+ Opt = if OCBs =:= [] ->
+ [];
+ true ->
+ [br, " Optional callback functions: "]
+ ++ seq(fun callback/1, OCBs, ["."])
+ end,
[{p, ([{b, ["This module defines the ", {tt, [Name]},
- " behaviour."]},
- br, " Required callback functions: "]
- ++ seq(fun callback/1, Es1, ["."]))},
+ " behaviour."]}]
+ ++ Req ++ Opt)},
?NL]
end).
@@ -829,6 +844,8 @@ t_type([#xmlElement{name = list, content = Es}]) ->
t_list(Es);
t_type([#xmlElement{name = nonempty_list, content = Es}]) ->
t_nonempty_list(Es);
+t_type([#xmlElement{name = map, content = Es}]) ->
+ t_map(Es);
t_type([#xmlElement{name = tuple, content = Es}]) ->
t_tuple(Es);
t_type([#xmlElement{name = 'fun', content = Es}]) ->
@@ -877,6 +894,19 @@ t_fun(Es) ->
["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es),
[") -> "] ++ t_utype(get_elem(type, Es))).
+t_map(Es) ->
+ Fs = get_elem(map_field, Es),
+ ["#{"] ++ seq(fun t_map_field/1, Fs, ["}"]).
+
+t_map_field(#xmlElement{content = [K,V]}=E) ->
+ KElem = t_utype_elem(K),
+ VElem = t_utype_elem(V),
+ AS = case get_attrval(assoc_type, E) of
+ "assoc" -> " => ";
+ "exact" -> " := "
+ end,
+ KElem ++ [AS] ++ VElem.
+
t_record(E, Es) ->
Name = ["#"] ++ t_type(get_elem(atom, Es)),
case get_elem(field, Es) of
@@ -956,9 +986,6 @@ get_text(Name, Es) ->
local_label(R) ->
"#" ++ R.
-xhtml(Title, CSS, Body) ->
- xhtml(Title, CSS, Body, "latin1").
-
xhtml(Title, CSS, Body, Encoding) ->
EncString = case Encoding of
"latin1" -> "ISO-8859-1";
@@ -988,27 +1015,6 @@ type(E, Ds) ->
xmerl:export_simple_content(t_utype_elem(E) ++ local_defs(Ds, Opts),
?HTML_EXPORT).
-package(E=#xmlElement{name = package, content = Es}, Options) ->
- Opts = init_opts(E, Options),
- Name = get_text(packageName, Es),
- Title = ["Package ", Name],
- Desc = get_content(description, Es),
-% ShortDesc = get_content(briefDescription, Desc),
- FullDesc = get_content(fullDescription, Desc),
- Body = ([?NL, {h1, [Title]}, ?NL]
-% ++ ShortDesc
- ++ copyright(Es)
- ++ deprecated(Es, "package")
- ++ version(Es)
- ++ since(Es)
- ++ authors(Es)
- ++ references(Es)
- ++ sees(Es)
- ++ todos(Es)
- ++ FullDesc),
- XML = xhtml(Title, stylesheet(Opts), Body),
- xmerl:export_simple(XML, ?HTML_EXPORT, []).
-
overview(E=#xmlElement{name = overview, content = Es}, Options) ->
Opts = init_opts(E, Options),
Title = [get_text(title, Es)],
@@ -1072,6 +1078,8 @@ ot_type([#xmlElement{name = nonempty_list, content = Es}]) ->
ot_nonempty_list(Es);
ot_type([#xmlElement{name = tuple, content = Es}]) ->
ot_tuple(Es);
+ot_type([#xmlElement{name = map, content = Es}]) ->
+ ot_map(Es);
ot_type([#xmlElement{name = 'fun', content = Es}]) ->
ot_fun(Es);
ot_type([#xmlElement{name = record, content = Es}]) ->
@@ -1085,8 +1093,8 @@ ot_var(E) ->
{var,0,list_to_atom(get_attrval(name, E))}.
ot_atom(E) ->
- {ok, [Atom], _} = erl_scan:string(get_attrval(value, E), 0),
- Atom.
+ {ok, [{atom,A,Name}], _} = erl_scan:string(get_attrval(value, E), 0),
+ {atom,erl_anno:line(A),Name}.
ot_integer(E) ->
{integer,0,list_to_integer(get_attrval(value, E))}.
@@ -1128,6 +1136,16 @@ ot_nonempty_list(Es) ->
ot_tuple(Es) ->
{type,0,tuple,[ot_utype_elem(E) || E <- Es]}.
+ot_map(Es) ->
+ {type,0,map,[ot_map_field(E) || E <- get_elem(map_field,Es)]}.
+
+ot_map_field(#xmlElement{content=[K,V]}=E) ->
+ A = case get_attrval(assoc_type, E) of
+ "assoc" -> map_field_assoc;
+ "exact" -> map_field_exact
+ end,
+ {type,0,A,[ot_utype_elem(K), ot_utype_elem(V)]}.
+
ot_fun(Es) ->
Range = ot_utype(get_elem(type, Es)),
Args = [ot_utype_elem(A) || A <- get_content(argtypes, Es)],
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index 276f48453e..dcc239f6b4 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -1,4 +1,3 @@
-%% -*- coding: utf-8 -*-
%% =====================================================================
%% This library is free software; you can redistribute it and/or modify
%% it under the terms of the GNU Lesser General Public License as
@@ -30,9 +29,9 @@
get_first_sentence/1, is_space/1, strip_space/1, parse_expr/2,
parse_contact/2, escape_uri/1, join_uri/2, is_relative_uri/1,
is_name/1, to_label/1, find_doc_dirs/0, find_sources/2,
- find_sources/3, find_file/3, try_subdir/2, unique/1,
- write_file/3, write_file/4, write_file/5, write_info_file/4,
- read_info_file/1, get_doc_env/1, get_doc_env/4, copy_file/2,
+ find_file/2, try_subdir/2, unique/1,
+ write_file/3, write_file/4, write_info_file/3,
+ read_info_file/1, get_doc_env/1, get_doc_env/3, copy_file/2,
uri_get/1, run_doclet/2, run_layout/2,
simplify_path/1, timestr/1, datestr/1, read_encoding/2]).
@@ -267,13 +266,6 @@ is_name_1([$_ | Cs]) ->
is_name_1([]) -> true;
is_name_1(_) -> false.
-to_atom(A) when is_atom(A) -> A;
-to_atom(S) when is_list(S) -> list_to_atom(S).
-
-to_list(A) when is_atom(A) -> atom_to_list(A);
-to_list(S) when is_list(S) -> S.
-
-
%% @private
unique([X | Xs]) -> [X | unique(Xs, X)];
unique([]) -> [].
@@ -675,7 +667,7 @@ simplify_path(P) ->
try_subdir(Dir, Subdir) ->
D = filename:join(Dir, Subdir),
case filelib:is_dir(D) of
- true -> D;
+ true -> D;
false -> Dir
end.
@@ -687,19 +679,10 @@ try_subdir(Dir, Subdir) ->
%% @private
write_file(Text, Dir, Name) ->
- write_file(Text, Dir, Name, '').
-
-%% @spec (Text::deep_string(), Dir::edoc:filename(),
-%% Name::edoc:filename(), Package::atom()|string()) -> ok
-%% @doc Like {@link write_file/3}, but adds path components to the target
-%% directory corresponding to the specified package.
-%% @private
+ write_file(Text, Dir, Name, [{encoding,latin1}]).
-write_file(Text, Dir, Name, Package) ->
- write_file(Text, Dir, Name, Package, [{encoding,latin1}]).
-
-write_file(Text, Dir, Name, Package, Options) ->
- File = filename:join([Dir, to_list(Package), Name]),
+write_file(Text, Dir, Name, Options) ->
+ File = filename:join([Dir, Name]),
ok = filelib:ensure_dir(File),
case file:open(File, [write] ++ Options) of
{ok, FD} ->
@@ -712,15 +695,14 @@ write_file(Text, Dir, Name, Package, Options) ->
end.
%% @private
-write_info_file(App, Packages, Modules, Dir) ->
- Ts = [{packages, Packages},
- {modules, Modules}],
+write_info_file(App, Modules, Dir) ->
+ Ts = [{modules, Modules}],
Ts1 = if App =:= ?NO_APP -> Ts;
true -> [{application, App} | Ts]
end,
S0 = [io_lib:fwrite("~p.\n", [T]) || T <- Ts1],
S = ["%% encoding: UTF-8\n" | S0],
- write_file(S, Dir, ?INFO_FILE, '', [{encoding,unicode}]).
+ write_file(S, Dir, ?INFO_FILE, [{encoding,unicode}]).
%% @spec (Name::edoc:filename()) -> {ok, string()} | {error, Reason}
%%
@@ -745,9 +727,8 @@ read_file(File) ->
info_file_data(Ts) ->
App = proplists:get_value(application, Ts, ?NO_APP),
- Ps = proplists:append_values(packages, Ts),
Ms = proplists:append_values(modules, Ts),
- {App, Ps, Ms}.
+ {App, Ms}.
%% Local file access - don't complain if file does not exist.
@@ -762,10 +743,10 @@ read_info_file(Dir) ->
{error, R} ->
R1 = file:format_error(R),
warning("could not read '~ts': ~ts.", [File, R1]),
- {?NO_APP, [], []}
- end;
+ {?NO_APP, []}
+ end;
false ->
- {?NO_APP, [], []}
+ {?NO_APP, []}
end.
%% URI access
@@ -777,7 +758,7 @@ uri_get_info_file(Base) ->
parse_info_file(Text, URI);
{error, Msg} ->
warning("could not read '~ts': ~ts.", [URI, Msg]),
- {?NO_APP, [], []}
+ {?NO_APP, []}
end.
parse_info_file(Text, Name) ->
@@ -786,10 +767,10 @@ parse_info_file(Text, Name) ->
info_file_data(Vs);
{error, eof} ->
warning("unexpected end of file in '~ts'.", [Name]),
- {?NO_APP, [], []};
+ {?NO_APP, []};
{error, {_Line,Module,R}} ->
warning("~ts: ~ts.", [Module:format_error(R), Name]),
- {?NO_APP, [], []}
+ {?NO_APP, []}
end.
parse_terms(Text) ->
@@ -816,82 +797,67 @@ parse_terms_1([], _As, _Vs) ->
%% ---------------------------------------------------------------------
-%% Source files and packages
+%% Source files
+%% @doc See {@link edoc:run/2} for a description of the options
+%% `subpackages', `source_suffix'.
%% @private
-find_sources(Path, Opts) ->
- find_sources(Path, "", Opts).
-%% @doc See {@link edoc:run/3} for a description of the options
-%% `subpackages', `source_suffix' and `exclude_packages'.
-%% @private
+%% NEW-OPTIONS: subpackages, source_suffix
+%% DEFER-OPTIONS: edoc:run/2
-%% NEW-OPTIONS: subpackages, source_suffix, exclude_packages
-%% DEFER-OPTIONS: edoc:run/3
-
-find_sources(Path, Pkg, Opts) ->
+find_sources(Path, Opts) ->
Rec = proplists:get_bool(subpackages, Opts),
Ext = proplists:get_value(source_suffix, Opts, ?DEFAULT_SOURCE_SUFFIX),
- find_sources(Path, Pkg, Rec, Ext, Opts).
+ find_sources(Path, Rec, Ext, Opts).
-find_sources(Path, Pkg, Rec, Ext, Opts) ->
- Skip = proplists:get_value(exclude_packages, Opts, []),
- lists:flatten(find_sources_1(Path, to_atom(Pkg), Rec, Ext, Skip)).
+find_sources(Path, Rec, Ext, _Opts) ->
+ lists:flatten(find_sources_1(Path, Rec, Ext)).
-find_sources_1([P | Ps], Pkg, Rec, Ext, Skip) ->
- Dir = filename:join(P, atom_to_list(Pkg)),
- Fs1 = find_sources_1(Ps, Pkg, Rec, Ext, Skip),
+find_sources_1([P | Ps], Rec, Ext) ->
+ Dir = P,
+ Fs1 = find_sources_1(Ps, Rec, Ext),
case filelib:is_dir(Dir) of
true ->
- [find_sources_2(Dir, Pkg, Rec, Ext, Skip) | Fs1];
+ [find_sources_2(Dir, Rec, Ext) | Fs1];
false ->
Fs1
end;
-find_sources_1([], _Pkg, _Rec, _Ext, _Skip) ->
+find_sources_1([], _Rec, _Ext) ->
[].
-find_sources_2(Dir, Pkg, Rec, Ext, Skip) ->
- case lists:member(Pkg, Skip) of
- false ->
- Es = list_dir(Dir, false), % just warn if listing fails
- Es1 = [{Pkg, E, Dir} || E <- Es, is_source_file(E, Ext)],
- case Rec of
+find_sources_2(Dir, Rec, Ext) ->
+ Es = list_dir(Dir, false), % just warn if listing fails
+ Es1 = [{E, Dir} || E <- Es, is_source_file(E, Ext)],
+ case Rec of
true ->
- [find_sources_3(Es, Dir, Pkg, Rec, Ext, Skip) | Es1];
+ [find_sources_3(Es, Dir, Rec, Ext) | Es1];
false ->
- Es1
- end;
- true ->
- []
- end.
+ Es1
+ end.
-find_sources_3(Es, Dir, Pkg, Rec, Ext, Skip) ->
+find_sources_3(Es, Dir, Rec, Ext) ->
[find_sources_2(filename:join(Dir, E),
- to_atom(join(Pkg, E)), Rec, Ext, Skip)
- || E <- Es, is_package_dir(E, Dir)].
-
-join('', E) -> E;
-join(Pkg, E) -> filename:join(Pkg, E).
+ Rec, Ext)
+ || E <- Es, is_source_dir(E, Dir)].
is_source_file(Name, Ext) ->
(filename:extension(Name) == Ext)
andalso is_name(filename:rootname(Name, Ext)).
-is_package_dir(Name, Dir) ->
- is_name(filename:rootname(filename:basename(Name)))
- andalso filelib:is_dir(filename:join(Dir, Name)).
+is_source_dir(Name, Dir) ->
+ filelib:is_dir(filename:join(Dir, Name)).
%% @private
-find_file([P | Ps], []=Pkg, Name) ->
- Pkg = [],
+find_file([P | Ps], Name) ->
File = filename:join(P, Name),
case filelib:is_file(File) of
true ->
- File;
+ File;
false ->
- find_file(Ps, Pkg, Name)
- end;
-find_file([], [], _Name) ->
+ find_file(Ps, Name)
+ end;
+find_file([], _Name) ->
"".
%% @private
@@ -910,7 +876,7 @@ find_doc_dirs([P0 | Ps]) ->
File = filename:join(Dir, ?INFO_FILE),
case filelib:is_file(File) of
true ->
- [Dir | find_doc_dirs(Ps)];
+ [Dir | find_doc_dirs(Ps)];
false ->
find_doc_dirs(Ps)
end;
@@ -922,24 +888,23 @@ find_doc_dirs([]) ->
%% implies that we use the default app-path.
%% NEW-OPTIONS: doc_path
-%% DEFER-OPTIONS: get_doc_env/4
+%% DEFER-OPTIONS: get_doc_env/3
-get_doc_links(App, Packages, Modules, Opts) ->
+get_doc_links(App, Modules, Opts) ->
Path = proplists:append_values(doc_path, Opts) ++ find_doc_dirs(),
Ds = [{P, uri_get_info_file(P)} || P <- Path],
- Ds1 = [{"", {App, Packages, Modules}} | Ds],
+ Ds1 = [{"", {App, Modules}} | Ds],
D = dict:new(),
- make_links(Ds1, D, D, D).
+ make_links(Ds1, D, D).
-make_links([{Dir, {App, Ps, Ms}} | Ds], A, P, M) ->
+make_links([{Dir, {App, Ms}} | Ds], A, M) ->
A1 = if App == ?NO_APP -> A;
true -> add_new(App, Dir, A)
end,
F = fun (K, D) -> add_new(K, Dir, D) end,
- P1 = lists:foldl(F, P, Ps),
M1 = lists:foldl(F, M, Ms),
- make_links(Ds, A1, P1, M1);
-make_links([], A, P, M) ->
+ make_links(Ds, A1, M1);
+make_links([], A, M) ->
F = fun (D) ->
fun (K) ->
case dict:find(K, D) of
@@ -948,7 +913,7 @@ make_links([], A, P, M) ->
end
end
end,
- {F(A), F(P), F(M)}.
+ {F(A), F(M)}.
add_new(K, V, D) ->
case dict:is_key(K, D) of
@@ -959,15 +924,14 @@ add_new(K, V, D) ->
end.
%% @spec (Options::proplist()) -> edoc_env()
-%% @equiv get_doc_env([], [], [], Opts)
+%% @equiv get_doc_env([], [], Opts)
%% @private
get_doc_env(Opts) ->
- get_doc_env([], [], [], Opts).
+ get_doc_env([], [], Opts).
-%% @spec (App, Packages, Modules, Options::proplist()) -> edoc_env()
+%% @spec (App, Modules, Options::proplist()) -> edoc_env()
%% App = [] | atom()
-%% Packages = [atom()]
%% Modules = [atom()]
%% proplist() = [term()]
%%
@@ -976,7 +940,7 @@ get_doc_env(Opts) ->
%% generating references. The data representation is not documented.
%%
%% @doc Creates an environment data structure used by parts of EDoc for
-%% generating references, etc. See {@link edoc:run/3} for a description
+%% generating references, etc. See {@link edoc:run/2} for a description
%% of the options `file_suffix', `app_default' and `doc_path'.
%%
%% @see edoc_extract:source/4
@@ -984,19 +948,17 @@ get_doc_env(Opts) ->
%% NEW-OPTIONS: file_suffix, app_default
%% INHERIT-OPTIONS: get_doc_links/4
-%% DEFER-OPTIONS: edoc:run/3
+%% DEFER-OPTIONS: edoc:run/2
-get_doc_env(App, Packages, Modules, Opts) ->
+get_doc_env(App, Modules, Opts) ->
Suffix = proplists:get_value(file_suffix, Opts,
?DEFAULT_FILE_SUFFIX),
AppDefault = proplists:get_value(app_default, Opts, ?APP_DEFAULT),
Includes = proplists:append_values(includes, Opts),
- {A, P, M} = get_doc_links(App, Packages, Modules, Opts),
+ {A, M} = get_doc_links(App, Modules, Opts),
#env{file_suffix = Suffix,
- package_summary = ?PACKAGE_SUMMARY ++ Suffix,
apps = A,
- packages = P,
modules = M,
app_default = AppDefault,
includes = Includes
@@ -1005,10 +967,10 @@ get_doc_env(App, Packages, Modules, Opts) ->
%% ---------------------------------------------------------------------
%% Plug-in modules
-%% @doc See {@link edoc:run/3} for a description of the `doclet' option.
+%% @doc See {@link edoc:run/2} for a description of the `doclet' option.
%% NEW-OPTIONS: doclet
-%% DEFER-OPTIONS: edoc:run/3
+%% DEFER-OPTIONS: edoc:run/2
%% @private
run_doclet(Fun, Opts) ->
@@ -1033,7 +995,7 @@ run_plugin(Name, Key, Default, Fun, Opts) when is_atom(Name) ->
{ok, Value} ->
Value;
R ->
- report("error in ~ts '~w': ~W.", [Name, Module, R, 20]),
+ report("error in ~ts '~w': ~P.", [Name, Module, R, 20]),
exit(error)
end.
@@ -1050,7 +1012,7 @@ get_plugin(Key, Default, Opts) ->
%% ---------------------------------------------------------------------
%% Error handling
--type line() :: erl_scan:line().
+-type line() :: erl_anno:line().
-type err() :: 'eof'
| {'missing', char()}
| {line(), atom(), string()}
diff --git a/lib/edoc/src/edoc_macros.erl b/lib/edoc/src/edoc_macros.erl
index 8efbfd00c7..e1a54d5090 100644
--- a/lib/edoc/src/edoc_macros.erl
+++ b/lib/edoc/src/edoc_macros.erl
@@ -40,10 +40,6 @@ std_macros(Env) ->
true -> [{module, atom_to_list(Env#env.module)}]
end
++
- if Env#env.package =:= [] -> [];
- true -> [{package, atom_to_list(Env#env.package)}]
- end
- ++
[{date, fun date_macro/3},
{docRoot, Env#env.root},
{link, fun link_macro/3},
@@ -315,7 +311,7 @@ macro_content([C | Cs], As, L, N) ->
macro_content([], _As, _L, _N) ->
throw('end').
--type line() :: erl_scan:line().
+-type line() :: erl_anno:line().
-type err() :: 'unterminated_macro'
| 'macro_name'
| {'macro_name', string()}
diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl
index a20f152f34..68a3439f10 100644
--- a/lib/edoc/src/edoc_parser.yrl
+++ b/lib/edoc/src/edoc_parser.yrl
@@ -1,4 +1,3 @@
-%% -*- coding: utf-8 -*-
%% ========================== -*-Erlang-*- =============================
%% EDoc type specification grammar for the Yecc parser generator,
%% adapted from Sven-Olof Nyström's type specification parser.
@@ -29,15 +28,16 @@
Nonterminals
start spec func_type utype_list utype_tuple utypes utype ptypes ptype
nutype function_name where_defs defs defs2 def typedef etype
-throws qname ref aref mref lref pref var_list vars fields field
+throws qname ref aref mref lref var_list vars fields field
+utype_map utype_map_fields utype_map_field
futype_list bin_base_type bin_unit_type.
Terminals
atom float integer var an_var string start_spec start_typedef start_throws
start_ref
-'(' ')' ',' '.' '->' '{' '}' '[' ']' '|' '+' ':' '::' '=' '/' '//' '*'
-'#' 'where' '<<' '>>' '..' '...'.
+'(' ')' ',' '.' '=>' ':=' '->' '{' '}' '[' ']' '|' '+' ':' '::' '=' '/' '//'
+'*' '#' 'where' '<<' '>>' '..' '...'.
Rootsymbol start.
@@ -70,6 +70,19 @@ utype_list -> '(' utypes ')' : {lists:reverse('$2'), tok_line('$1')}.
futype_list -> utype_list : '$1'.
futype_list -> '(' '...' ')' : {[#t_var{name = '...'}], tok_line('$1')}.
+utype_map -> '#' '{' utype_map_fields '}' : lists:reverse('$3').
+
+utype_map_fields -> '$empty' : [].
+utype_map_fields -> utype_map_field : ['$1'].
+utype_map_fields -> utype_map_fields ',' utype_map_field : ['$3' | '$1'].
+
+utype_map_field -> utype '=>' utype : #t_map_field{assoc_type = assoc,
+ k_type = '$1',
+ v_type = '$3'}.
+utype_map_field -> utype ':=' utype : #t_map_field{assoc_type = exact,
+ k_type = '$1',
+ v_type = '$3'}.
+
utype_tuple -> '{' utypes '}' : lists:reverse('$2').
%% Produced in reverse order.
@@ -92,9 +105,10 @@ ptype -> var : #t_var{name = tok_val('$1')}.
ptype -> atom : #t_atom{val = tok_val('$1')}.
ptype -> integer: #t_integer{val = tok_val('$1')}.
ptype -> integer '..' integer: #t_integer_range{from = tok_val('$1'),
- to = tok_val('$3')}.
+ to = tok_val('$3')}.
ptype -> float: #t_float{val = tok_val('$1')}.
ptype -> utype_tuple : #t_tuple{types = '$1'}.
+ptype -> utype_map : #t_map{types = '$1'}.
ptype -> '[' ']' : #t_nil{}.
ptype -> '[' utype ']' : #t_list{type = '$2'}.
ptype -> '[' utype ',' '...' ']' : #t_nonempty_list{type = '$2'}.
@@ -198,14 +212,11 @@ typedef -> atom var_list '=' utype where_defs:
ref -> aref: '$1'.
ref -> mref: '$1'.
ref -> lref: '$1'.
-ref -> pref: '$1'.
aref -> '//' atom:
edoc_refs:app(tok_val('$2')).
aref -> '//' atom '/' mref:
edoc_refs:app(tok_val('$2'), '$4').
-aref -> '//' atom '/' pref:
- edoc_refs:app(tok_val('$2'), '$4').
mref -> qname ':' atom '/' integer:
edoc_refs:function(qname('$1'), tok_val('$3'), tok_val('$5')).
@@ -214,9 +225,6 @@ mref -> qname ':' atom '(' ')':
mref -> qname:
edoc_refs:module(qname('$1')).
-pref -> qname '.' '*':
- edoc_refs:package(qname('$1')).
-
lref -> atom '/' integer:
edoc_refs:function(tok_val('$1'), tok_val('$3')).
lref -> atom '(' ')':
@@ -335,7 +343,7 @@ build_def(S, P, As, T) ->
args = lists:reverse(As)},
type = T};
false ->
- return_error(element(2, P), "variable expected after '('")
+ return_error(tok_line(P), "variable expected after '('")
end.
all_vars([#t_var{} | As]) ->
@@ -390,7 +398,7 @@ parse_typedef_1(S, L) ->
%% @doc Parses a <a
%% href="overview-summary.html#References">reference</a> to a module,
-%% package, function, type, or application
+%% function, type, or application
parse_ref(S, L) ->
case edoc_scanner:string(S, L) of
@@ -449,7 +457,7 @@ parse_throws(S, L) ->
%% ---------------------------------------------------------------------
--spec throw_error(term(), erl_scan:line()) -> no_return().
+-spec throw_error(term(), erl_anno:line()) -> no_return().
throw_error({parse_spec, E}, L) ->
throw_error({"specification", E}, L);
@@ -463,3 +471,5 @@ throw_error(parse_param, L) ->
throw({error, L, "missing parameter name"});
throw_error({Where, E}, L) when is_list(Where) ->
throw({error,L,{"unknown error parsing ~ts: ~P.",[Where,E,15]}}).
+
+%% vim: ft=erlang
diff --git a/lib/edoc/src/edoc_refs.erl b/lib/edoc/src/edoc_refs.erl
index ea439490ed..b9a9391053 100644
--- a/lib/edoc/src/edoc_refs.erl
+++ b/lib/edoc/src/edoc_refs.erl
@@ -27,10 +27,9 @@
-module(edoc_refs).
--export([app/1, app/2, package/1, module/1, module/2, module/3,
+-export([app/1, app/2, module/1, module/2, module/3,
function/2, function/3, function/4, type/1, type/2, type/3,
- to_string/1, to_label/1, get_uri/2, is_top/2,
- relative_module_path/2, relative_package_path/2]).
+ to_string/1, to_label/1, get_uri/2, is_top/2]).
-import(edoc_lib, [join_uri/2, escape_uri/1]).
@@ -56,9 +55,6 @@ module(M, Ref) ->
module(App, M, Ref) ->
app(App, module(M, Ref)).
-package(P) ->
- {package, P}.
-
function(F, A) ->
{function, F, A}.
@@ -88,8 +84,6 @@ to_string({module, M}) ->
atom_to_list(M) ;
to_string({module, M, Ref}) ->
atom_to_list(M) ++ ":" ++ to_string(Ref);
-to_string({package, P}) ->
- atom_to_list(P) ++ ".*";
to_string({function, F, A}) ->
atom_to_list(F) ++ "/" ++ integer_to_list(A);
to_string({type, T}) ->
@@ -111,24 +105,19 @@ get_uri({module, M, Ref}, Env) ->
module_ref(M, Env) ++ "#" ++ to_label(Ref);
get_uri({module, M}, Env) ->
module_ref(M, Env);
-get_uri({package, P}, Env) ->
- package_ref(P, Env);
get_uri(Ref, _Env) ->
"#" ++ to_label(Ref).
abs_uri({module, M}, Env) ->
module_absref(M, Env);
abs_uri({module, M, Ref}, Env) ->
- module_absref(M, Env) ++ "#" ++ to_label(Ref);
-abs_uri({package, P}, Env) ->
- package_absref(P, Env).
+ module_absref(M, Env) ++ "#" ++ to_label(Ref).
module_ref(M, Env) ->
case (Env#env.modules)(M) of
"" ->
File = atom_to_list(M) ++ Env#env.file_suffix,
- Path = relative_module_path(M, Env#env.package),
- join_uri(Path, escape_uri(File));
+ escape_uri(File);
Base ->
join_uri(Base, module_absref(M, Env))
end.
@@ -136,19 +125,6 @@ module_ref(M, Env) ->
module_absref(M, Env) ->
escape_uri(atom_to_list(M)) ++ escape_uri(Env#env.file_suffix).
-package_ref(P, Env) ->
- case (Env#env.packages)(P) of
- "" ->
- join_uri(relative_package_path(P, Env#env.package),
- escape_uri(Env#env.package_summary));
- Base ->
- join_uri(Base, package_absref(P, Env))
- end.
-
-package_absref(P, Env) ->
- join_uri(escape_uri(atom_to_list(P)),
- escape_uri(Env#env.package_summary)).
-
app_ref(A, Env) ->
case (Env#env.apps)(A) of
"" ->
@@ -166,43 +142,3 @@ is_top({app, _App}, _Env) ->
is_top(_Ref, _Env) ->
false.
-%% Each segment of a path must be separately escaped before joining.
-
-join_segments([S]) ->
- escape_uri(S);
-join_segments([S | Ss]) ->
- join_uri(escape_uri(S), join_segments(Ss)).
-
-%% 'From' is always the "current package" here:
-
-%% The empty string is returned if the To module has only one segment,
-%% implying a local reference.
-
-relative_module_path(_To, _From) ->
- "".
-
-relative_package_path(To, From) ->
- relative_path([atom_to_list(To)], [atom_to_list(From)]).
-
-%% This takes two lists of path segments (From, To). Note that an empty
-%% string will be returned if the paths are the same. Empty leading
-%% segments are stripped from both paths.
-
-relative_path(Ts, ["" | Fs]) ->
- relative_path(Ts, Fs);
-relative_path(["" | Ts], Fs) ->
- relative_path(Ts, Fs);
-relative_path(Ts, Fs) ->
- relative_path_1(Ts, Fs).
-
-relative_path_1([T | Ts], [F | Fs]) when F == T ->
- relative_path_1(Ts, Fs);
-relative_path_1(Ts, Fs) ->
- relative_path_2(Fs, Ts).
-
-relative_path_2([_F | Fs], Ts) ->
- relative_path_2(Fs, [".." | Ts]);
-relative_path_2([], []) ->
- "";
-relative_path_2([], Ts) ->
- join_segments(Ts).
diff --git a/lib/edoc/src/edoc_run.erl b/lib/edoc/src/edoc_run.erl
index b5a1ef713d..261a649c70 100644
--- a/lib/edoc/src/edoc_run.erl
+++ b/lib/edoc/src/edoc_run.erl
@@ -17,7 +17,7 @@
%% @copyright 2003 Richard Carlsson
%% @author Richard Carlsson <[email protected]>
%% @see edoc
-%% @end
+%% @end
%% =====================================================================
%% @doc Interface for calling EDoc from Erlang startup options.
@@ -38,12 +38,14 @@
-module(edoc_run).
--export([file/1, application/1, packages/1, files/1, toc/1]).
+-export([file/1, application/1, files/1, toc/1]).
-compile({no_auto_import,[error/1]}).
-import(edoc_report, [report/2, error/1]).
+-type args() :: [string()].
+
%% @spec application([string()]) -> none()
%%
@@ -58,6 +60,7 @@
%% automatically terminated when the call has completed, signalling
%% success or failure to the operating system.
+-spec application(args()) -> no_return().
application(Args) ->
F = fun () ->
case parse_args(Args) of
@@ -81,6 +84,7 @@ application(Args) ->
%% automatically terminated when the call has completed, signalling
%% success or failure to the operating system.
+-spec files(args()) -> no_return().
files(Args) ->
F = fun () ->
case parse_args(Args) of
@@ -92,29 +96,8 @@ files(Args) ->
end,
run(F).
-%% @spec packages([string()]) -> none()
-%%
-%% @doc Calls {@link edoc:application/2} with the corresponding
-%% arguments. The strings in the list are parsed as Erlang constant
-%% terms. The list can be either `[Packages]' or `[Packages, Options]'.
-%% In the first case {@link edoc:application/1} is called instead.
-%%
-%% The function call never returns; instead, the emulator is
-%% automatically terminated when the call has completed, signalling
-%% success or failure to the operating system.
-
-packages(Args) ->
- F = fun () ->
- case parse_args(Args) of
- [Packages] -> edoc:packages(Packages);
- [Packages, Opts] -> edoc:packages(Packages, Opts);
- _ ->
- invalid_args("edoc_run:packages/1", Args)
- end
- end,
- run(F).
-
%% @hidden Not official yet
+-spec toc(args()) -> no_return().
toc(Args) ->
F = fun () ->
case parse_args(Args) of
@@ -131,8 +114,8 @@ toc(Args) ->
%%
%% @deprecated This is part of the old interface to EDoc and is mainly
%% kept for backwards compatibility. The preferred way of generating
-%% documentation is through one of the functions {@link application/1},
-%% {@link packages/1} and {@link files/1}.
+%% documentation is through one of the functions {@link application/1}
+%% and {@link files/1}.
%%
%% @doc Calls {@link edoc:file/2} with the corresponding arguments. The
%% strings in the list are parsed as Erlang constant terms. The list can
@@ -148,6 +131,7 @@ toc(Args) ->
%% automatically terminated when the call has completed, signalling
%% success or failure to the operating system.
+-spec file(args()) -> no_return().
file(Args) ->
F = fun () ->
case parse_args(Args) of
@@ -159,8 +143,7 @@ file(Args) ->
end,
run(F).
--spec invalid_args(string(), list()) -> no_return().
-
+-spec invalid_args(string(), args()) -> no_return().
invalid_args(Where, Args) ->
report("invalid arguments to ~ts: ~w.", [Where, Args]),
shutdown_error().
@@ -191,10 +174,12 @@ wait_init() ->
%% When and if a function init:stop/1 becomes generally available, we
%% can use that instead of delay-and-pray when there is an error.
+-spec shutdown_ok() -> no_return().
shutdown_ok() ->
%% shut down emulator nicely, signalling "normal termination"
init:stop().
+-spec shutdown_error() -> no_return().
shutdown_error() ->
%% delay 1 second to allow I/O to finish
receive after 1000 -> ok end,
diff --git a/lib/edoc/src/edoc_scanner.erl b/lib/edoc/src/edoc_scanner.erl
index 754fcef643..f1d5e1d4b9 100644
--- a/lib/edoc/src/edoc_scanner.erl
+++ b/lib/edoc/src/edoc_scanner.erl
@@ -1,12 +1,13 @@
-%% ``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 via the world wide web at http://www.erlang.org/.
+%% ``Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
%%
-%% 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
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings
@@ -137,12 +138,16 @@ scan1([$"|Cs0], Toks, Pos) -> % String
scan_error({illegal, string}, Pos)
end;
%% Punctuation characters and operators, first recognise multiples.
+scan1([$=,$>|Cs], Toks, Pos) ->
+ scan1(Cs, [{'=>',Pos}|Toks], Pos);
scan1([$<,$<|Cs], Toks, Pos) ->
scan1(Cs, [{'<<',Pos}|Toks], Pos);
scan1([$>,$>|Cs], Toks, Pos) ->
scan1(Cs, [{'>>',Pos}|Toks], Pos);
scan1([$-,$>|Cs], Toks, Pos) ->
scan1(Cs, [{'->',Pos}|Toks], Pos);
+scan1([$:,$=|Cs], Toks, Pos) ->
+ scan1(Cs, [{':=',Pos}|Toks], Pos);
scan1([$:,$:|Cs], Toks, Pos) ->
scan1(Cs, [{'::',Pos}|Toks], Pos);
scan1([$/,$/|Cs], Toks, Pos) ->
diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl
index 5acf8ac0d5..c15dfd328f 100644
--- a/lib/edoc/src/edoc_specs.erl
+++ b/lib/edoc/src/edoc_specs.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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/.
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
%%
-%% 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.
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
%%
%% %CopyrightEnd%
@@ -35,20 +36,21 @@
%% Exported functions
%%
--spec type(Form::syntaxTree(), TypeDocs::dict()) -> #tag{}.
+-spec type(Form::syntaxTree(), TypeDocs::dict:dict()) -> #tag{}.
%% @doc Convert an Erlang type to EDoc representation.
%% TypeDocs is a dict of {Name, Doc}.
%% Note: #t_typedef.name is set to {record, R} for record types.
type(Form, TypeDocs) ->
- {Name, Data0} = erl_syntax_lib:analyze_wild_attribute(Form),
- type = tag(Name),
+ {Name, Data0} = analyze_type_attribute(Form),
{TypeName, Type, Args, Doc} =
case Data0 of
- {{record, R}, Fs, []} ->
+ {R, Fs} ->
+ record = Name,
L = erl_syntax:get_pos(Form),
{{record, R}, {type, L, record, [{atom,L,R} | Fs]}, [], ""};
{N,T,As} ->
+ type = tag(Name),
Doc0 =
case dict:find({N, length(As)}, TypeDocs) of
{ok, Doc1} ->
@@ -58,7 +60,7 @@ type(Form, TypeDocs) ->
end,
{#t_name{name = N}, T, As, Doc0}
end,
- #tag{name = type, line = element(2, Type),
+ #tag{name = type, line = get_line(element(2, Type)),
origin = code,
data = {#t_typedef{name = TypeName,
args = d2e(Args),
@@ -71,7 +73,7 @@ type(Form, TypeDocs) ->
spec(Form, Clause) ->
{Name, _Arity, TypeSpecs} = get_spec(Form),
TypeSpec = lists:nth(Clause, TypeSpecs),
- #tag{name = spec, line = element(2, TypeSpec),
+ #tag{name = spec, line = get_line(element(2, TypeSpec)),
origin = code,
data = aspec(d2e(TypeSpec), Name)}.
@@ -83,12 +85,12 @@ dummy_spec(Form) ->
{#t_name{name = Name}, Arity, TypeSpecs} = get_spec(Form),
As = string:join(lists:duplicate(Arity, "_X"), ","),
S = lists:flatten(io_lib:format("~p(~s) -> true\n", [Name, As])),
- #tag{name = spec, line = element(2, hd(TypeSpecs)),
+ #tag{name = spec, line = get_line(element(2, hd(TypeSpecs))),
origin = code, data = S}.
-spec docs(Forms::[syntaxTree()],
CommentFun :: fun( ([syntaxTree()], Line :: term()) -> #tag{} ))
- -> dict().
+ -> dict:dict().
%% @doc Find comments after -type/-opaque declarations.
%% Postcomments "inside" the type are skipped.
@@ -140,7 +142,7 @@ find_type_docs([F | Fs], Cs, Fun) ->
%% Postcomments before the dot after the typespec are ignored.
C2 = [C1 | [C ||
C <- erl_syntax:get_postcomments(F),
- get_line(erl_syntax:get_pos(C)) >= LastTypeLine]],
+ erl_syntax:get_pos(C) >= LastTypeLine]],
C3 = collect_comments(Fs, LastTypeLine),
#tag{data = Doc0} = Fun(lists:reverse(C2 ++ C3), LastTypeLine),
case strip(Doc0) of % Strip away "f(). \n"
@@ -157,7 +159,7 @@ find_type_docs([F | Fs], Cs, Fun) ->
collect_comments([], _Line) ->
[];
collect_comments([F | Fs], Line) ->
- L1 = get_line(erl_syntax:get_pos(F)),
+ L1 = erl_syntax:get_pos(F),
if
L1 =:= Line + 1;
L1 =:= Line -> % a separate postcomment
@@ -187,32 +189,29 @@ strip([_ | S]) ->
%% Find the type name and the greatest line number of a type spec.
%% Should use syntax_tools but this has to do for now.
get_name_and_last_line(F) ->
- {Name, Data} = erl_syntax_lib:analyze_wild_attribute(F),
+ {Name, Data} = analyze_type_attribute(F),
type = edoc_specs:tag(Name),
Attr = {attribute, erl_syntax:get_pos(F), Name, Data},
- Ref = make_ref(),
- Fun = fun(L) -> {Ref, get_line(L)} end,
+ Fun = fun(A) ->
+ Line = get_line(A),
+ case get('$max_line') of
+ Max when Max < Line ->
+ _ = put('$max_line', Line);
+ _ ->
+ ok
+ end
+ end,
+ undefined = put('$max_line', 0),
+ _ = erl_parse:map_anno(Fun, Attr),
+ Line = erase('$max_line'),
TypeName = case Data of
{N, _T, As} when is_atom(N) -> % skip records
{N, length(As)}
end,
- Line = gll(erl_lint:modify_line(Attr, Fun), Ref),
{TypeName, Line}.
-gll({Ref, Line}, Ref) ->
- Line;
-gll([], _Ref) ->
- 0;
-gll(List, Ref) when is_list(List) ->
- lists:max([gll(E, Ref) || E <- List]);
-gll(Tuple, Ref) when is_tuple(Tuple) ->
- gll(tuple_to_list(Tuple), Ref);
-gll(_, _) ->
- 0.
-
-get_line(Pos) ->
- {line, Line} = erl_scan:attributes_info(Pos, line),
- Line.
+get_line(Anno) ->
+ erl_anno:line(Anno).
%% Collect all Erlang types. Types in comments (@type) shadow Erlang
%% types (-spec/-opaque).
@@ -231,6 +230,7 @@ get_all_tags(Es) ->
%% Turns an opaque type into an abstract datatype.
%% Note: top level annotation is ignored.
opaque2abstr(opaque, _T) -> undefined;
+opaque2abstr(record, T) -> T;
opaque2abstr(type, T) -> T.
%% Replaces the parameters extracted from the source (by
@@ -272,12 +272,8 @@ parms([], []) ->
parms([A | As], [D | Ds]) ->
[param(A, D) | parms(As, Ds)].
-param(#t_list{type = Type}, Default) ->
- param(Type, Default);
param(#t_paren{type = Type}, Default) ->
param(Type, Default);
-param(#t_nonempty_list{type = Type}, Default) ->
- param(Type, Default);
param(#t_record{name = #t_atom{val = Name}}, _Default) ->
list_to_atom(capitalize(atom_to_list(Name)));
param(T, Default) ->
@@ -298,47 +294,54 @@ arg_name([A | As], Default) ->
is_name(A) ->
is_atom(A).
-d2e({ann_type,_,[V, T0]}) ->
+d2e(T) ->
+ d2e(T, 0).
+
+d2e({ann_type,_,[V, T0]}, Prec) ->
%% Note: the -spec/-type syntax allows annotations everywhere, but
%% EDoc does not. The fact that the annotation is added to the
%% type here does not necessarily mean that it will be used by the
%% layout module.
- T = d2e(T0),
- ?add_t_ann(T, element(3, V));
-d2e({remote_type,_,[{atom,_,M},{atom,_,F},Ts0]}) ->
+ {_L,P,R} = erl_parse:type_inop_prec('::'),
+ T1 = d2e(T0, R),
+ T = ?add_t_ann(T1, element(3, V)),
+ maybe_paren(P, Prec, T); % the only necessary call to maybe_paren()
+d2e({remote_type,_,[{atom,_,M},{atom,_,F},Ts0]}, _Prec) ->
Ts = d2e(Ts0),
typevar_anno(#t_type{name = #t_name{module = M, name = F}, args = Ts}, Ts);
-d2e({type,_,'fun',[{type,_,product,As0},Ran0]}) ->
+d2e({type,_,'fun',[{type,_,product,As0},Ran0]}, _Prec) ->
Ts = [Ran|As] = d2e([Ran0|As0]),
%% Assume that the linter has checked type variables.
typevar_anno(#t_fun{args = As, range = Ran}, Ts);
-d2e({type,_,'fun',[A0={type,_,any},Ran0]}) ->
+d2e({type,_,'fun',[A0={type,_,any},Ran0]}, _Prec) ->
Ts = [A, Ran] = d2e([A0, Ran0]),
typevar_anno(#t_fun{args = [A], range = Ran}, Ts);
-d2e({type,_,'fun',[]}) ->
+d2e({type,_,'fun',[]}, _Prec) ->
#t_type{name = #t_name{name = function}, args = []};
-d2e({type,_,any}) ->
+d2e({type,_,any}, _Prec) ->
#t_var{name = '...'}; % Kludge... not a type variable!
-d2e({type,_,nil,[]}) ->
+d2e({type,_,nil,[]}, _Prec) ->
#t_nil{};
-d2e({paren_type,_,[T]}) ->
- #t_paren{type = d2e(T)};
-d2e({type,_,list,[T0]}) ->
+d2e({paren_type,_,[T]}, Prec) ->
+ d2e(T, Prec);
+d2e({type,_,list,[T0]}, _Prec) ->
T = d2e(T0),
typevar_anno(#t_list{type = T}, [T]);
-d2e({type,_,nonempty_list,[T0]}) ->
+d2e({type,_,nonempty_list,[T0]}, _Prec) ->
T = d2e(T0),
typevar_anno(#t_nonempty_list{type = T}, [T]);
-d2e({type,_,bounded_fun,[T,Gs]}) ->
+d2e({type,_,bounded_fun,[T,Gs]}, _Prec) ->
[F0|Defs] = d2e([T|Gs]),
F = ?set_t_ann(F0, lists:keydelete(type_variables, 1, ?t_ann(F0))),
%% Assume that the linter has checked type variables.
#t_spec{type = typevar_anno(F, [F0]), defs = Defs};
-d2e({type,_,range,[V1,V2]}) ->
+d2e({type,_,range,[V1,V2]}, Prec) ->
+ {_L,P,_R} = erl_parse:type_inop_prec('..'),
{integer,_,I1} = erl_eval:partial_eval(V1),
{integer,_,I2} = erl_eval:partial_eval(V2),
- #t_integer_range{from = I1, to = I2};
-d2e({type,_,constraint,[Sub,Ts0]}) ->
+ T0 = #t_integer_range{from = I1, to = I2},
+ maybe_paren(P, Prec, T0);
+d2e({type,_,constraint,[Sub,Ts0]}, _Prec) ->
case {Sub,Ts0} of
{{atom,_,is_subtype},[{var,_,N},T0]} ->
Ts = [T] = d2e([T0]),
@@ -348,41 +351,62 @@ d2e({type,_,constraint,[Sub,Ts0]}) ->
Ts = [ST,T] = d2e([ST0,T0]),
#t_def{name = ST, type = typevar_anno(T, Ts)};
_ ->
- throw_error(element(2, Sub), "cannot handle guard", [])
+ throw_error(get_line(element(2, Sub)), "cannot handle guard", [])
end;
-d2e({type,_,union,Ts0}) ->
- Ts = d2e(Ts0),
- typevar_anno(#t_union{types = Ts}, Ts);
-d2e({type,_,tuple,any}) ->
+d2e({type,_,union,Ts0}, Prec) ->
+ {_L,P,R} = erl_parse:type_inop_prec('|'),
+ Ts = d2e(Ts0, R),
+ T = maybe_paren(P, Prec, #t_union{types = Ts}),
+ typevar_anno(T, Ts);
+d2e({type,_,tuple,any}, _Prec) ->
#t_type{name = #t_name{name = tuple}, args = []};
-d2e({type,_,binary,[Base,Unit]}) ->
- #t_binary{base_size = element(3, Base),
- unit_size = element(3, Unit)};
-d2e({type,_,tuple,Ts0}) ->
+d2e({type,_,binary,[Base,Unit]}, _Prec) ->
+ {integer,_,B} = erl_eval:partial_eval(Base),
+ {integer,_,U} = erl_eval:partial_eval(Unit),
+ #t_binary{base_size = B, unit_size = U};
+d2e({type,_,map,any}, _Prec) ->
+ #t_map{types = []};
+d2e({type,_,map,Es}, _Prec) ->
+ #t_map{types = d2e(Es) };
+d2e({type,_,map_field_assoc,[K,V]}, Prec) ->
+ T = #t_map_field{assoc_type = assoc, k_type = d2e(K), v_type=d2e(V) },
+ {P,_R} = erl_parse:type_preop_prec('#'),
+ maybe_paren(P, Prec, T);
+d2e({type,_,map_field_exact,[K,V]}, Prec) ->
+ T = #t_map_field{assoc_type = exact, k_type = d2e(K), v_type=d2e(V) },
+ {P,_R} = erl_parse:type_preop_prec('#'),
+ maybe_paren(P, Prec, T);
+d2e({type,_,tuple,Ts0}, _Prec) ->
Ts = d2e(Ts0),
typevar_anno(#t_tuple{types = Ts}, Ts);
-d2e({type,_,record,[Name|Fs0]}) ->
+d2e({type,_,record,[Name|Fs0]}, Prec) ->
Atom = #t_atom{val = element(3, Name)},
Fs = d2e(Fs0),
- typevar_anno(#t_record{name = Atom, fields = Fs}, Fs);
-d2e({type,_,field_type,[Name,Type0]}) ->
- Type = d2e(Type0),
- typevar_anno(#t_field{name = #t_atom{val = element(3, Name)}, type = Type},
- [Type]);
-d2e({typed_record_field,{record_field,L,Name},Type}) ->
- d2e({type,L,field_type,[Name,Type]});
-d2e({typed_record_field,{record_field,L,Name,_E},Type}) ->
- d2e({type,L,field_type,[Name,Type]});
-d2e({record_field,L,_Name,_E}=F) ->
- d2e({typed_record_field,F,{type,L,any,[]}}); % Maybe skip...
-d2e({record_field,L,_Name}=F) ->
- d2e({typed_record_field,F,{type,L,any,[]}}); % Maybe skip...
-d2e({type,_,Name,Types0}) ->
+ {P,_R} = erl_parse:type_preop_prec('#'),
+ T = maybe_paren(P, Prec, #t_record{name = Atom, fields = Fs}),
+ typevar_anno(T, Fs);
+d2e({type,_,field_type,[Name,Type0]}, Prec) ->
+ {_L,P,R} = erl_parse:type_inop_prec('::'),
+ Type = maybe_paren(P, Prec, d2e(Type0, R)),
+ T = #t_field{name = #t_atom{val = element(3, Name)}, type = Type},
+ typevar_anno(T, [Type]);
+d2e({typed_record_field,{record_field,L,Name},Type}, Prec) ->
+ d2e({type,L,field_type,[Name,Type]}, Prec);
+d2e({typed_record_field,{record_field,L,Name,_E},Type}, Prec) ->
+ d2e({type,L,field_type,[Name,Type]}, Prec);
+d2e({record_field,L,_Name,_E}=F, Prec) ->
+ d2e({typed_record_field,F,{type,L,any,[]}}, Prec); % Maybe skip...
+d2e({record_field,L,_Name}=F, Prec) ->
+ d2e({typed_record_field,F,{type,L,any,[]}}, Prec); % Maybe skip...
+d2e({type,_,Name,Types0}, _Prec) ->
Types = d2e(Types0),
typevar_anno(#t_type{name = #t_name{name = Name}, args = Types}, Types);
-d2e({var,_,'_'}) ->
+d2e({user_type,_,Name,Types0}, _Prec) ->
+ Types = d2e(Types0),
+ typevar_anno(#t_type{name = #t_name{name = Name}, args = Types}, Types);
+d2e({var,_,'_'}, _Prec) ->
#t_type{name = #t_name{name = ?TOP_TYPE}};
-d2e({var,_,TypeName}) ->
+d2e({var,_,TypeName}, _Prec) ->
TypeVar = ordsets:from_list([TypeName]),
T = #t_var{name = TypeName},
%% Annotate type variables with the name of the variable.
@@ -390,13 +414,13 @@ d2e({var,_,TypeName}) ->
%% from using the argument name from the source or to invent a new name.
T1 = ?add_t_ann(T, {type_variables, TypeVar}),
?add_t_ann(T1, TypeName);
-d2e(L) when is_list(L) ->
- [d2e(T) || T <- L];
-d2e({atom,_,A}) ->
+d2e(L, Prec) when is_list(L) ->
+ [d2e(T, Prec) || T <- L];
+d2e({atom,_,A}, _Prec) ->
#t_atom{val = A};
-d2e(undefined = U) -> % opaque
+d2e(undefined = U, _Prec) -> % opaque
U;
-d2e(Expr) ->
+d2e(Expr, _Prec) ->
{integer,_,I} = erl_eval:partial_eval(Expr),
#t_integer{val = I}.
@@ -414,6 +438,11 @@ typevars(Ts) ->
get_typevars(Ts) ->
[Vs || T <- Ts, T =/= undefined, {type_variables, Vs} <- ?t_ann(T)].
+maybe_paren(P, Prec, T) when P < Prec ->
+ #t_paren{type = T};
+maybe_paren(_P, _Prec, T) ->
+ T.
+
-record(parms, {tab, warn, file, line}).
%% Expands record references. Explicitly given record fields are kept,
@@ -476,6 +505,11 @@ xrecs(#t_fun{args = Args0, range = Range0}=T, P) ->
Args = xrecs(Args0, P),
Range = xrecs(Range0, P),
T#t_fun{args = Args, range = Range};
+xrecs(#t_map{types = Ts0 }=T,P) ->
+ Ts = xrecs(Ts0, P),
+ T#t_map{types = Ts };
+xrecs(#t_map_field{k_type=Kt, v_type=Vt}=T, P) ->
+ T#t_map_field{k_type=xrecs(Kt,P), v_type=xrecs(Vt,P)};
xrecs(#t_tuple{types = Types0}=T, P) ->
Types = xrecs(Types0, P),
T#t_tuple{types = Types};
@@ -576,6 +610,16 @@ type_name(#tag{name = type,
data = {#t_typedef{name = Name, args = As},_}}) ->
{Name, length(As)}.
+analyze_type_attribute(Form) ->
+ Name = erl_syntax:atom_value(erl_syntax:attribute_name(Form)),
+ case tag(Name) of
+ type ->
+ erl_syntax_lib:analyze_wild_attribute(Form);
+ _ when Name =:= record ->
+ {attribute, _, record, {N, Fields}} = erl_syntax:revert(Form),
+ {record, {N, Fields}}
+ end.
+
%% @doc Return `true' if `Tag' is one of the specification and type
%% attribute tags recognized by the Erlang compiler.
diff --git a/lib/edoc/src/edoc_tags.erl b/lib/edoc/src/edoc_tags.erl
index eb41f1922a..9e2e41e902 100644
--- a/lib/edoc/src/edoc_tags.erl
+++ b/lib/edoc/src/edoc_tags.erl
@@ -42,7 +42,7 @@
%% Name = atom()
%% Parser = text | xml | (Text,Line,Where) -> term()
%% Flags = [Flag]
-%% Flag = module | function | package | overview | single
+%% Flag = module | function | overview | single
%%
%% Note that the pseudo-tag '@clear' is not listed here.
%% (Cf. the function 'filter_tags'.)
@@ -57,11 +57,11 @@
%% - @category (useless; superseded by keywords or free text search)
tags() ->
- All = [module,footer,function,package,overview],
- [{author, fun parse_contact/4, [module,package,overview]},
- {copyright, text, [module,package,overview,single]},
- {deprecated, xml, [module,function,package,single]},
- {doc, xml, [module,function,package,overview,single]},
+ All = [module,footer,function,overview],
+ [{author, fun parse_contact/4, [module,overview]},
+ {copyright, text, [module,overview,single]},
+ {deprecated, xml, [module,function,single]},
+ {doc, xml, [module,function,overview,single]},
{docfile, fun parse_file/4, All},
{'end', text, All},
{equiv, fun parse_expr/4, [function,single]},
@@ -69,17 +69,17 @@ tags() ->
{hidden, text, [module,function,single]},
{param, fun parse_param/4, [function]},
{private, text, [module,function,single]},
- {reference, xml, [module,footer,package,overview]},
+ {reference, xml, [module,footer,overview]},
{returns, xml, [function,single]},
- {see, fun parse_see/4, [module,function,package,overview]},
- {since, text, [module,function,package,overview,single]},
+ {see, fun parse_see/4, [module,function,overview]},
+ {since, text, [module,function,overview,single]},
{spec, fun parse_spec/4, [function,single]},
{throws, fun parse_throws/4, [function,single]},
{title, text, [overview,single]},
{'TODO', xml, All},
{todo, xml, All},
{type, fun parse_typedef/4, [module,footer,function]},
- {version, text, [module,package,overview,single]}].
+ {version, text, [module,overview,single]}].
aliases('TODO') -> todo;
aliases(return) -> returns;
@@ -329,10 +329,7 @@ parse_typedef(Data, Line, _Env, Where) ->
NAs = length(As),
case edoc_types:is_predefined(T, NAs) of
true ->
- case
- edoc_types:is_new_predefined(T, NAs)
- orelse edoc_types:is_predefined_otp_type(T, NAs)
- of
+ case edoc_types:is_new_predefined(T, NAs) of
false ->
throw_error(Line, {"redefining built-in type '~w'.",
[T]});
@@ -345,7 +342,7 @@ parse_typedef(Data, Line, _Env, Where) ->
Def
end.
--type line() :: erl_scan:line().
+-type line() :: erl_anno:line().
-spec parse_file(_, line(), _, _) -> no_return().
@@ -372,7 +369,7 @@ parse_header(Data, Line, Env, Where) when is_list(Where) ->
{string, _, File} ->
Dir = filename:dirname(Where),
Path = Env#env.includes ++ [Dir],
- case edoc_lib:find_file(Path, "", File) of
+ case edoc_lib:find_file(Path, File) of
"" ->
throw_error(Line, {file_not_found, File});
File1 ->
@@ -454,12 +451,14 @@ check_type(#tag{line = L, data = Data}, P0, Ls, Ts) ->
check_type(#t_def{type = Type}, P, Ls, Ts) ->
check_type(Type, P, Ls, Ts);
check_type(#t_type{name = Name, args = Args}, P, Ls, Ts) ->
- check_used_type(Name, Args, P, Ls),
+ _ = check_used_type(Name, Args, P, Ls),
check_types3(Args++Ts, P, Ls);
check_type(#t_var{}, P, Ls, Ts) ->
check_types3(Ts, P, Ls);
check_type(#t_fun{args = Args, range = Range}, P, Ls, Ts) ->
check_type(Range, P, Ls, Args++Ts);
+check_type(#t_map{}, P, Ls, Ts) ->
+ check_types3(Ts, P, Ls);
check_type(#t_tuple{types = Types}, P, Ls, Ts) ->
check_types3(Types ++Ts, P, Ls);
check_type(#t_list{type = Type}, P, Ls, Ts) ->
@@ -497,7 +496,6 @@ check_used_type(#t_name{name = N, module = Mod}=Name, Args, P, LocalTypes) ->
Mod =/= []
orelse lists:member(TypeName, ets:lookup(DT, Name))
orelse edoc_types:is_predefined(N, NArgs)
- orelse edoc_types:is_predefined_otp_type(N, NArgs)
orelse lists:member(TypeName, LocalTypes)
of
true ->
diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl
index 60c6cecb97..5bb68e79fb 100644
--- a/lib/edoc/src/edoc_types.erl
+++ b/lib/edoc/src/edoc_types.erl
@@ -25,7 +25,7 @@
-module(edoc_types).
--export([is_predefined/2, is_new_predefined/2, is_predefined_otp_type/2,
+-export([is_predefined/2, is_new_predefined/2,
to_ref/1, to_xml/2, to_label/1, arg_names/1, set_arg_names/2,
arg_descs/1, range_desc/1]).
@@ -34,66 +34,13 @@
-include("edoc_types.hrl").
-include_lib("xmerl/include/xmerl.hrl").
-
-is_predefined(any, 0) -> true;
-is_predefined(atom, 0) -> true;
-is_predefined(binary, 0) -> true;
-is_predefined(bool, 0) -> true; % kept for backwards compatibility
-is_predefined(char, 0) -> true;
is_predefined(cons, 2) -> true;
is_predefined(deep_string, 0) -> true;
-is_predefined(float, 0) -> true;
-is_predefined(function, 0) -> true;
-is_predefined(integer, 0) -> true;
-is_predefined(list, 0) -> true;
-is_predefined(list, 1) -> true;
-is_predefined(nil, 0) -> true;
-is_predefined(none, 0) -> true;
-is_predefined(no_return, 0) -> true;
-is_predefined(number, 0) -> true;
-is_predefined(pid, 0) -> true;
-is_predefined(port, 0) -> true;
-is_predefined(reference, 0) -> true;
-is_predefined(string, 0) -> true;
-is_predefined(term, 0) -> true;
-is_predefined(tuple, 0) -> true;
-is_predefined(F, A) -> is_new_predefined(F, A).
+is_predefined(F, A) -> erl_internal:is_type(F, A).
-%% Should eventually be coalesced with is_predefined/2.
-is_new_predefined(arity, 0) -> true;
-is_new_predefined(bitstring, 0) -> true;
-is_new_predefined(boolean, 0) -> true;
-is_new_predefined(byte, 0) -> true;
-is_new_predefined(iodata, 0) -> true;
-is_new_predefined(iolist, 0) -> true;
-is_new_predefined(maybe_improper_list, 0) -> true;
-is_new_predefined(maybe_improper_list, 2) -> true;
-is_new_predefined(mfa, 0) -> true;
-is_new_predefined(module, 0) -> true;
-is_new_predefined(neg_integer, 0) -> true;
-is_new_predefined(node, 0) -> true;
-is_new_predefined(non_neg_integer, 0) -> true;
-is_new_predefined(nonempty_improper_list, 2) -> true;
-is_new_predefined(nonempty_list, 0) -> true;
-is_new_predefined(nonempty_list, 1) -> true;
-is_new_predefined(nonempty_maybe_improper_list, 0) -> true;
-is_new_predefined(nonempty_maybe_improper_list, 2) -> true;
-is_new_predefined(nonempty_string, 0) -> true;
-is_new_predefined(pos_integer, 0) -> true;
-is_new_predefined(timeout, 0) -> true;
+is_new_predefined(map, 0) -> true;
is_new_predefined(_, _) -> false.
-%% The following types will be removed later, but they are currently
-%% kind of built-in.
-is_predefined_otp_type(array, 0) -> true;
-is_predefined_otp_type(dict, 0) -> true;
-is_predefined_otp_type(digraph, 0) -> true;
-is_predefined_otp_type(gb_set, 0) -> true;
-is_predefined_otp_type(gb_tree, 0) -> true;
-is_predefined_otp_type(queue, 0) -> true;
-is_predefined_otp_type(set, 0) -> true;
-is_predefined_otp_type(_, _) -> false.
-
to_ref(#t_typedef{name = N}) ->
to_ref(N);
to_ref(#t_def{name = N}) ->
@@ -128,8 +75,7 @@ to_xml(#t_type{name = N, args = As}, Env) ->
Predef = case N of
#t_name{module = [], name = T} ->
NArgs = length(As),
- (is_predefined(T, NArgs)
- orelse is_predefined_otp_type(T, NArgs));
+ is_predefined(T, NArgs);
_ ->
false
end,
@@ -141,6 +87,10 @@ to_xml(#t_type{name = N, args = As}, Env) ->
to_xml(#t_fun{args = As, range = T}, Env) ->
{'fun', [{argtypes, map(fun wrap_utype/2, As, Env)},
wrap_utype(T, Env)]};
+to_xml(#t_map{ types = Ts}, Env) ->
+ {map, map(fun to_xml/2, Ts, Env)};
+to_xml(#t_map_field{assoc_type = AT, k_type=K, v_type=V}, Env) ->
+ {map_field, [{assoc_type, AT}], [wrap_utype(K,Env), wrap_utype(V, Env)]};
to_xml(#t_tuple{types = Ts}, Env) ->
{tuple, map(fun wrap_utype/2, Ts, Env)};
to_xml(#t_list{type = T}, Env) ->
diff --git a/lib/edoc/src/edoc_types.hrl b/lib/edoc/src/edoc_types.hrl
index 05c61d70ff..3e5e91484f 100644
--- a/lib/edoc/src/edoc_types.hrl
+++ b/lib/edoc/src/edoc_types.hrl
@@ -155,3 +155,7 @@
%% @type t_paren() = #t_paren{a = list(), type = type()}
-record(t_paren, {a=[], type}). % parentheses
+
+-record(t_map, {a=[], types=[]}).
+-record(t_map_field, {a=[], assoc_type, k_type, v_type}).
+
diff --git a/lib/edoc/src/otpsgml_layout.erl b/lib/edoc/src/otpsgml_layout.erl
index 2c4cd919bb..052c75b9d4 100644
--- a/lib/edoc/src/otpsgml_layout.erl
+++ b/lib/edoc/src/otpsgml_layout.erl
@@ -28,7 +28,7 @@
-module(otpsgml_layout).
--export([module/2, package/2, overview/2,type/1]).
+-export([module/2, overview/2,type/1]).
-import(edoc_report, [report/2]).
@@ -811,27 +811,6 @@ xml(Title, CSS, Body) ->
xmerl:export_simple_content(t_utype_elem(E) ++ local_defs(Ds),
?SGML_EXPORT).
-
-package(E=#xmlElement{name = package, content = Es}, Options) ->
- Opts = init_opts(E, Options),
- Name = get_text(packageName, Es),
- Title = io_lib:fwrite("Package ~s", [Name]),
- Desc = get_content(description, Es),
-% ShortDesc = get_content(briefDescription, Desc),
- FullDesc = get_content(fullDescription, Desc),
- Body = ([?NL, {h1, [Title]}, ?NL]
-% ++ ShortDesc
- ++ copyright(Es)
- ++ deprecated(Es, "package")
- ++ version(Es)
- ++ since(Es)
- ++ authors(Es)
- ++ references(Es)
- ++ sees(Es)
- ++ FullDesc),
- XML = xml(Title, stylesheet(Opts), Body),
- xmerl:export_simple([XML], ?SGML_EXPORT, []).
-
overview(E=#xmlElement{name = overview, content = Es}, Options) ->
Opts = init_opts(E, Options),
Title = get_text(title, Es),
@@ -843,6 +822,7 @@ overview(E=#xmlElement{name = overview, content = Es}, Options) ->
++ copyright(Es)
++ version(Es)
++ since(Es)
+ ++ deprecated(Es, "application")
++ authors(Es)
++ references(Es)
++ sees(Es)
diff --git a/lib/edoc/test/Makefile b/lib/edoc/test/Makefile
index 2033e003b3..7a03ddeba9 100644
--- a/lib/edoc/test/Makefile
+++ b/lib/edoc/test/Makefile
@@ -25,7 +25,7 @@ RELSYSDIR = $(RELEASE_PATH)/edoc_test
# ----------------------------------------------------
ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include
+ERL_COMPILE_FLAGS +=
EBIN = .
diff --git a/lib/edoc/test/edoc_SUITE.erl b/lib/edoc/test/edoc_SUITE.erl
index 5b95c35756..00d7550bed 100644
--- a/lib/edoc/test/edoc_SUITE.erl
+++ b/lib/edoc/test/edoc_SUITE.erl
@@ -1,13 +1,14 @@
-%% ``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 via the world wide web 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.
+%% ``Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
@@ -15,19 +16,19 @@
%%
-module(edoc_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
%% Test server specific exports
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
%% Test cases
--export([build_std/1]).
+-export([app/1,appup/1,build_std/1,build_map_module/1,otp_12008/1, build_app/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [build_std].
+ [app,appup,build_std,build_map_module,otp_12008, build_app].
groups() ->
[].
@@ -44,26 +45,71 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+%% Test that the .app file does not contain any `basic' errors
+app(Config) when is_list(Config) ->
+ ok = ?t:app_test(edoc).
+
+%% Test that the .appup file does not contain any `basic' errors
+appup(Config) when is_list(Config) ->
+ ok = ?t:appup_test(edoc).
-build_std(suite) ->
- [];
-build_std(doc) ->
- ["Build some documentation using standard EDoc layout"];
+build_std(suite) -> [];
+build_std(doc) -> ["Build some documentation using standard EDoc layout"];
build_std(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Overview1 = filename:join(DataDir, "overview.edoc"),
+ Overview2 = filename:join(DataDir, "overview.syntax_tools"),
+ PrivDir = ?config(priv_dir, Config),
- ?line DataDir = ?config(data_dir, Config),
- ?line Overview1 = filename:join(DataDir, "overview.edoc"),
- ?line Overview2 = filename:join(DataDir, "overview.syntax_tools"),
- ?line PrivDir = ?config(priv_dir, Config),
+ ok = edoc:application(edoc, [{overview, Overview1},
+ {def, {vsn,"TEST"}},
+ {dir, PrivDir}]),
- ?line ok = edoc:application(edoc, [{overview, Overview1},
- {def, {vsn,"TEST"}},
- {dir, PrivDir}]),
+ ok = edoc:application(syntax_tools, [{overview, Overview2},
+ {def, {vsn,"TEST"}},
+ {dir, PrivDir}]),
- ?line ok = edoc:application(syntax_tools, [{overview, Overview2},
- {def, {vsn,"TEST"}},
- {dir, PrivDir}]),
+ ok = edoc:application(xmerl, [{dir, PrivDir}]),
+ ok.
- ?line ok = edoc:application(xmerl, [{dir, PrivDir}]),
+build_map_module(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Filename = filename:join(DataDir, "map_module.erl"),
+ ok = edoc:file(Filename, [{dir, PrivDir}]),
+ ok.
+otp_12008(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Un1 = filename:join(DataDir, "un1.erl"),
+ Un2 = filename:join(DataDir, "un2.erl"),
+ Un3 = filename:join(DataDir, "un3.erl"),
+ %% epp_dodger
+ Opts1 = [{dir, PrivDir}],
+ ok = edoc:files([Un1], Opts1),
+ ok = edoc:files([Un2], Opts1),
+ {'EXIT', error} = (catch edoc:files([Un3], Opts1)),
+ %% epp
+ Opts2 = [{preprocess, true}, {dir, PrivDir}],
+ ok = edoc:files([Un1], Opts2),
+ ok = edoc:files([Un2], Opts2),
+ {'EXIT', error} = (catch edoc:files([Un3], Opts2)),
ok.
+
+build_app(suite) -> [];
+build_app(doc) -> ["Build a local app with nested source directories"];
+build_app(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ OutDir = filename:join(PrivDir, "myapp"),
+ Src = filename:join(DataDir, "myapp"),
+
+ ok = edoc:application(myapp, Src, [{dir, OutDir}, {subpackages, false}]),
+ true = filelib:is_regular(filename:join(OutDir, "a.html")),
+ false = filelib:is_regular(filename:join(OutDir, "b.html")),
+
+ ok = edoc:application(myapp, Src, [{dir, OutDir}]),
+ true = filelib:is_regular(filename:join(OutDir, "a.html")),
+ true = filelib:is_regular(filename:join(OutDir, "b.html")),
+ ok.
diff --git a/lib/edoc/test/edoc_SUITE_data/map_module.erl b/lib/edoc/test/edoc_SUITE_data/map_module.erl
new file mode 100644
index 0000000000..f242721637
--- /dev/null
+++ b/lib/edoc/test/edoc_SUITE_data/map_module.erl
@@ -0,0 +1,67 @@
+-module(map_module).
+
+-export([foo1/1,foo2/3,start_child/2]).
+
+%% @type wazzup() = integer()
+%% @type some_type() = map()
+%% @type some_other_type() = {a, #{ list() => term()}}
+
+-type some_type() :: map().
+-type some_other_type() :: {'a', #{ list() => term()} }.
+-type wazzup() :: integer().
+
+-spec foo1(Map :: #{ 'a' => integer(), 'b' => term()}) -> term().
+
+%% @doc Gets value from map.
+
+foo1(#{ a:= 1, b := V}) -> V.
+
+%% @spec foo2(some_type(), Type2 :: some_other_type(), map()) -> Value
+%% @doc Gets value from map.
+
+-spec foo2(
+ Type1 :: some_type(),
+ Type2 :: some_other_type(),
+ Map :: #{ get => 'value', 'value' => binary()}) -> binary().
+
+foo2(Type1, {a,#{ "a" := _}}, #{get := value, value := B}) when is_map(Type1) -> B.
+
+%% from supervisor 18.0
+
+-type child() :: 'undefined' | pid().
+-type child_id() :: term().
+-type mfargs() :: {M :: module(), F :: atom(), A :: [term()] | undefined}.
+-type modules() :: [module()] | 'dynamic'.
+-type restart() :: 'permanent' | 'transient' | 'temporary'.
+-type shutdown() :: 'brutal_kill' | timeout().
+-type worker() :: 'worker' | 'supervisor'.
+-type sup_ref() :: (Name :: atom())
+ | {Name :: atom(), Node :: node()}
+ | {'global', Name :: atom()}
+ | {'via', Module :: module(), Name :: any()}
+ | pid().
+-type child_spec() :: #{name => child_id(), % mandatory
+ start => mfargs(), % mandatory
+ restart => restart(), % optional
+ shutdown => shutdown(), % optional
+ type => worker(), % optional
+ modules => modules()} % optional
+ | {Id :: child_id(),
+ StartFunc :: mfargs(),
+ Restart :: restart(),
+ Shutdown :: shutdown(),
+ Type :: worker(),
+ Modules :: modules()}.
+
+-type startchild_err() :: 'already_present'
+ | {'already_started', Child :: child()} | term().
+-type startchild_ret() :: {'ok', Child :: child()}
+ | {'ok', Child :: child(), Info :: term()}
+ | {'error', startchild_err()}.
+
+
+-spec start_child(SupRef, ChildSpec) -> startchild_ret() when
+ SupRef :: sup_ref(),
+ ChildSpec :: child_spec() | (List :: [term()]).
+start_child(Supervisor, ChildSpec) ->
+ {Supervisor,ChildSpec}.
diff --git a/lib/edoc/test/edoc_SUITE_data/myapp/doc/.dummy b/lib/edoc/test/edoc_SUITE_data/myapp/doc/.dummy
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/edoc/test/edoc_SUITE_data/myapp/doc/.dummy
diff --git a/lib/edoc/test/edoc_SUITE_data/myapp/src/a.erl b/lib/edoc/test/edoc_SUITE_data/myapp/src/a.erl
new file mode 100644
index 0000000000..1b5b704551
--- /dev/null
+++ b/lib/edoc/test/edoc_SUITE_data/myapp/src/a.erl
@@ -0,0 +1 @@
+-module(a).
diff --git a/lib/edoc/test/edoc_SUITE_data/myapp/src/src_1/b.erl b/lib/edoc/test/edoc_SUITE_data/myapp/src/src_1/b.erl
new file mode 100644
index 0000000000..6d6f15dfe5
--- /dev/null
+++ b/lib/edoc/test/edoc_SUITE_data/myapp/src/src_1/b.erl
@@ -0,0 +1 @@
+-module(b).
diff --git a/lib/edoc/test/edoc_SUITE_data/un1.erl b/lib/edoc/test/edoc_SUITE_data/un1.erl
new file mode 100644
index 0000000000..0c48e7f940
--- /dev/null
+++ b/lib/edoc/test/edoc_SUITE_data/un1.erl
@@ -0,0 +1,7 @@
+-module(un1).
+
+-export([t/0]).
+
+%% @doc F�pp
+t() ->
+ �rlig.
diff --git a/lib/edoc/test/edoc_SUITE_data/un2.erl b/lib/edoc/test/edoc_SUITE_data/un2.erl
new file mode 100644
index 0000000000..a6d13f4723
--- /dev/null
+++ b/lib/edoc/test/edoc_SUITE_data/un2.erl
@@ -0,0 +1,8 @@
+-module(un2).
+%% coding: latin-1
+
+-export([t/0]).
+
+%% @doc F�pp
+t() ->
+ �rlig.
diff --git a/lib/edoc/test/edoc_SUITE_data/un3.erl b/lib/edoc/test/edoc_SUITE_data/un3.erl
new file mode 100644
index 0000000000..fbe9591dce
--- /dev/null
+++ b/lib/edoc/test/edoc_SUITE_data/un3.erl
@@ -0,0 +1,8 @@
+-module(un3).
+%% coding: utf-8
+
+-export([t/0]).
+
+%% @doc F�pp
+t() ->
+ �rlig.
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index af2aa2203f..f38800b3e0 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.7.12
+EDOC_VSN = 0.7.19