Merge branch 'Issue-1632'
* Issue-1632:
Minor workaround in doxygen_basic_translate_style3 test
Add new test doxygen_basic_translate_style3.i
Fix for newline handling in doxygen "///" style comments
diff --git a/.travis.yml b/.travis.yml
index 72ede27..32c6656 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -54,7 +54,12 @@
dist: xenial
- compiler: gcc
os: linux
- env: SWIGLANG=d
+ env: SWIGLANG=d VER=2.066.0
+ sudo: required
+ dist: xenial
+ - compiler: gcc
+ os: linux
+ env: SWIGLANG=d VER=2.086.1
sudo: required
dist: xenial
- compiler: gcc
@@ -204,6 +209,11 @@
dist: xenial
- compiler: gcc
os: linux
+ env: SWIGLANG=python PY3=3 VER=3.8
+ sudo: required
+ dist: xenial
+ - compiler: gcc
+ os: linux
env: SWIGLANG=python SWIG_FEATURES=-builtin
sudo: required
dist: xenial
@@ -217,7 +227,7 @@
sudo: required
dist: xenial
- os: linux
- env: SWIGLANG=python SWIG_FEATURES=-builtin GCC=6 CPP11=1 PY3=3 VER=3.7
+ env: SWIGLANG=python SWIG_FEATURES=-builtin GCC=6 CPP11=1 PY3=3 VER=3.8
sudo: required
dist: xenial
- compiler: gcc
@@ -237,12 +247,17 @@
dist: xenial
- compiler: gcc
os: linux
- env: SWIGLANG=python SWIG_FEATURES="-builtin -O" PY3=3 VER=3.7
+ env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.8
sudo: required
dist: xenial
- compiler: gcc
os: linux
- env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.7 SWIGOPTPY3=
+ env: SWIGLANG=python SWIG_FEATURES="-builtin -O" PY3=3 VER=3.8
+ sudo: required
+ dist: xenial
+ - compiler: gcc
+ os: linux
+ env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.8 SWIGOPTPY3=
sudo: required
dist: xenial
- compiler: gcc
@@ -252,7 +267,7 @@
dist: xenial
- compiler: gcc
os: linux
- env: SWIGLANG=python SWIG_FEATURES=-O PY3=3 VER=3.7
+ env: SWIGLANG=python SWIG_FEATURES=-O PY3=3 VER=3.8
sudo: required
dist: xenial
- compiler: gcc
@@ -302,6 +317,11 @@
dist: xenial
- compiler: gcc
os: linux
+ env: SWIGLANG=ruby VER=2.7
+ sudo: required
+ dist: xenial
+ - compiler: gcc
+ os: linux
env: SWIGLANG=scilab
sudo: required
dist: xenial
@@ -379,7 +399,7 @@
sudo: required
dist: xenial
- os: linux
- env: SWIGLANG=python GCC=8 CPP17=1 PY3=3 VER=3.7
+ env: SWIGLANG=python GCC=8 CPP17=1 PY3=3 VER=3.8
sudo: required
dist: xenial
- os: linux
@@ -391,7 +411,7 @@
sudo: required
dist: xenial
- os: linux
- env: SWIGLANG=python GCC=9 CPP17=1 PY3=3 VER=3.7
+ env: SWIGLANG=python GCC=9 CPP17=1 PY3=3 VER=3.8
sudo: required
dist: xenial
- compiler: gcc
@@ -443,6 +463,12 @@
osx_image: xcode10.2
allow_failures:
+ # Newer version of D not yet working/supported
+ - compiler: gcc
+ os: linux
+ env: SWIGLANG=d VER=2.086.1
+ sudo: required
+ dist: xenial
# seg fault in director_basic testcase
- compiler: gcc
os: linux
diff --git a/CHANGES.current b/CHANGES.current
index 3e65091..06f214c 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -7,3 +7,48 @@
Version 4.0.2 (in progress)
===========================
+
+2020-01-14: mcfarljm
+ #1608 Improve doxygen support.
+ - Add support for \param[] commands such as: \param[in].
+ - Optional arguments are marked as 'optional' in pydoc.
+ - Improve support for \code commands so that other languages are supported as code blocks.
+ Support added for java, c and py. For example Python: \code{.py} ... \endcode
+ - Fix doxygen handling of \em and \p tags for Python.
+
+2020-01-13: wsfulton
+ [Python] #1595 Python -builtin constructors silently ignored keyword arguments.
+ Instead of silenty ignoring them, now a "TypeError: f() takes no keyword arguments"
+ exception is thrown if keyword arguments are used. Hence constructors and normal methods/
+ functions behave in the same way. Note, -keyword should be used with -builtin to obtain
+ keyword argument support.
+
+2020-01-05: jschueller shadchin
+ [Python] #1670 #1696 Add missing field initializers introduced in python 3.8:
+ tp_vectorcall and tp_print.
+
+2020-01-05: friedrichatgc
+ [Octave] #1688 Change swig_this() to use size_t instead of long for compatibility
+ with Windows 64 bit.
+
+2020-01-05: treitmayr
+ [Ruby] #1692 #1689 Add support for Ruby 2.7
+
+2019-12-30: treitmayr
+ [Ruby] #1653 #1668 Fix code generated when using -globalmodule option.
+
+2019-12-29: ZackerySpytz
+ [OCaml] #1686 Fix compilation errors with OCaml 4.09.0.
+
+2019-12-10: wsfulton
+ #1679 Fix parsing of C++11 identifiers with special meaning (final and override) when
+ they are used as part of the scope name of an identifier, such as a namespace name.
+
+2019-11-26: wsfulton
+ [C#] #1628 'out' or 'ref' used in a cstype typemap was not always stripped out in parts
+ of director code generation.
+
+2019-11-01: wsfulton
+ [Python] #1595 Fix bug in support for keyword arguments (kwargs feature or -keyword)
+ when using -builtin. The fix is in the argument error checking when wrapping zero
+ argument constructors only.
diff --git a/Doc/Manual/CSharp.html b/Doc/Manual/CSharp.html
index 1fc2d21..d041bf5 100644
--- a/Doc/Manual/CSharp.html
+++ b/Doc/Manual/CSharp.html
@@ -66,7 +66,16 @@
It is also better suited for robust production environments due to the Managed C++ flaw called the
<a href="https://msdn.microsoft.com/en-us/ie/aa290048(v=vs.94)">Mixed DLL Loading Problem</a>.
SWIG C# works equally well on non-Microsoft operating systems such as Linux, Solaris and Apple Mac using
-<a href="https://www.mono-project.com/Main_Page/">Mono</a> and <a href="http://www.dotgnu.org/pnet.html">Portable.NET</a>.
+<a href="https://www.mono-project.com/Main_Page/">Mono</a>.
+</p>
+
+<p>
+SWIG 3 and later requires .NET 2.0 at a minimum.
+There are some minor exceptions, where the minimum required is .NET 4.0.
+This is when using the <tt>std::complex</tt> and <tt>std::list</tt> STL containers.
+</p>
+
+<p>
</p>
<p>
diff --git a/Doc/Manual/Doxygen.html b/Doc/Manual/Doxygen.html
index ff025c0..93e1153 100644
--- a/Doc/Manual/Doxygen.html
+++ b/Doc/Manual/Doxygen.html
@@ -117,14 +117,15 @@
</pre></div>
<p>
-Also any of the above with '<' added after comment-starting symbol,
-like <i>/**<, /*!<, ///<, </i> or <i> //!<</i> will be
+Also any of the above with '<tt><</tt>' added after comment-starting symbol,
+like <tt>/**<, /*!<, ///<, </tt> or <tt> //!<</tt> will be
treated as a post-comment and will be assigned to the code before the
comment.
-Any number of '*' or '/' within a Doxygen comment is considered to be a
-separator and is not included in the final comment, so you may safely use
-comments like <i>/*********/</i> or <i>//////////</i>.
+Any number of '<tt>*</tt>' or '<tt>/</tt>' within a Doxygen comment is
+considered to be a separator and is not included in the final comment,
+so you may safely use comments like <tt>/*********/</tt>
+or <tt>//////////</tt>.
</p>
<p>
@@ -606,6 +607,10 @@
<td>translated to {@code ...}</td>
</tr>
<tr>
+<td>\code{<ext>}</td>
+<td>translated to {@code ...}; code language extension is ignored</td>
+</tr>
+<tr>
<td>\cond</td>
<td>translated to 'Conditional comment: <condition>'</td>
</tr>
@@ -683,7 +688,7 @@
</tr>
<tr>
<td>\n</td>
-<td>replaced with new line char</td>
+<td>replaced with newline char</td>
</tr>
<tr>
<td>\note</td>
@@ -706,6 +711,10 @@
<td>translated to @param</td>
</tr>
<tr>
+<td>\param[<dir>]</td>
+<td>translated to @param; parameter direction ('in'; 'out'; or 'in,out') is ignored</td>
+</tr>
+<tr>
<td>\remark</td>
<td>replaced with 'Remarks:'</td>
</tr>
@@ -829,155 +838,107 @@
sense, typically text content).
Here is the list of these tags:
</p>
+
<div class="diagram">
-<table border="0" summary="Unsupported Java Doxygen Tags">
-<tr>
- <th align="left">Unsupported Doxygen tags</th>
-</tr>
-<tr>
-<td>\addindex</td>
-<td>\addtogroup</td>
-<td>\anchor</td>
-<td>\attention</td>
-</tr>
-<tr>
-<td>\brief</td>
-<td>\bug</td>
-<td>\callgraph</td>
-<td>\callergraph</td>
-</tr>
-<tr>
-<td>\class</td>
-<td>\copybrief</td>
-<td>\copydetails</td>
-<td>\copydoc</td>
-</tr>
-<tr>
-<td>\date</td>
-<td>\def</td>
-<td>\defgroup</td>
-<td>\details</td>
-</tr>
-<tr>
-<td>\dir</td>
-<td>\dontinclude</td>
-<td>\dot</td>
-<td>\dotfile</td>
-</tr>
-<tr>
-<td>\enddot</td>
-<td>\endhtmlonly</td>
-<td>\endinternal</td>
-<td>\endlatexonly</td>
-</tr>
-<tr>
-<td>\endmanonly</td>
-<td>\endmsc</td>
-<td>\endrtfonly</td>
-<td>\endxmlonly</td>
-</tr>
-<tr>
-<td>\enum</td>
-<td>\example</td>
-<td>\extends</td>
-</tr>
-<tr>
-<td>\file</td>
-<td>\fn</td>
-<td>\headerfile</td>
-<td>\hideinitializer</td>
-</tr>
-<tr>
-<td>\htmlinclude</td>
-<td>\htmlonly</td>
-<td>\implements</td>
-<td>\include</td>
-</tr>
-<tr>
-<td>\includelineno</td>
-<td>\ingroup</td>
-<td>\internal</td>
-<td>\invariant</td>
-</tr>
-<tr>
-<td>\interface</td>
-<td>\latexonly</td>
-<td>\line</td>
-<td>\mainpage</td>
-</tr>
-<tr>
-<td>\manonly</td>
-<td>\memberof</td>
-<td>\msc</td>
-<td>\mscfile</td>
-</tr>
-<tr>
-<td>\name</td>
-<td>\namespace</td>
-<td>\nosubgrouping</td>
-<td>\package</td>
-</tr>
-<tr>
-<td>\page</td>
-<td>\paragraph</td>
-<td>\post</td>
-<td>\pre</td>
-</tr>
-<tr>
-<td>\private</td>
-<td>\privatesection</td>
-<td>\property</td>
-<td>\protected</td>
-</tr>
-<tr>
-<td>\protectedsection</td>
-<td>\protocol</td>
-<td>\public</td>
-<td>\publicsection</td>
-</tr>
-<tr>
-<td>\ref</td>
-<td>\related</td>
-<td>\relates</td>
-<td>\relatedalso</td>
-</tr>
-<tr>
-<td>\relatesalso</td>
-<td>\retval</td>
-<td>\rtfonly</td>
-<td>\section</td>
-</tr>
-<tr>
-<td>\short</td>
-<td>\showinitializer</td>
-<td>\skip</td>
-<td>\skipline</td>
-</tr>
-<tr>
-<td>\snippet</td>
-<td>\struct</td>
-<td>\subpage</td>
-<td>\subsection</td>
-</tr>
-<tr>
-<td>\subsubsection</td>
-<td>\tableofcontents</td>
-<td>\test</td>
-<td>\typedef</td>
-</tr>
-<tr>
-<td>\union</td>
-<td>\until</td>
-<td>\var</td>
-<td>\verbinclude</td>
-</tr>
-<tr>
-<td>\weakgroup</td>
-<td>\xmlonly</td>
-<td>\xrefitem</td>
-<td>\category</td>
-</tr>
-</table>
+ <b>Unsupported Doxygen tags</b>
+
+ <ul style="list-style-type:none;column-count:4;">
+ <li>\addindex</li>
+ <li>\addtogroup</li>
+ <li>\anchor</li>
+ <li>\attention</li>
+ <li>\brief</li>
+ <li>\bug</li>
+ <li>\callergraph</li>
+ <li>\callgraph</li>
+ <li>\category</li>
+ <li>\class</li>
+ <li>\copybrief</li>
+ <li>\copydetails</li>
+ <li>\copydoc</li>
+ <li>\date</li>
+ <li>\def</li>
+ <li>\defgroup</li>
+ <li>\details</li>
+ <li>\dir</li>
+ <li>\dontinclude</li>
+ <li>\dot</li>
+ <li>\dotfile</li>
+ <li>\enddot</li>
+ <li>\endhtmlonly</li>
+ <li>\endinternal</li>
+ <li>\endlatexonly</li>
+ <li>\endmanonly</li>
+ <li>\endmsc</li>
+ <li>\endrtfonly</li>
+ <li>\endxmlonly</li>
+ <li>\enum</li>
+ <li>\example</li>
+ <li>\extends</li>
+ <li>\file</li>
+ <li>\fn</li>
+ <li>\headerfile</li>
+ <li>\hideinitializer</li>
+ <li>\htmlinclude</li>
+ <li>\htmlonly</li>
+ <li>\implements</li>
+ <li>\include</li>
+ <li>\includelineno</li>
+ <li>\ingroup</li>
+ <li>\interface</li>
+ <li>\internal</li>
+ <li>\invariant</li>
+ <li>\latexonly</li>
+ <li>\line</li>
+ <li>\mainpage</li>
+ <li>\manonly</li>
+ <li>\memberof</li>
+ <li>\msc</li>
+ <li>\mscfile</li>
+ <li>\name</li>
+ <li>\namespace</li>
+ <li>\nosubgrouping</li>
+ <li>\package</li>
+ <li>\page</li>
+ <li>\paragraph</li>
+ <li>\post</li>
+ <li>\pre</li>
+ <li>\private</li>
+ <li>\privatesection</li>
+ <li>\property</li>
+ <li>\protected</li>
+ <li>\protectedsection</li>
+ <li>\protocol</li>
+ <li>\public</li>
+ <li>\publicsection</li>
+ <li>\ref</li>
+ <li>\related</li>
+ <li>\relatedalso</li>
+ <li>\relates</li>
+ <li>\relatesalso</li>
+ <li>\retval</li>
+ <li>\rtfonly</li>
+ <li>\section</li>
+ <li>\short</li>
+ <li>\showinitializer</li>
+ <li>\skip</li>
+ <li>\skipline</li>
+ <li>\snippet</li>
+ <li>\struct</li>
+ <li>\subpage</li>
+ <li>\subsection</li>
+ <li>\subsubsection</li>
+ <li>\tableofcontents</li>
+ <li>\test</li>
+ <li>\typedef</li>
+ <li>\union</li>
+ <li>\until</li>
+ <li>\var</li>
+ <li>\verbinclude</li>
+ <li>\weakgroup</li>
+ <li>\xmlonly</li>
+ <li>\xrefitem</li>
+ </ul>
</div>
<p>
@@ -987,68 +948,47 @@
<!-- see parser.y, function isStructuralDoxygen() -->
</p>
-<div class="diagram">
-<table border="0" summary="Ignored Java Doxygen Tags">
-<tr>
- <th align="left">Ignored Doxygen tags</th>
-</tr>
-<tr>
-<td>\addtogroup</td>
-<td>\callgraph</td>
-<td>\callergraph</td>
-<td>\category</td>
-</tr>
-<tr>
-<td>\class</td>
-<td>\def</td>
-<td>\defgroup</td>
-<td>\dir</td>
-</tr>
-<tr>
-<td>\enum</td>
-<td>\example</td>
-<td>\file</td>
-<td>\fn</td>
-</tr>
-<tr>
-<td>\headerfile</td>
-<td>\hideinitializer</td>
-<td>\interface</td>
-<td>\internal</td>
-</tr>
-<tr>
-<td>\mainpage</td>
-<td>\name</td>
-<td>\namespace</td>
-<td>\nosubgrouping</td>
-</tr>
-<tr>
-<td>\overload</td>
-<td>\package</td>
-<td>\page</td>
-<td>\property</td>
-</tr>
-<tr>
-<td>\protocol</td>
-<td>\relates</td>
-<td>\relatesalso</td>
-<td>\showinitializer</td>
-</tr>
-<tr>
-<td>\struct</td>
-<td>\name</td>
-<td>\namespace</td>
-<td>\nosubgrouping</td>
-</tr>
-<tr>
-<td>\typedef</td>
-<td>\union</td>
-<td>\var</td>
-<td>\weakgroup</td>
-</tr>
-</table>
+<div class="diagram">
+ <b>Ignored Doxygen tags</b>
+
+ <ul style="list-style-type:none;column-count:4;">
+ <li>\addtogroup</li>
+ <li>\callergraph</li>
+ <li>\callgraph</li>
+ <li>\category</li>
+ <li>\class</li>
+ <li>\def</li>
+ <li>\defgroup</li>
+ <li>\dir</li>
+ <li>\enum</li>
+ <li>\example</li>
+ <li>\file</li>
+ <li>\fn</li>
+ <li>\headerfile</li>
+ <li>\hideinitializer</li>
+ <li>\interface</li>
+ <li>\internal</li>
+ <li>\mainpage</li>
+ <li>\name</li>
+ <li>\namespace</li>
+ <li>\nosubgrouping</li>
+ <li>\overload</li>
+ <li>\package</li>
+ <li>\page</li>
+ <li>\property</li>
+ <li>\protocol</li>
+ <li>\relates</li>
+ <li>\relatesalso</li>
+ <li>\showinitializer</li>
+ <li>\struct</li>
+ <li>\typedef</li>
+ <li>\union</li>
+ <li>\var</li>
+ <li>\weakgroup</li>
+ </ul>
</div>
+
@@ -1246,11 +1186,11 @@
</tr>
<tr>
<td>\a</td>
-<td>wrapped with '_'</td>
+<td>wrapped with '*'</td>
</tr>
<tr>
<td>\arg</td>
-<td>prepended with ' --'</td>
+<td>prepended with '* '</td>
</tr>
<tr>
<td>\author</td>
@@ -1258,17 +1198,28 @@
</tr>
<tr>
<td>\authors</td>
-<td>prints 'Author:'</td>
+<td>prints 'Authors:'</td>
</tr>
<tr>
<td>\b</td>
-<td>wrapped with '__'</td>
+<td>wrapped with '**'</td>
+</tr>
+<td>\c</td>
+<td>wrapped with '``'</td>
</tr>
<tr>
<td>\cite</td>
<td>wrapped with single quotes</td>
</tr>
<tr>
+<td>\code</td>
+<td>replaced with '.. code-block:: c++'</td>
+</tr>
+<tr>
+<td>\code{<ext>}</td>
+<td>replaced with '.. code-block:: <lang>', where the following doxygen code languages are recognized: .c -> C, .py -> python, .java > java</td>
+</tr>
+<tr>
<td>\cond</td>
<td>translated to 'Conditional comment: <condition>'</td>
</tr>
@@ -1282,7 +1233,7 @@
</tr>
<tr>
<td>\e</td>
-<td>wrapped with '_'</td>
+<td>wrapped with '*'</td>
</tr>
<tr>
<td>\else</td>
@@ -1294,7 +1245,7 @@
</tr>
<tr>
<td>\em</td>
-<td>wrapped with '_'</td>
+<td>wrapped with '*'</td>
</tr>
<tr>
<td>\endcond</td>
@@ -1305,8 +1256,24 @@
<td>replaced with '}'</td>
</tr>
<tr>
+<td>\example</td>
+<td>replaced with 'Example:'</td>
+</tr>
+<tr>
<td>\exception</td>
-<td>replaced with 'Throws:'</td>
+<td>replaced with ':raises:'</td>
+</tr>
+<tr>
+<td>\f$</td>
+<td>rendered using ':math:``'</td>
+</tr>
+<tr>
+<td>\f[</td>
+<td>rendered using '.. math::'</td>
+</tr>
+<tr>
+<td>\f{</td>
+<td>rendered using '.. math::'</td>
</tr>
<tr>
<td>\if</td>
@@ -1318,11 +1285,11 @@
</tr>
<tr>
<td>\li</td>
-<td>prepended with ' --'</td>
+<td>prepended with '* '</td>
</tr>
<tr>
<td>\n</td>
-<td>replaced with new line char</td>
+<td>replaced with newline char</td>
</tr>
<tr>
<td>\note</td>
@@ -1332,13 +1299,21 @@
<td>\overload</td>
<td>prints 'This is an overloaded ...' according to Doxygen docs</td>
</tr>
+</tr>
+<td>\p</td>
+<td>wrapped with '``'</td>
+</tr>
<tr>
<td>\par</td>
<td>replaced with 'Title: ...'</td>
</tr>
<tr>
<td>\param</td>
-<td>translated to 'Arguments:\n param(type) --description'</td>
+<td>add ':type:' and ':param:' directives</td>
+</tr>
+<tr>
+<td>\param[<dir>]</td>
+<td>same as \param, but direction ('in'; 'out'; 'in,out') is included in ':type:' directive</td>
</tr>
<tr>
<td>\remark</td>
@@ -1350,15 +1325,15 @@
</tr>
<tr>
<td>\result</td>
-<td>replaced with 'Result:'</td>
+<td>add ':rtype:' and ':return:' directives</td>
</tr>
<tr>
<td>\return</td>
-<td>replaced with 'Result:'</td>
+<td>add ':rtype:' and ':return:' directives</td>
</tr>
<tr>
<td>\returns</td>
-<td>replaced with 'Result:'</td>
+<td>add ':rtype:' and ':return:' directives</td>
</tr>
<tr>
<td>\sa</td>
@@ -1374,11 +1349,11 @@
</tr>
<tr>
<td>\throw</td>
-<td>replaced with 'Throws:'</td>
+<td>replaced with ':raises:'</td>
</tr>
<tr>
<td>\throws</td>
-<td>replaced wih 'Throws:'</td>
+<td>replaced wih ':raises:'</td>
</tr>
<tr>
<td>\todo</td>
@@ -1386,7 +1361,11 @@
</tr>
<tr>
<td>\tparam</td>
-<td>translated to 'Arguments:\n param(type) --description'</td>
+<td>add ':type:' and ':param:' directives</td>
+</tr>
+<tr>
+<td>\verbatim</td>
+<td>content copied verbatim</td>
</tr>
<tr>
<td>\version</td>
@@ -1458,177 +1437,109 @@
sense, typically text content).
Here is the list of these tags:
</p>
+
<div class="diagram">
-<table border="0" summary="Unsupported Python Doxygen Tags">
-<tr>
- <th align="left">Unsupported Doxygen tags</th>
-</tr>
-<tr>
-<td>\addindex</td>
-<td>\addtogroup</td>
-<td>\anchor</td>
-<td>\attention</td>
-</tr>
-<tr>
-<td>\brief</td>
-<td>\bug</td>
-<td>\callgraph</td>
-<td>\callergraph</td>
-</tr>
-<tr>
-<td>\class</td>
-<td>\copybrief</td>
-<td>\copydetails</td>
-<td>\copydoc</td>
-</tr>
-<tr>
-<td>\date</td>
-<td>\def</td>
-<td>\defgroup</td>
-<td>\details</td>
-</tr>
-<tr>
-<td>\dir</td>
-<td>\dontinclude</td>
-<td>\dot</td>
-<td>\dotfile</td>
-</tr>
-<tr>
-<td>\code</td>
-<td>\endcode</td>
-<td>\endverbatim</td>
-<td>\endlink</td>
-</tr>
-<tr>
-<td>\enddot</td>
-<td>\endhtmlonly</td>
-<td>\endinternal</td>
-<td>\endlatexonly</td>
-</tr>
-<tr>
-<td>\endmanonly</td>
-<td>\endmsc</td>
-<td>\endrtfonly</td>
-<td>\endxmlonly</td>
-</tr>
-<tr>
-<td>\enum</td>
-<td>\example</td>
-<td>\extends</td>
-<td>\f$</td>
-</tr>
-<tr>
-<td>\f[</td>
-<td>\f]</td>
-<td>\f{</td>
-<td>\f}</td>
-</tr>
-<tr>
-<td>\file</td>
-<td>\fn</td>
-<td>\headerfile</td>
-<td>\hideinitializer</td>
-</tr>
-<tr>
-<td>\htmlinclude</td>
-<td>\htmlonly</td>
-<td>\implements</td>
-<td>\include</td>
-</tr>
-<tr>
-<td>\image</td>
-<td>\link</td>
-<td>\verbatim</td>
-<td>\p</td>
-</tr>
-<tr>
-<td>\includelineno</td>
-<td>\ingroup</td>
-<td>\internal</td>
-<td>\invariant</td>
-</tr>
-<tr>
-<td>\interface</td>
-<td>\latexonly</td>
-<td>\line</td>
-<td>\mainpage</td>
-</tr>
-<tr>
-<td>\manonly</td>
-<td>\memberof</td>
-<td>\msc</td>
-<td>\mscfile</td>
-</tr>
-<tr>
-<td>\name</td>
-<td>\namespace</td>
-<td>\nosubgrouping</td>
-<td>\package</td>
-</tr>
-<tr>
-<td>\page</td>
-<td>\paragraph</td>
-<td>\post</td>
-<td>\pre</td>
-</tr>
-<tr>
-<td>\private</td>
-<td>\privatesection</td>
-<td>\property</td>
-<td>\protected</td>
-</tr>
-<tr>
-<td>\protectedsection</td>
-<td>\protocol</td>
-<td>\public</td>
-<td>\publicsection</td>
-</tr>
-<tr>
-<td>\ref</td>
-<td>\related</td>
-<td>\relates</td>
-<td>\relatedalso</td>
-</tr>
-<tr>
-<td>\relatesalso</td>
-<td>\retval</td>
-<td>\rtfonly</td>
-<td>\section</td>
-</tr>
-<tr>
-<td>\short</td>
-<td>\showinitializer</td>
-<td>\skip</td>
-<td>\skipline</td>
-</tr>
-<tr>
-<td>\snippet</td>
-<td>\struct</td>
-<td>\subpage</td>
-<td>\subsection</td>
-</tr>
-<tr>
-<td>\subsubsection</td>
-<td>\tableofcontents</td>
-<td>\test</td>
-<td>\typedef</td>
-</tr>
-<tr>
-<td>\union</td>
-<td>\until</td>
-<td>\var</td>
-<td>\verbinclude</td>
-</tr>
-<tr>
-<td>\weakgroup</td>
-<td>\xmlonly</td>
-<td>\xrefitem</td>
-<td>\category</td>
-</tr>
-<tr>
-<td>\c</td>
-</tr>
-</table>
+ <b>Unsupported Python Doxygen tags</b>
+
+ <ul style="list-style-type:none;column-count:4;">
+ <li>\addindex</li>
+ <li>\addtogroup</li>
+ <li>\anchor</li>
+ <li>\attention</li>
+ <li>\brief</li>
+ <li>\bug</li>
+ <li>\callergraph</li>
+ <li>\callgraph</li>
+ <li>\category</li>
+ <li>\class</li>
+ <li>\copybrief</li>
+ <li>\copydetails</li>
+ <li>\copydoc</li>
+ <li>\date</li>
+ <li>\def</li>
+ <li>\defgroup</li>
+ <li>\details</li>
+ <li>\dir</li>
+ <li>\dontinclude</li>
+ <li>\dot</li>
+ <li>\dotfile</li>
+ <li>\enddot</li>
+ <li>\endhtmlonly</li>
+ <li>\endinternal</li>
+ <li>\endlatexonly</li>
+ <li>\endlink</li>
+ <li>\endmanonly</li>
+ <li>\endmsc</li>
+ <li>\endrtfonly</li>
+ <li>\endxmlonly</li>
+ <li>\enum</li>
+ <li>\extends</li>
+ <li>\file</li>
+ <li>\fn</li>
+ <li>\headerfile</li>
+ <li>\hideinitializer</li>
+ <li>\htmlinclude</li>
+ <li>\htmlonly</li>
+ <li>\image</li>
+ <li>\implements</li>
+ <li>\include</li>
+ <li>\includelineno</li>
+ <li>\ingroup</li>
+ <li>\interface</li>
+ <li>\internal</li>
+ <li>\invariant</li>
+ <li>\latexonly</li>
+ <li>\line</li>
+ <li>\link</li>
+ <li>\mainpage</li>
+ <li>\manonly</li>
+ <li>\memberof</li>
+ <li>\msc</li>
+ <li>\mscfile</li>
+ <li>\name</li>
+ <li>\namespace</li>
+ <li>\nosubgrouping</li>
+ <li>\package</li>
+ <li>\page</li>
+ <li>\paragraph</li>
+ <li>\post</li>
+ <li>\pre</li>
+ <li>\private</li>
+ <li>\privatesection</li>
+ <li>\property</li>
+ <li>\protected</li>
+ <li>\protectedsection</li>
+ <li>\protocol</li>
+ <li>\public</li>
+ <li>\publicsection</li>
+ <li>\ref</li>
+ <li>\related</li>
+ <li>\relatedalso</li>
+ <li>\relates</li>
+ <li>\relatesalso</li>
+ <li>\retval</li>
+ <li>\rtfonly</li>
+ <li>\section</li>
+ <li>\short</li>
+ <li>\showinitializer</li>
+ <li>\skip</li>
+ <li>\skipline</li>
+ <li>\snippet</li>
+ <li>\struct</li>
+ <li>\subpage</li>
+ <li>\subsection</li>
+ <li>\subsubsection</li>
+ <li>\tableofcontents</li>
+ <li>\test</li>
+ <li>\typedef</li>
+ <li>\union</li>
+ <li>\until</li>
+ <li>\var</li>
+ <li>\verbinclude</li>
+ <li>\weakgroup</li>
+ <li>\xmlonly</li>
+ <li>\xrefitem</li>
+ </ul>
</div>
<H3><a name="Doxygen_python_further_details">17.4.4 Further details</a></H3>
diff --git a/Doc/Manual/Ruby.html b/Doc/Manual/Ruby.html
index 3cfd129..6939a8a 100644
--- a/Doc/Manual/Ruby.html
+++ b/Doc/Manual/Ruby.html
@@ -615,6 +615,24 @@
effect until it is explicitly disabled using <tt>%mutable</tt>.
</p>
+<p>Note: When SWIG is invoked with the <tt>-globalmodule</tt> option in
+effect, the C/C++ global variables will be translated into Ruby global
+variables. Type-checking and the optional read-only characteristic are
+available in the same way as described above. However the example would
+then have to be modified and executed in the following way:
+
+<div class="code targetlang">
+<pre>$ <b>irb</b>
+irb(main):001:0> <b>require 'Example'</b>
+true
+irb(main):002:0> <b>$variable1 = 2</b>
+2
+irb(main):003:0> <b>$Variable2 = 4 * 10.3</b>
+41.2
+irb(main):004:0> <b>$Variable2</b>
+41.2</pre>
+</div>
+
<H3><a name="Ruby_nn15">34.3.4 Constants</a></H3>
diff --git a/Doc/Manual/style.css b/Doc/Manual/style.css
index 45e51e3..ffadb87 100644
--- a/Doc/Manual/style.css
+++ b/Doc/Manual/style.css
@@ -65,6 +65,10 @@
font-family: "Courier New", Courier, "Courier 10 Pitch", monospace;
}
+div.diagram li {
+ margin-left: 0;
+}
+
ul li p {
margin-left: 0;
margin-right: 0;
diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk
index 25a0d8e..43fb45b 100644
--- a/Examples/test-suite/common.mk
+++ b/Examples/test-suite/common.mk
@@ -159,6 +159,7 @@
cpp_enum \
cpp_namespace \
cpp_nodefault \
+ cpp_parameters \
cpp_static \
cpp_typedef \
cpp14_binary_integer_literals \
@@ -250,6 +251,7 @@
funcptr_cpp \
functors \
fvirtual \
+ global_immutable_vars_cpp \
global_namespace \
global_ns_arg \
global_scope_types \
@@ -610,11 +612,14 @@
# cpp11_reference_wrapper \ # No typemaps
# Doxygen support test cases: can only be used with languages supporting
-# Doxygen comment translation, currently only Python and Java.
+# Doxygen comment translation (currently Python and Java) and only if not
+# disabled by configure via SKIP_DOXYGEN_TEST_CASES.
+ifneq ($(SKIP_DOXYGEN_TEST_CASES),1)
python_HAS_DOXYGEN := 1
java_HAS_DOXYGEN := 1
$(eval HAS_DOXYGEN := $($(LANGUAGE)_HAS_DOXYGEN))
+endif
ifdef HAS_DOXYGEN
DOXYGEN_TEST_CASES += \
@@ -631,6 +636,7 @@
doxygen_translate \
doxygen_translate_all_tags \
doxygen_translate_links \
+ doxygen_code_blocks \
$(DOXYGEN_TEST_CASES:=.cpptest): SWIGOPT += -doxygen
@@ -690,6 +696,7 @@
funcptr \
function_typedef \
global_functions \
+ global_immutable_vars \
immutable_values \
inctest \
infinity \
diff --git a/Examples/test-suite/cpp11_final_override.i b/Examples/test-suite/cpp11_final_override.i
index 8d275b3..c31ae73 100644
--- a/Examples/test-suite/cpp11_final_override.i
+++ b/Examples/test-suite/cpp11_final_override.i
@@ -138,3 +138,31 @@
DerivedNoVirtualStruct::~DerivedNoVirtualStruct() {}
%}
+%inline %{
+namespace Outer {
+ namespace final {
+ template <typename T> struct smart_ptr {
+ typedef T type;
+ };
+ }
+ namespace override {
+ template <typename T> struct dumb_ptr {
+ typedef T type;
+ };
+ }
+}
+%}
+
+%template(SmartPtrBaseStruct) Outer::final::smart_ptr<DerivedStruct>;
+
+%inline %{
+class ObjectDB
+{
+public:
+ static void smart1(typename Outer::final::smart_ptr<DerivedStruct>::type *objectT) {}
+ static void smart2(Outer::final::smart_ptr<DerivedStruct>::type *objectT) {}
+ static void dumb1(typename Outer::override::dumb_ptr<DerivedStruct>::type *objectT) {}
+ static void dumb2(Outer::override::dumb_ptr<DerivedStruct>::type *objectT) {}
+ static Outer::final::smart_ptr<DerivedStruct>::type get() { return DerivedStruct(); }
+};
+%}
diff --git a/Examples/test-suite/cpp_parameters.i b/Examples/test-suite/cpp_parameters.i
new file mode 100644
index 0000000..e8a4c94
--- /dev/null
+++ b/Examples/test-suite/cpp_parameters.i
@@ -0,0 +1,46 @@
+%module cpp_parameters
+
+%{
+// For Perl
+#ifdef Zero
+#undef Zero
+#endif
+%}
+%inline %{
+
+// Zero arguments
+struct Zero {
+ Zero() {}
+ int zero() { return 0; }
+ static int stat_zero() { return 0; }
+};
+// One mandatory argument
+struct One {
+ One(int a) {}
+ int one(int a) { return a; }
+ static int stat_one(int a) { return a; }
+};
+// Two mandatory arguments
+struct Two {
+ Two(int a, int b) {}
+ int two(int a, int b) { return a + b; }
+ static int stat_two(int a, int b) { return a + b; }
+};
+// Single optional argument
+struct Single {
+ Single(int a=0) {}
+ int single(int a=0) { return a; }
+ static int stat_single(int a=0) { return a; }
+};
+
+int global_zero() { return 0; }
+int global_one(int a) { return a; }
+int global_two(int a, int b) { return a + b; }
+int global_single(int a=0) { return a; }
+
+#ifdef SWIGPYTHON_BUILTIN
+bool is_python_builtin() { return true; }
+#else
+bool is_python_builtin() { return false; }
+#endif
+%}
diff --git a/Examples/test-suite/csharp/Makefile.in b/Examples/test-suite/csharp/Makefile.in
index 8272864..57a81e3 100644
--- a/Examples/test-suite/csharp/Makefile.in
+++ b/Examples/test-suite/csharp/Makefile.in
@@ -16,6 +16,7 @@
complextest \
csharp_attributes \
csharp_swig2_compatibility \
+ csharp_director_typemaps \
csharp_exceptions \
csharp_features \
csharp_lib_arrays \
diff --git a/Examples/test-suite/csharp/csharp_director_typemaps_runme.cs b/Examples/test-suite/csharp/csharp_director_typemaps_runme.cs
new file mode 100644
index 0000000..6143332
--- /dev/null
+++ b/Examples/test-suite/csharp/csharp_director_typemaps_runme.cs
@@ -0,0 +1,53 @@
+
+using System;
+using System.Reflection;
+using csharp_director_typemapsNamespace;
+
+public class csharp_director_typemaps_runme {
+
+ class CSharpDirectorTypemaps_InStreamDerived : InStream
+ {
+ private int constant;
+ public CSharpDirectorTypemaps_InStreamDerived(int constant) { this.constant = constant; }
+ public override int Read(global::System.IntPtr buf, int len, out int readLen) {
+ readLen = (buf == global::System.IntPtr.Zero) ? -len - constant : len + constant;
+ return readLen;
+ }
+ public override int Write(global::System.IntPtr buf, int len, out int writeLen) {
+ writeLen = (buf == global::System.IntPtr.Zero) ? -len - constant : len + constant;
+ return writeLen;
+ }
+ }
+ public static void Main() {
+ int outLen = -1;
+ int k = 100;
+ int j = 23;
+ InStream instream = new CSharpDirectorTypemaps_InStreamDerived(k);
+
+ {
+ int ret = csharp_director_typemaps.callRead(instream, InStream.getCPtr(instream).Handle, j, out outLen);
+ Assert(outLen, j + k);
+ Assert(ret, j + k);
+ }
+ {
+ int ret = csharp_director_typemaps.callRead(instream, global::System.IntPtr.Zero, j, out outLen);
+ Assert(outLen, -j - k);
+ Assert(ret, -j - k);
+ }
+
+ {
+ int ret = csharp_director_typemaps.callWrite(instream, InStream.getCPtr(instream).Handle, j, out outLen);
+ Assert(outLen, j + k);
+ Assert(ret, j + k);
+ }
+ {
+ int ret = csharp_director_typemaps.callWrite(instream, global::System.IntPtr.Zero, j, out outLen);
+ Assert(outLen, -j - k);
+ Assert(ret, -j - k);
+ }
+ }
+ private static void Assert(int i1, int i2) {
+ if (i1 != i2)
+ throw new Exception("assertion failure. " + i1 + " != " + i2);
+ }
+}
diff --git a/Examples/test-suite/csharp_director_typemaps.i b/Examples/test-suite/csharp_director_typemaps.i
new file mode 100644
index 0000000..614bdbf
--- /dev/null
+++ b/Examples/test-suite/csharp_director_typemaps.i
@@ -0,0 +1,37 @@
+%module (directors="1") csharp_director_typemaps
+
+// This tests that the csout typemap is handled correctly in the director code.
+// The 'out' needs stripping in some parts of the generated director code.
+
+%feature("director") InStream;
+
+%apply void *VOID_INT_PTR { void * }
+
+%typemap(ctype) int* readLen, int* writeLen "/*ctype*/ int*"
+%typemap(imtype) int* readLen, int* writeLen "/*imtype*/ out int"
+%typemap(cstype) int* readLen "/*cstype*/ out int"
+// Note for below: 'out' used in typemap comment
+%typemap(cstype) int* writeLen "/*out cstype out*/ out int"
+%typemap(csin) int* readLen, int* writeLen "/*csin*/ out $csinput"
+%typemap(in) int* readLen, int* writeLen %{/*in*/ $1 = ($1_ltype)$input; %}
+%typemap(out) int* readLen, int* writeLen %{/*out*/ $result = (void *)$1; %}
+%typemap(csdirectorin) int* readLen, int* writeLen "/*csdirectorin*/ out $iminput"
+%typemap(csdirectorout) int* readLen, int* writeLen "/*csdirectorout*/ $cscall"
+%typemap(directorin) int* readLen, int* writeLen "/*directorin*/ $input = $1;"
+%typemap(directorout) int* readLen, int* writeLen %{/*directorout*/ $result = ($1_ltype)$input; %}
+
+%inline %{
+class InStream
+{
+public:
+ virtual int Read(void* buf, int len, int* readLen) = 0;
+ virtual int Write(void* buf, int len, int* writeLen) = 0;
+ virtual ~InStream() {}
+};
+int callRead(InStream* stream, void* buf, int len, int* readLen) {
+ return stream->Read(buf, len, readLen);
+}
+int callWrite(InStream* stream, void* buf, int len, int* writeLen) {
+ return stream->Write(buf, len, writeLen);
+}
+%}
diff --git a/Examples/test-suite/doxygen_basic_translate.i b/Examples/test-suite/doxygen_basic_translate.i
index da4d809..232633f 100644
--- a/Examples/test-suite/doxygen_basic_translate.i
+++ b/Examples/test-suite/doxygen_basic_translate.i
@@ -107,6 +107,9 @@
return 0;
}
+/* Regression test for crash with empty comment: */
+/**/
+
/**
* Comment at the end of file should be ignored.
*/
diff --git a/Examples/test-suite/doxygen_code_blocks.i b/Examples/test-suite/doxygen_code_blocks.i
new file mode 100644
index 0000000..900e8f9
--- /dev/null
+++ b/Examples/test-suite/doxygen_code_blocks.i
@@ -0,0 +1,62 @@
+%module doxygen_code_blocks
+
+// This test is only used with Python
+
+%inline %{
+
+/**
+ * \brief Test for code blocks
+ *
+ * \code
+ * simple code block
+ * \endcode
+ *
+ * More advanced usage with C++ characters:
+ * \code
+ * std::vector<int> first; // empty vector of ints
+ * std::vector<int> second (4,100); // four ints with value 100
+ * std::vector<int> third (second.begin(),second.end()); // iterating through second
+ * std::vector<int> fourth (third); // a copy of third
+ * // the iterator constructor can also be used to construct from arrays:
+ * int myints[] = {16,2,77,29};
+ * std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
+ *
+ * std::cout << "The contents of fifth are:";
+ * for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
+ * std::cout << ' ' << *it;
+ * std::cout << '\n';
+ * \endcode
+ *
+ * A code block for C:
+ * \code{.c}
+ * printf("hello world");
+ * \endcode
+ *
+ * A code block for Java:
+ * \code{.java}
+ * public class HelloWorld {
+ * public static void main(String[] args) {
+ * // Prints "Hello, World" to the terminal window.
+ * System.out.println("Hello, World");
+ * }
+ * }
+ * \endcode
+ *
+ * A code block for python:
+ * \code{.py}
+ * print('hello world')
+ * \endcode
+ *
+ * A python doctest example:
+ * \code{.py}
+ * >>> 1 + 1
+ * 2
+ * \endcode
+ */
+int function()
+{
+ return 0;
+}
+
+
+%}
diff --git a/Examples/test-suite/doxygen_translate_all_tags.i b/Examples/test-suite/doxygen_translate_all_tags.i
index 8da683d..6cefd8d 100644
--- a/Examples/test-suite/doxygen_translate_all_tags.i
+++ b/Examples/test-suite/doxygen_translate_all_tags.i
@@ -262,6 +262,9 @@
* \paragraph someParagraph Paragraph title
*
* \param a the first param
+ * \param[in] b parameter with intent(in)
+ * \param[out] c parameter with intent(out)
+ * \param[in,out] d parameter with intent(in,out)
*
* \post Some description
*
@@ -273,7 +276,7 @@
*
* \property someVar
*/
-void func07(int a)
+void func07(int a, int b, int c, int d)
{
}
diff --git a/Examples/test-suite/global_immutable_vars.i b/Examples/test-suite/global_immutable_vars.i
new file mode 100644
index 0000000..ab0d4f7
--- /dev/null
+++ b/Examples/test-suite/global_immutable_vars.i
@@ -0,0 +1,33 @@
+%module global_immutable_vars
+
+// Test immutable and mutable global variables,
+// see http://www.swig.org/Doc4.0/SWIGDocumentation.html#SWIG_readonly_variables
+
+%inline %{
+ int default_mutable_var = 40;
+%}
+
+%immutable;
+%feature("immutable", "0") specific_mutable_var;
+
+%inline %{
+ int global_immutable_var = 41;
+ int specific_mutable_var = 42;
+%}
+
+%mutable;
+%immutable specific_immutable_var;
+%inline %{
+ int global_mutable_var = 43;
+ int specific_immutable_var = 44;
+
+ int check_values(int default_mutable, int global_immutable, int specific_mutable, int global_mutable, int specific_immutable) {
+ return
+ default_mutable == default_mutable_var &&
+ global_immutable == global_immutable_var &&
+ specific_mutable == specific_mutable_var &&
+ global_mutable == global_mutable_var &&
+ specific_immutable == specific_immutable_var;
+ }
+%}
+
diff --git a/Examples/test-suite/global_immutable_vars_cpp.i b/Examples/test-suite/global_immutable_vars_cpp.i
new file mode 100644
index 0000000..40cc08e
--- /dev/null
+++ b/Examples/test-suite/global_immutable_vars_cpp.i
@@ -0,0 +1,33 @@
+%module global_immutable_vars_cpp
+
+// Test immutable and mutable global variables,
+// see http://www.swig.org/Doc4.0/SWIGDocumentation.html#SWIG_readonly_variables
+
+%inline %{
+ int default_mutable_var = 40;
+%}
+
+%immutable;
+%feature("immutable", "0") specific_mutable_var;
+
+%inline %{
+ int global_immutable_var = 41;
+ int specific_mutable_var = 42;
+%}
+
+%mutable;
+%immutable specific_immutable_var;
+%inline %{
+ int global_mutable_var = 43;
+ int specific_immutable_var = 44;
+
+ int check_values(int default_mutable, int global_immutable, int specific_mutable, int global_mutable, int specific_immutable) {
+ return
+ default_mutable == default_mutable_var &&
+ global_immutable == global_immutable_var &&
+ specific_mutable == specific_mutable_var &&
+ global_mutable == global_mutable_var &&
+ specific_immutable == specific_immutable_var;
+ }
+%}
+
diff --git a/Examples/test-suite/java/CommentParser.java b/Examples/test-suite/java/CommentParser.java
index 7dc6d59..1fc6f64 100644
--- a/Examples/test-suite/java/CommentParser.java
+++ b/Examples/test-suite/java/CommentParser.java
@@ -1,5 +1,6 @@
-import com.sun.javadoc.*;
+import com.sun.source.doctree.*;
+import com.sun.source.util.DocTrees;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Map;
@@ -9,45 +10,120 @@
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.*;
+import java.util.spi.ToolProvider;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.util.*;
+import jdk.javadoc.doclet.*;
-public class CommentParser {
+public class CommentParser implements Doclet {
private static Map<String, String> m_parsedComments = new HashMap<String, String>();
- public static boolean start(RootDoc root) {
+ // We need to implement these base class pure virtual methods.
+ @Override
+ public void init(Locale locale, Reporter reporter) {
+ }
+
+ @Override
+ public Set<? extends Option> getSupportedOptions() {
+ return new HashSet<>();
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latest();
+ }
+
+ @Override
+ public String getName() {
+ return "CommentParser";
+ }
+
+ // Element name must be the fully qualified name of the element.
+ //
+ // If there is no comment associated with this element, simply do nothing.
+ private void storeCommentFor(DocTrees docTrees, String fullName, Element e) {
+ DocCommentTree docCommentTree = docTrees.getDocCommentTree(e);
+ if (docCommentTree == null)
+ return;
+
+ StringBuilder name = new StringBuilder(fullName);
+
+ // We must use signature in the key for methods for compatibility with
+ // the existing tests and to allow distinguishing between overloaded
+ // methods.
+ if (e instanceof ExecutableElement) {
+ ExecutableElement ex = (ExecutableElement)e;
+ name.append("(");
+
+ boolean firstParam = true;
+ for (VariableElement p : ex.getParameters()) {
+ if (firstParam) {
+ firstParam = false;
+ } else {
+ name.append(", ");
+ }
+
+ name.append(p.asType().toString());
+ }
+
+ name.append(")");
+ }
+
+ // For some reason the comment in the source is split into "body" and
+ // "block tags" parts, so we need to concatenate them back together.
+ StringBuilder comment = new StringBuilder();
+ for (DocTree d : docCommentTree.getFullBody()) {
+ comment.append(d.toString());
+ comment.append("\n");
+ }
+
+ boolean firstBlockTag = true;
+ for (DocTree d : docCommentTree.getBlockTags()) {
+ if (firstBlockTag) {
+ firstBlockTag = false;
+ comment.append("\n");
+ }
+
+ comment.append(d.toString());
+ comment.append("\n");
+ }
+
+ m_parsedComments.put(name.toString(), comment.toString());
+ }
+
+ @Override
+ public boolean run(DocletEnvironment docEnv) {
/*
* This method is called by 'javadoc' and gets the whole parsed java
* file, we get comments and store them
*/
+ DocTrees docTrees = docEnv.getDocTrees();
+ for (TypeElement t : ElementFilter.typesIn(docEnv.getIncludedElements())) {
+ String typeName = t.getQualifiedName().toString();
- for (ClassDoc classDoc : root.classes()) {
+ storeCommentFor(docTrees, typeName, t);
- if (classDoc.getRawCommentText().length() > 0)
- m_parsedComments.put(classDoc.qualifiedName(), classDoc.getRawCommentText());
+ for (Element e : t.getEnclosedElements()) {
+ // Omit the method name for ctors: this is a bit weird, but
+ // this is what the existing tests expect.
+ String fullName = typeName;
+ if (e.getKind() != ElementKind.CONSTRUCTOR) {
+ fullName = fullName + "." + e.getSimpleName();
+ }
- for (FieldDoc f : classDoc.enumConstants()) {
- if (f.getRawCommentText().length() > 0)
- m_parsedComments.put(f.qualifiedName(), f.getRawCommentText());
- }
- for (FieldDoc f : classDoc.fields()) {
- if (f.getRawCommentText().length() > 0)
- m_parsedComments.put(f.qualifiedName(), f.getRawCommentText());
- }
- for (ConstructorDoc c : classDoc.constructors()) {
- if (c.getRawCommentText().length() > 0)
- m_parsedComments.put(c.toString(), c.getRawCommentText());
- }
- for (MethodDoc m : classDoc.methods()) {
- if (m.getRawCommentText().length() > 0)
- m_parsedComments.put(m.toString(), m.getRawCommentText());
+ storeCommentFor(docTrees, fullName, e);
}
}
+
return true;
}
- public int check(Map<String, String> wantedComments) {
+ public static int check(Map<String, String> wantedComments) {
int errorCount=0;
Iterator<Entry<String, String>> it = m_parsedComments.entrySet().iterator();
@@ -93,13 +169,14 @@
System.out.println("Output is also saved to files '" + expectedFileName +
"' and '" + gotFileName + "'");
// here we print original strings, for nicer output
- System.out.println("\n\n---\nexpected:\n" + wantedComments.get(e.getKey()));
+ System.out.println("\n\n---\nexpected:\n" + wantedStr);
System.out.println("\n\n---\ngot:\n" + e.getValue());
try {
// write expected string to file
BufferedWriter expectedFile = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(expectedFileName)));
- expectedFile.write(wantedComments.get(e.getKey()));
+ if (wantedStr != null)
+ expectedFile.write(wantedStr);
expectedFile.close();
// write translated string to file
@@ -130,7 +207,7 @@
}
- private void printKeys(Map<String, String> map) {
+ private static void printKeys(Map<String, String> map) {
Set<String> keys = map.keySet();
for (String key : keys) {
@@ -154,6 +231,15 @@
}
}
+ public static void parse(String sourcefile) {
+ ToolProvider javadoc = ToolProvider.findFirst("javadoc").orElseThrow();
+ int result = javadoc.run(System.out, System.err, new String[]{"-quiet", "-doclet", "CommentParser", sourcefile});
+ if (result != 0) {
+ System.err.println("Executing javadoc failed.");
+ System.exit(result);
+ }
+ }
+
public static void main(String argv[]) {
@@ -162,8 +248,7 @@
System.exit(1);
}
- com.sun.tools.javadoc.Main.execute("The comment parser program",
- "CommentParser", new String[]{"-quiet", argv[0]});
+ parse(argv[0]);
// if we are run as standalone app, print the list of found comments as it would appear in java source
diff --git a/Examples/test-suite/java/Makefile.in b/Examples/test-suite/java/Makefile.in
index 2e788fa..f8e290e 100644
--- a/Examples/test-suite/java/Makefile.in
+++ b/Examples/test-suite/java/Makefile.in
@@ -9,6 +9,7 @@
JAVA_CLASSPATH_SEP = @JAVA_CLASSPATH_SEP@
JAVA_TOOLS_JAR = @JAVA_TOOLS_JAR@
SCRIPTSUFFIX = _runme.java
+SKIP_DOXYGEN_TEST_CASES = @JAVA_SKIP_DOXYGEN_TEST_CASES@
srcdir = @srcdir@
top_srcdir = ../@top_srcdir@
@@ -108,13 +109,11 @@
mkdir $(JAVA_PACKAGE); \
fi
-# Doxygen test cases need to be compiled together with the CommentParser class
-# which depends on com.sun.javadoc package which is located in this JAR.
+# Doxygen test cases need to be compiled together with the CommentParser class.
CommentParser.class:
$(COMPILETOOL) $(JAVAC) -classpath $(JAVA_CLASSPATH) -d . $(srcdir)/CommentParser.java
JAVA_CLASSPATH := .
-$(DOXYGEN_TEST_CASES:=.cpptest): JAVA_CLASSPATH := "$(JAVA_TOOLS_JAR)$(JAVA_CLASSPATH_SEP)."
$(DOXYGEN_TEST_CASES:=.cpptest): CommentParser.class
# Compiles java files then runs the testcase. A testcase is only run if
diff --git a/Examples/test-suite/java/director_string_runme.java b/Examples/test-suite/java/director_string_runme.java
index a6ed671..67cb0fe 100644
--- a/Examples/test-suite/java/director_string_runme.java
+++ b/Examples/test-suite/java/director_string_runme.java
@@ -19,7 +19,7 @@
director_string_A c = new director_string_A("hi");
for (int i=0; i<3; i++) {
s = c.call_get(i);
- if (!s.equals(new Integer(i).toString())) throw new RuntimeException("director_string_A.get(" + i + ") failed. Got:" + s);
+ if (!s.equals(Integer.valueOf(i).toString())) throw new RuntimeException("director_string_A.get(" + i + ") failed. Got:" + s);
}
director_string_B b = new director_string_B("hello");
@@ -50,7 +50,7 @@
super(first);
}
public String get(int n) {
- return new Integer(n).toString();
+ return Integer.valueOf(n).toString();
}
}
diff --git a/Examples/test-suite/java/doxygen_alias_runme.java b/Examples/test-suite/java/doxygen_alias_runme.java
index e21ed6d..98cd977 100644
--- a/Examples/test-suite/java/doxygen_alias_runme.java
+++ b/Examples/test-suite/java/doxygen_alias_runme.java
@@ -1,6 +1,5 @@
import doxygen_alias.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_alias_runme {
@@ -15,10 +14,7 @@
public static void main(String argv[])
{
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_alias runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_alias"});
+ CommentParser.parse("doxygen_alias");
HashMap<String, String> wantedComments = new HashMap<String, String>();
wantedComments.put("doxygen_alias.doxygen_alias.make_something()",
@@ -27,6 +23,6 @@
" @return A new object which may be null.\n" +
"");
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_basic_notranslate_runme.java b/Examples/test-suite/java/doxygen_basic_notranslate_runme.java
index e3d9b02..621cc9e 100644
--- a/Examples/test-suite/java/doxygen_basic_notranslate_runme.java
+++ b/Examples/test-suite/java/doxygen_basic_notranslate_runme.java
@@ -1,6 +1,5 @@
import doxygen_basic_notranslate.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_basic_notranslate_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_basic_notranslate runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_basic_notranslate"});
+ CommentParser.parse("doxygen_basic_notranslate");
HashMap<String, String> wantedComments = new HashMap<String, String>();
wantedComments.put("doxygen_basic_notranslate.doxygen_basic_notranslate.function3(int)",
@@ -97,6 +89,6 @@
"");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_basic_translate_runme.java b/Examples/test-suite/java/doxygen_basic_translate_runme.java
index ab343b5..f0b1efb 100644
--- a/Examples/test-suite/java/doxygen_basic_translate_runme.java
+++ b/Examples/test-suite/java/doxygen_basic_translate_runme.java
@@ -1,6 +1,5 @@
import doxygen_basic_translate.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_basic_translate_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_basic_translate runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_basic_translate"});
+ CommentParser.parse("doxygen_basic_translate");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -96,6 +88,6 @@
"");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_basic_translate_style2_runme.java b/Examples/test-suite/java/doxygen_basic_translate_style2_runme.java
index 05e51cf..28cf2da 100644
--- a/Examples/test-suite/java/doxygen_basic_translate_style2_runme.java
+++ b/Examples/test-suite/java/doxygen_basic_translate_style2_runme.java
@@ -1,6 +1,5 @@
import doxygen_basic_translate_style2.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_basic_translate_style2_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_basic_translate_style2 runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_basic_translate_style2"});
+ CommentParser.parse("doxygen_basic_translate_style2");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -96,6 +88,6 @@
"");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_code_blocks_runme.java b/Examples/test-suite/java/doxygen_code_blocks_runme.java
new file mode 100644
index 0000000..8e8373b
--- /dev/null
+++ b/Examples/test-suite/java/doxygen_code_blocks_runme.java
@@ -0,0 +1,75 @@
+
+import doxygen_code_blocks.*;
+import java.util.HashMap;
+
+public class doxygen_code_blocks_runme {
+ static {
+ try {
+ System.loadLibrary("doxygen_code_blocks");
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
+ System.exit(1);
+ }
+ }
+
+ public static void main(String argv[])
+ {
+ CommentParser.parse("doxygen_code_blocks");
+
+ HashMap<String, String> wantedComments = new HashMap<String, String>();
+
+ wantedComments.put("doxygen_code_blocks.doxygen_code_blocks.function()",
+ " Test for code blocks\n \n" +
+ " \n \n" +
+ " {@code \n" +
+ " simple code block \n" +
+ " }\n \n" +
+ " \n \n" +
+ " More advanced usage with C++ characters:\n \n" +
+ " {@code \n" +
+ " std::vector<int> first; // empty vector of ints \n" +
+ " std::vector<int> second (4,100); // four ints with value 100 \n" +
+ " std::vector<int> third (second.begin(),second.end()); // iterating through second \n" +
+ " std::vector<int> fourth (third); // a copy of third \n" +
+ " // the iterator constructor can also be used to construct from arrays: \n" +
+ " int myints[] = {16,2,77,29}; \n" +
+ " std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) ); \n" +
+ " \n" +
+ " std::cout << \"The contents of fifth are:\"; \n" +
+ " for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it) \n" +
+ " std::cout << \' \' << *it; \n" +
+ " std::cout << \'\\n\'; \n" +
+ " }\n \n" +
+ " \n \n" +
+ " A code block for C:\n \n" +
+ " {@code \n" +
+ " printf(\"hello world\"); \n" +
+ " }\n \n" +
+ " \n \n" +
+ " A code block for Java:\n \n" +
+ " {@code \n" +
+ " public class HelloWorld { \n" +
+ " public static void main(String[] args) { \n" +
+ " // Prints \"Hello, World\" to the terminal window. \n" +
+ " System.out.println(\"Hello, World\"); \n" +
+ " } \n" +
+ " } \n" +
+ " }\n \n" +
+ " \n \n" +
+ " A code block for python:\n \n" +
+ " {@code \n" +
+ " print(\'hello world\') \n" +
+ " }\n \n" +
+ " \n \n" +
+ " A python doctest example:\n \n" +
+ " {@code \n" +
+ " >>> 1 + 1 \n" +
+ " 2 \n" +
+ " } \n" +
+ " \n" +
+ "");
+
+ // and ask the parser to check comments for us
+ System.exit(CommentParser.check(wantedComments));
+ }
+}
diff --git a/Examples/test-suite/java/doxygen_ignore_runme.java b/Examples/test-suite/java/doxygen_ignore_runme.java
index 6250ce5..29b6e06 100644
--- a/Examples/test-suite/java/doxygen_ignore_runme.java
+++ b/Examples/test-suite/java/doxygen_ignore_runme.java
@@ -1,6 +1,5 @@
import doxygen_ignore.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_ignore_runme {
@@ -15,10 +14,7 @@
public static void main(String argv[])
{
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_ignore runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_ignore"});
+ CommentParser.parse("doxygen_ignore");
HashMap<String, String> wantedComments = new HashMap<String, String>();
wantedComments.put("doxygen_ignore.doxygen_ignore.func()",
@@ -39,6 +35,6 @@
"\n" +
"");
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_misc_constructs_runme.java b/Examples/test-suite/java/doxygen_misc_constructs_runme.java
index 5d95bd5..b1f4e2e 100644
--- a/Examples/test-suite/java/doxygen_misc_constructs_runme.java
+++ b/Examples/test-suite/java/doxygen_misc_constructs_runme.java
@@ -1,6 +1,5 @@
import doxygen_misc_constructs.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_misc_constructs_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_misc_constructs runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_misc_constructs"});
+ CommentParser.parse("doxygen_misc_constructs");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -195,6 +187,6 @@
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_nested_class_runme.java b/Examples/test-suite/java/doxygen_nested_class_runme.java
index 3ffa796..e9d1a06 100644
--- a/Examples/test-suite/java/doxygen_nested_class_runme.java
+++ b/Examples/test-suite/java/doxygen_nested_class_runme.java
@@ -1,5 +1,4 @@
import doxygen_nested_class.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_nested_class_runme {
@@ -14,14 +13,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_nested_class runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_nested_class"});
+ CommentParser.parse("doxygen_nested_class");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -43,6 +35,6 @@
" doxShort const variable ");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_parsing_enums_proper_runme.java b/Examples/test-suite/java/doxygen_parsing_enums_proper_runme.java
index ef1f06a..6b1e2b0 100644
--- a/Examples/test-suite/java/doxygen_parsing_enums_proper_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_enums_proper_runme.java
@@ -1,6 +1,5 @@
import doxygen_parsing_enums_proper.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_parsing_enums_proper_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_parsing_enums_proper runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_parsing_enums_proper"});
+ CommentParser.parse("doxygen_parsing_enums_proper");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -61,6 +53,6 @@
"Post comment after last comma.");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_parsing_enums_simple_runme.java b/Examples/test-suite/java/doxygen_parsing_enums_simple_runme.java
index 85ec0cb..1e0dd74 100644
--- a/Examples/test-suite/java/doxygen_parsing_enums_simple_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_enums_simple_runme.java
@@ -1,6 +1,5 @@
import doxygen_parsing_enums_simple.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_parsing_enums_simple_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_parsing_enums_simple runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_parsing_enums_simple"});
+ CommentParser.parse("doxygen_parsing_enums_simple");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -53,6 +45,6 @@
"Post comment after last comma.");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_parsing_enums_typesafe_runme.java b/Examples/test-suite/java/doxygen_parsing_enums_typesafe_runme.java
index 4e5f4b4..7cf3b17 100644
--- a/Examples/test-suite/java/doxygen_parsing_enums_typesafe_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_enums_typesafe_runme.java
@@ -1,6 +1,5 @@
import doxygen_parsing_enums_typesafe.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_parsing_enums_typesafe_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_parsing_enums_typesafe runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_parsing_enums_typesafe"});
+ CommentParser.parse("doxygen_parsing_enums_typesafe");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -62,6 +54,6 @@
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_parsing_enums_typeunsafe_runme.java b/Examples/test-suite/java/doxygen_parsing_enums_typeunsafe_runme.java
index 4286491..3a41fe5 100644
--- a/Examples/test-suite/java/doxygen_parsing_enums_typeunsafe_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_enums_typeunsafe_runme.java
@@ -1,6 +1,5 @@
import doxygen_parsing_enums_typeunsafe.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_parsing_enums_typeunsafe_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_parsing_enums_typeunsafe runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_parsing_enums_typeunsafe"});
+ CommentParser.parse("doxygen_parsing_enums_typeunsafe");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -61,6 +53,6 @@
"Post comment after last comma.");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_parsing_runme.java b/Examples/test-suite/java/doxygen_parsing_runme.java
index d58b1f4..10d65fc 100644
--- a/Examples/test-suite/java/doxygen_parsing_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_runme.java
@@ -1,6 +1,5 @@
import doxygen_parsing.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_parsing_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_parsing runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_parsing"});
+ CommentParser.parse("doxygen_parsing");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -136,6 +128,6 @@
"");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_translate_all_tags_runme.java b/Examples/test-suite/java/doxygen_translate_all_tags_runme.java
index d5c533f..fda1fc3 100644
--- a/Examples/test-suite/java/doxygen_translate_all_tags_runme.java
+++ b/Examples/test-suite/java/doxygen_translate_all_tags_runme.java
@@ -1,6 +1,5 @@
import doxygen_translate_all_tags.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_translate_all_tags_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_translate_all_tags runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_translate_all_tags"});
+ CommentParser.parse("doxygen_translate_all_tags");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -104,7 +96,7 @@
" {@link someMember Some description follows }\n" +
" This will only appear in man\n");
- wantedComments.put("doxygen_translate_all_tags.doxygen_translate_all_tags.func07(int)",
+ wantedComments.put("doxygen_translate_all_tags.doxygen_translate_all_tags.func07(int, int, int, int)",
" Comment for <b>func07()</b>.\n" +
" Note: Here \n" +
" is the note! \n" +
@@ -115,7 +107,10 @@
" The paragraph text. \n" +
" Maybe even multiline \n" +
" </p>\n" +
- " @param a the first param\n");
+ " @param a the first param\n" +
+ " @param b parameter with intent(in)\n" +
+ " @param c parameter with intent(out)\n" +
+ " @param d parameter with intent(in,out)\n");
wantedComments.put("doxygen_translate_all_tags.doxygen_translate_all_tags.func08(int)",
"<a id=\"someAnchor\"></a>\n" +
@@ -154,6 +149,6 @@
" And here goes simple text \n" +
"");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/java/doxygen_translate_links_runme.java b/Examples/test-suite/java/doxygen_translate_links_runme.java
index 6d74e16..afee4ea 100644
--- a/Examples/test-suite/java/doxygen_translate_links_runme.java
+++ b/Examples/test-suite/java/doxygen_translate_links_runme.java
@@ -1,6 +1,5 @@
import doxygen_translate_links.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
public class doxygen_translate_links_runme {
@@ -15,14 +14,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_translate_links runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_translate_links"});
+ CommentParser.parse("doxygen_translate_links");
HashMap<String, String> wantedComments = new HashMap<String, String>();
@@ -64,6 +56,6 @@
"");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
\ No newline at end of file
diff --git a/Examples/test-suite/java/doxygen_translate_runme.java b/Examples/test-suite/java/doxygen_translate_runme.java
index 55e5d23..b049a64 100644
--- a/Examples/test-suite/java/doxygen_translate_runme.java
+++ b/Examples/test-suite/java/doxygen_translate_runme.java
@@ -1,6 +1,5 @@
import doxygen_translate.*;
-import com.sun.javadoc.*;
import java.util.HashMap;
import java.util.Map;
@@ -16,14 +15,7 @@
public static void main(String argv[])
{
- /*
- Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
- and calls the start() method of that class with parsed information.
- */
- CommentParser parser = new CommentParser();
- com.sun.tools.javadoc.Main.execute("doxygen_translate runtime test",
- "CommentParser",
- new String[]{"-quiet", "doxygen_translate"});
+ CommentParser.parse("doxygen_translate");
Map<String, String> wantedComments = new HashMap<String, String>();
@@ -274,6 +266,6 @@
"");
// and ask the parser to check comments for us
- System.exit(parser.check(wantedComments));
+ System.exit(CommentParser.check(wantedComments));
}
}
diff --git a/Examples/test-suite/kwargs_feature.i b/Examples/test-suite/kwargs_feature.i
index a8d1c38..2b662ca 100644
--- a/Examples/test-suite/kwargs_feature.i
+++ b/Examples/test-suite/kwargs_feature.i
@@ -100,3 +100,29 @@
int foo_mm(int min = 1, int max = 2) {return min + max; }
%}
+
+
+// Extended constructors
+%extend Extending0 {
+ Extending0() { return new Extending0(); }
+}
+%extend Extending1 {
+ Extending1(int one) { return new Extending1(); }
+}
+%extend Extending2 {
+ Extending2(int one, const char *two) { return new Extending2(); }
+}
+%extend ExtendingOptArgs1 {
+ ExtendingOptArgs1(int one = 0) { return new ExtendingOptArgs1(); }
+}
+%extend ExtendingOptArgs2 {
+ ExtendingOptArgs2(int one = 0, const char* two = NULL) { return new ExtendingOptArgs2(); }
+}
+
+%inline %{
+struct Extending0 {};
+struct Extending1 {};
+struct Extending2 {};
+struct ExtendingOptArgs1 {};
+struct ExtendingOptArgs2 {};
+%}
diff --git a/Examples/test-suite/python/cpp_parameters_runme.py b/Examples/test-suite/python/cpp_parameters_runme.py
new file mode 100644
index 0000000..99d14ad
--- /dev/null
+++ b/Examples/test-suite/python/cpp_parameters_runme.py
@@ -0,0 +1,296 @@
+from cpp_parameters import *
+
+# Testing correct and incorrect parameter counts being passed (kwargs and non-kwargs)
+# Note that the implementation depends a lot on whether zero, one, two or more args are being wrapped
+
+def is_python_fastproxy():
+ """Return True if SWIG is generating Python code using -fastproxy."""
+ import cpp_parameters
+ # Note: _swig_new_instance_method is only generated when using -fastproxy
+ return hasattr(cpp_parameters, "_swig_new_instance_method")
+
+# Zero parameters expected
+x = Zero()
+try:
+ x = Zero(z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ x = Zero(0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ x.zero(z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ x.zero(0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ Zero.stat_zero(z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ Zero.stat_zero(0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ global_zero(z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ global_zero(0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+# One mandatory parameter expected
+x = One(1)
+try:
+ x = One(a=1, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ x = One(1, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ x.one(a=1, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ x.one(1, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ One.stat_one(a=1, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ One.stat_one(1, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ global_one(a=1, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ global_one(1, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+# Two mandatory parameters expected
+x = Two(1, 2)
+try:
+ x = Two(a=1, b=2, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ x = Two(1, 2, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ x.two(a=1, b=2, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ x.two(1, 2, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ Two.stat_two(a=1, b=2, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ Two.stat_two(1, 2, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ global_two(a=1, b=2, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ global_two(1, 2, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+# Single optional parameter expected
+x = Single(1)
+try:
+ x = Single(a=1, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ x = Single(1, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ x.single(a=1, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ x.single(1, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ Single.stat_single(a=1, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ Single.stat_single(1, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+try:
+ global_single(a=1, z=0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+try:
+ global_single(1, 0)
+ raise RuntimeError("Missed throw")
+except TypeError:
+ pass
+
+# Test that -builtin option throws TypeError if kwargs are used even when they look like they should work, kwargs are not supported unless using -keyword.
+# Also same for -fastproxy option except that kwargs are supported by default for constructors. TODO: Fix inconsistency.
+
+if is_python_builtin() or is_python_fastproxy():
+ # One mandatory parameter in API
+ x = One(1)
+ if is_python_fastproxy():
+ x = One(a=1)
+ else:
+ try:
+ x = One(a=1)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ x.one(a=1)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ One.stat_one(a=1)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ global_one(a=1)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+
+ # Two mandatory parameters in API
+ x = Two(1, 2)
+ if is_python_fastproxy():
+ x = Two(a=1, b=2)
+ else:
+ try:
+ x = Two(a=1, b=2)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ x.two(a=1, b=2)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ Two.stat_two(a=1, b=2)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ global_two(a=1, b=2)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+
+ # Single optional parameter in API
+ x = Single(1)
+ if is_python_fastproxy():
+ x = Single(a=1)
+ else:
+ try:
+ x = Single(a=1)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ x.single(a=1)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ Single.stat_single(a=1)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+ try:
+ global_single(a=1)
+ raise RuntimeError("Missed throw")
+ except TypeError:
+ pass
+
+else:
+ # Non-builtin should work as expected
+ # One mandatory parameter in API
+ x = One(a=1)
+ x.one(a=1)
+ One.stat_one(a=1)
+ global_one(a=1)
+
+ # Two mandatory parameters in API
+ x = Two(a=1, b=2)
+ x.two(a=1, b=2)
+ Two.stat_two(a=1, b=2)
+ global_two(a=1, b=2)
+
+ # Single optional parameter in API
+ x = Single(a=1)
+ x.single(a=1)
+ Single.stat_single(a=1)
+ global_single(a=1)
diff --git a/Examples/test-suite/python/doxygen_basic_translate_runme.py b/Examples/test-suite/python/doxygen_basic_translate_runme.py
index 9ef8dbd..90edda1 100644
--- a/Examples/test-suite/python/doxygen_basic_translate_runme.py
+++ b/Examples/test-suite/python/doxygen_basic_translate_runme.py
@@ -60,7 +60,7 @@
comment_verifier.check(inspect.getdoc(doxygen_basic_translate.function6),
"""\
Test for default args
-:type a: int
+:type a: int, optional
:param a: Some parameter, default is 42"""
)
comment_verifier.check(inspect.getdoc(doxygen_basic_translate.function7),
diff --git a/Examples/test-suite/python/doxygen_basic_translate_style2_runme.py b/Examples/test-suite/python/doxygen_basic_translate_style2_runme.py
index b75045d..a24f5de 100644
--- a/Examples/test-suite/python/doxygen_basic_translate_style2_runme.py
+++ b/Examples/test-suite/python/doxygen_basic_translate_style2_runme.py
@@ -58,7 +58,7 @@
comment_verifier.check(inspect.getdoc(doxygen_basic_translate_style2.function6),
"""\
Test for default args
-:type a: int
+:type a: int, optional
:param a: Some parameter, default is 42"""
)
comment_verifier.check(inspect.getdoc(doxygen_basic_translate_style2.function7),
diff --git a/Examples/test-suite/python/doxygen_code_blocks_runme.py b/Examples/test-suite/python/doxygen_code_blocks_runme.py
new file mode 100644
index 0000000..46a0a3d
--- /dev/null
+++ b/Examples/test-suite/python/doxygen_code_blocks_runme.py
@@ -0,0 +1,58 @@
+import doxygen_code_blocks
+import inspect
+import string
+import sys
+import comment_verifier
+
+comment_verifier.check(inspect.getdoc(doxygen_code_blocks.function),
+ """\
+Test for code blocks
+
+.. code-block:: c++
+
+ simple code block
+
+More advanced usage with C++ characters:
+
+.. code-block:: c++
+
+ std::vector<int> first; // empty vector of ints
+ std::vector<int> second (4,100); // four ints with value 100
+ std::vector<int> third (second.begin(),second.end()); // iterating through second
+ std::vector<int> fourth (third); // a copy of third
+ // the iterator constructor can also be used to construct from arrays:
+ int myints[] = {16,2,77,29};
+ std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
+
+ std::cout << "The contents of fifth are:";
+ for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
+ std::cout << ' ' << *it;
+ std::cout << '\\n';
+
+A code block for C:
+
+.. code-block:: c
+
+ printf("hello world");
+
+A code block for Java:
+
+.. code-block:: java
+
+ public class HelloWorld {
+ public static void main(String[] args) {
+ // Prints "Hello, World" to the terminal window.
+ System.out.println("Hello, World");
+ }
+ }
+
+A code block for python:
+
+.. code-block:: python
+
+ print('hello world')
+
+A python doctest example:
+
+>>> 1 + 1
+2""")
diff --git a/Examples/test-suite/python/doxygen_misc_constructs_runme.py b/Examples/test-suite/python/doxygen_misc_constructs_runme.py
index 11aa53b..c0b5c16 100644
--- a/Examples/test-suite/python/doxygen_misc_constructs_runme.py
+++ b/Examples/test-suite/python/doxygen_misc_constructs_runme.py
@@ -12,7 +12,7 @@
:param fileName: name of the file, where the source line is located
:type line: int
:param line: line number
-:type isGetSize: boolean
+:type isGetSize: boolean, optional
:param isGetSize: if set, for every object location both address and size are returned
Connection::getId() """)
diff --git a/Examples/test-suite/python/doxygen_translate_all_tags_runme.py b/Examples/test-suite/python/doxygen_translate_all_tags_runme.py
index df1c0eb..2b5b3b8 100644
--- a/Examples/test-suite/python/doxygen_translate_all_tags_runme.py
+++ b/Examples/test-suite/python/doxygen_translate_all_tags_runme.py
@@ -82,7 +82,7 @@
*italicword*
-emphazedWord
+*emphazedWord*
@@ -196,7 +196,7 @@
This is an overloaded member function, provided for convenience.
It differs from the above function only in what argument(s) it accepts.
-someword
+``someword``
@@ -209,7 +209,13 @@
:type a: int
-:param a: the first param""")
+:param a: the first param
+:type b: int, in
+:param b: parameter with intent(in)
+:type c: int, out
+:param c: parameter with intent(out)
+:type d: int, in/out
+:param d: parameter with intent(in,out)""")
comment_verifier.check(inspect.getdoc(doxygen_translate_all_tags.func08),
r"""Text after anchor.
diff --git a/Examples/test-suite/python/doxygen_translate_runme.py b/Examples/test-suite/python/doxygen_translate_runme.py
index d698ba8..38dca2e 100644
--- a/Examples/test-suite/python/doxygen_translate_runme.py
+++ b/Examples/test-suite/python/doxygen_translate_runme.py
@@ -80,7 +80,7 @@
This is an overloaded member function, provided for convenience.
It differs from the above function only in what argument(s) it accepts.
-someword
+``someword``
diff --git a/Examples/test-suite/python/kwargs_feature_runme.py b/Examples/test-suite/python/kwargs_feature_runme.py
index a2d4731..31d49d2 100644
--- a/Examples/test-suite/python/kwargs_feature_runme.py
+++ b/Examples/test-suite/python/kwargs_feature_runme.py
@@ -79,3 +79,46 @@
if rfoo(x=11, n=22) != 11:
raise RuntimeError
+
+# Extended constructors
+e = Extending0()
+e = Extending1(one=1)
+e = Extending1(1)
+e = Extending2(1, "two")
+e = Extending2(1, two="two")
+e = Extending2(two="two", one=1)
+e = ExtendingOptArgs1()
+e = ExtendingOptArgs1(1)
+e = ExtendingOptArgs2(one=1)
+e = ExtendingOptArgs2()
+e = ExtendingOptArgs2(one=1)
+e = ExtendingOptArgs2(two="two")
+e = ExtendingOptArgs2(two="two", one=1)
+
+# Invalid kwargs test
+h = Hello()
+try:
+ h = Hello(nonexistent=10)
+ raise RuntimeError("missed exception")
+except TypeError as e:
+ pass
+
+f = Foo(1)
+f = Foo(a=1)
+try:
+ f = Foo(nonexistent=10)
+ raise RuntimeError("missed exception")
+except TypeError as e:
+ pass
+
+try:
+ f = Foo(a=1, nonexistent=10)
+ raise RuntimeError("missed exception")
+except TypeError as e:
+ pass
+
+try:
+ f = Foo(1, nonexistent=10)
+ raise RuntimeError("missed exception")
+except TypeError as e:
+ pass
diff --git a/Examples/test-suite/ruby/Makefile.in b/Examples/test-suite/ruby/Makefile.in
index d75cdb0..2c59029 100644
--- a/Examples/test-suite/ruby/Makefile.in
+++ b/Examples/test-suite/ruby/Makefile.in
@@ -23,6 +23,7 @@
li_std_wstring_inherit \
primitive_types \
ruby_alias_method \
+ ruby_global_immutable_vars_cpp \
ruby_keywords \
ruby_minherit_shared_ptr \
ruby_naming \
@@ -48,6 +49,7 @@
li_cstring \
ruby_alias_global_function \
ruby_alias_module_function \
+ ruby_global_immutable_vars \
ruby_manual_proxy \
include $(srcdir)/../common.mk
@@ -57,6 +59,8 @@
# Custom tests - tests with additional commandline options
ruby_alias_global_function.ctest: SWIGOPT += -globalmodule
+ruby_global_immutable_vars.ctest: SWIGOPT += -globalmodule
+ruby_global_immutable_vars_cpp.cpptest: SWIGOPT += -globalmodule
ruby_naming.cpptest: SWIGOPT += -autorename
# Rules for the different types of tests
diff --git a/Examples/test-suite/ruby/global_immutable_vars_cpp_runme.rb b/Examples/test-suite/ruby/global_immutable_vars_cpp_runme.rb
new file mode 100644
index 0000000..7897f7d
--- /dev/null
+++ b/Examples/test-suite/ruby/global_immutable_vars_cpp_runme.rb
@@ -0,0 +1,48 @@
+#!/usr/bin/env ruby
+#
+# C++ version of global_immutable_vars_runme.rb
+#
+
+require 'swig_assert'
+
+require 'global_immutable_vars_cpp'
+
+# first check if all variables can be read
+swig_assert_each_line( <<EOF )
+Global_immutable_vars_cpp::default_mutable_var == 40
+Global_immutable_vars_cpp::global_immutable_var == 41
+Global_immutable_vars_cpp::specific_mutable_var == 42
+Global_immutable_vars_cpp::global_mutable_var == 43
+Global_immutable_vars_cpp::specific_immutable_var == 44
+EOF
+
+# check that all mutable variables can be modified
+swig_assert_each_line( <<EOF )
+Global_immutable_vars_cpp::default_mutable_var = 80
+Global_immutable_vars_cpp::default_mutable_var == 80
+Global_immutable_vars_cpp::specific_mutable_var = 82
+Global_immutable_vars_cpp::specific_mutable_var == 82
+Global_immutable_vars_cpp::global_mutable_var = 83
+Global_immutable_vars_cpp::global_mutable_var == 83
+EOF
+
+# now check that immutable variables cannot be modified
+had_exception = false
+begin
+ Global_immutable_vars_cpp::global_immutable_var = 81
+rescue NoMethodError => e
+ had_exception = true
+end
+swig_assert(had_exception, nil,
+ "Global_immutable_vars_cpp::global_immutable_var is writable (expected to be immutable)")
+
+had_exception = false
+begin
+ Global_immutable_vars_cpp::specific_immutable_var = 81
+rescue NoMethodError => e
+ had_exception = true
+end
+swig_assert(had_exception, nil,
+ "Global_immutable_vars_cpp::specific_immutable_var is writable (expected to be immutable)")
+
+swig_assert(Global_immutable_vars_cpp::check_values(80, 41, 82, 83, 44) == 1, nil, "Check values failed")
diff --git a/Examples/test-suite/ruby/global_immutable_vars_runme.rb b/Examples/test-suite/ruby/global_immutable_vars_runme.rb
new file mode 100644
index 0000000..ffbea27
--- /dev/null
+++ b/Examples/test-suite/ruby/global_immutable_vars_runme.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+#
+# Here the proper generation of mutable and immutable variables is tested
+# in the target language.
+# Immutable variables do not have "<var>=" methods generated by SWIG,
+# therefore trying to assign these variables shall throw a NoMethodError
+# exception.
+#
+
+require 'swig_assert'
+
+require 'global_immutable_vars'
+
+# first check if all variables can be read
+swig_assert_each_line( <<EOF )
+Global_immutable_vars::default_mutable_var == 40
+Global_immutable_vars::global_immutable_var == 41
+Global_immutable_vars::specific_mutable_var == 42
+Global_immutable_vars::global_mutable_var == 43
+Global_immutable_vars::specific_immutable_var == 44
+EOF
+
+# check that all mutable variables can be modified
+swig_assert_each_line( <<EOF )
+Global_immutable_vars::default_mutable_var = 80
+Global_immutable_vars::default_mutable_var == 80
+Global_immutable_vars::specific_mutable_var = 82
+Global_immutable_vars::specific_mutable_var == 82
+Global_immutable_vars::global_mutable_var = 83
+Global_immutable_vars::global_mutable_var == 83
+EOF
+
+# now check that immutable variables cannot be modified
+had_exception = false
+begin
+ Global_immutable_vars::global_immutable_var = 81
+rescue NoMethodError => e
+ had_exception = true
+end
+swig_assert(had_exception, nil,
+ "Global_immutable_vars::global_immutable_var is writable (expected to be immutable)")
+
+had_exception = false
+begin
+ Global_immutable_vars::specific_immutable_var = 81
+rescue NoMethodError => e
+ had_exception = true
+end
+swig_assert(had_exception, nil,
+ "Global_immutable_vars::specific_immutable_var is writable (expected to be immutable)")
+
+swig_assert(Global_immutable_vars::check_values(80, 41, 82, 83, 44) == 1, nil, "Check values failed")
diff --git a/Examples/test-suite/ruby/ruby_global_immutable_vars_cpp_runme.rb b/Examples/test-suite/ruby/ruby_global_immutable_vars_cpp_runme.rb
new file mode 100644
index 0000000..5523b59
--- /dev/null
+++ b/Examples/test-suite/ruby/ruby_global_immutable_vars_cpp_runme.rb
@@ -0,0 +1,48 @@
+#!/usr/bin/env ruby
+#
+# C++ version of ruby_global_immutable_vars_runme.rb.
+#
+
+require 'swig_assert'
+
+require 'ruby_global_immutable_vars_cpp'
+
+# first check if all variables can be read
+swig_assert_each_line( <<EOF )
+$default_mutable_var == 40
+$global_immutable_var == 41
+$specific_mutable_var == 42
+$global_mutable_var == 43
+$specific_immutable_var == 44
+EOF
+
+# check that all mutable variables can be modified
+swig_assert_each_line( <<EOF )
+$default_mutable_var = 80
+$default_mutable_var == 80
+$specific_mutable_var = 82
+$specific_mutable_var == 82
+$global_mutable_var = 83
+$global_mutable_var == 83
+EOF
+
+# now check that immutable variables cannot be modified
+had_exception = false
+begin
+ $global_immutable_var = 81
+rescue NameError => e
+ had_exception = true
+end
+swig_assert(had_exception, nil,
+ "$global_immutable_var is writable (expected to be immutable)")
+
+had_exception = false
+begin
+ $specific_immutable_var = 81
+rescue NameError => e
+ had_exception = true
+end
+swig_assert(had_exception, nil,
+ "$specific_immutable_var is writable (expected to be immutable)")
+
+swig_assert(check_values(80, 41, 82, 83, 44) == 1, nil, "Check values failed")
diff --git a/Examples/test-suite/ruby/ruby_global_immutable_vars_runme.rb b/Examples/test-suite/ruby/ruby_global_immutable_vars_runme.rb
new file mode 100644
index 0000000..45a8506
--- /dev/null
+++ b/Examples/test-suite/ruby/ruby_global_immutable_vars_runme.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+#
+# This test program is similar to global_immutable_vars_runme.rb
+# with the difference that the global variables to check are also
+# Ruby global variables (SWIG Ruby option "-globalmodule").
+#
+# Immutable global variables shall throw a NameError exception.
+#
+
+require 'swig_assert'
+
+require 'ruby_global_immutable_vars'
+
+# first check if all variables can be read
+swig_assert_each_line( <<EOF )
+$default_mutable_var == 40
+$global_immutable_var == 41
+$specific_mutable_var == 42
+$global_mutable_var == 43
+$specific_immutable_var == 44
+EOF
+
+# check that all mutable variables can be modified
+swig_assert_each_line( <<EOF )
+$default_mutable_var = 80
+$default_mutable_var == 80
+$specific_mutable_var = 82
+$specific_mutable_var == 82
+$global_mutable_var = 83
+$global_mutable_var == 83
+EOF
+
+# now check that immutable variables cannot be modified
+had_exception = false
+begin
+ $global_immutable_var = 81
+rescue NameError => e
+ had_exception = true
+end
+swig_assert(had_exception, nil,
+ "$global_immutable_var is writable (expected to be immutable)")
+
+had_exception = false
+begin
+ $specific_immutable_var = 81
+rescue NameError => e
+ had_exception = true
+end
+swig_assert(had_exception, nil,
+ "$specific_immutable_var is writable (expected to be immutable)")
+
+swig_assert(check_values(80, 41, 82, 83, 44) == 1, nil, "Check values failed")
diff --git a/Examples/test-suite/ruby_global_immutable_vars.i b/Examples/test-suite/ruby_global_immutable_vars.i
new file mode 100644
index 0000000..6f067d2
--- /dev/null
+++ b/Examples/test-suite/ruby_global_immutable_vars.i
@@ -0,0 +1,34 @@
+%module ruby_global_immutable_vars
+
+// This copy of global_immutable_vars.i shall be compiled with the
+// SWIG Ruby option "-globalmodule" in order to check the code path
+// for registering global methods (in contrast to module methods).
+
+%inline %{
+ int default_mutable_var = 40;
+%}
+
+%immutable;
+%feature("immutable", "0") specific_mutable_var;
+
+%inline %{
+ int global_immutable_var = 41;
+ int specific_mutable_var = 42;
+%}
+
+%mutable;
+%immutable specific_immutable_var;
+%inline %{
+ int global_mutable_var = 43;
+ int specific_immutable_var = 44;
+
+ int check_values(int default_mutable, int global_immutable, int specific_mutable, int global_mutable, int specific_immutable) {
+ return
+ default_mutable == default_mutable_var &&
+ global_immutable == global_immutable_var &&
+ specific_mutable == specific_mutable_var &&
+ global_mutable == global_mutable_var &&
+ specific_immutable == specific_immutable_var;
+ }
+%}
+
diff --git a/Examples/test-suite/ruby_global_immutable_vars_cpp.i b/Examples/test-suite/ruby_global_immutable_vars_cpp.i
new file mode 100644
index 0000000..511390e
--- /dev/null
+++ b/Examples/test-suite/ruby_global_immutable_vars_cpp.i
@@ -0,0 +1,32 @@
+%module ruby_global_immutable_vars_cpp
+
+// C++ version of ruby_global_immutable_vars.i
+
+%inline %{
+ int default_mutable_var = 40;
+%}
+
+%immutable;
+%feature("immutable", "0") specific_mutable_var;
+
+%inline %{
+ int global_immutable_var = 41;
+ int specific_mutable_var = 42;
+%}
+
+%mutable;
+%immutable specific_immutable_var;
+%inline %{
+ int global_mutable_var = 43;
+ int specific_immutable_var = 44;
+
+ int check_values(int default_mutable, int global_immutable, int specific_mutable, int global_mutable, int specific_immutable) {
+ return
+ default_mutable == default_mutable_var &&
+ global_immutable == global_immutable_var &&
+ specific_mutable == specific_mutable_var &&
+ global_mutable == global_mutable_var &&
+ specific_immutable == specific_immutable_var;
+ }
+%}
+
diff --git a/Lib/ocaml/carray.i b/Lib/ocaml/carray.i
index 5e74c3d..4378f73 100644
--- a/Lib/ocaml/carray.i
+++ b/Lib/ocaml/carray.i
@@ -77,7 +77,7 @@
%typemap(out) SWIGTYPE [] {
int i;
- CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
+ const CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
$result = caml_array_new($1_dim0);
for( i = 0; i < $1_dim0; i++ ) {
diff --git a/Lib/ocaml/ocaml.swg b/Lib/ocaml/ocaml.swg
index ac496bd..afb01da 100644
--- a/Lib/ocaml/ocaml.swg
+++ b/Lib/ocaml/ocaml.swg
@@ -62,7 +62,7 @@
#if 0
%typemap(argout) SWIGTYPE & {
- CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
+ const CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
if( fromval ) {
swig_result =
caml_list_append(swig_result,
@@ -75,7 +75,7 @@
}
}
%typemap(argout) SWIGTYPE && {
- CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
+ const CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
if( fromval ) {
swig_result =
caml_list_append(swig_result,
diff --git a/Lib/ocaml/ocamlrun.swg b/Lib/ocaml/ocamlrun.swg
index 3d552cc..5a923c5 100644
--- a/Lib/ocaml/ocamlrun.swg
+++ b/Lib/ocaml/ocamlrun.swg
@@ -407,7 +407,7 @@
CAMLreturn((long)SWIG_Int64_val(SWIG_Field(SWIG_Field(v,0),0)));
case C_enum: {
SWIG_CAMLlocal1(ret);
- CAML_VALUE *enum_to_int = caml_named_value(SWIG_MODULE "_enum_to_int");
+ const CAML_VALUE *enum_to_int = caml_named_value(SWIG_MODULE "_enum_to_int");
if( !name ) caml_failwith( "Not an enum conversion" );
ret = caml_callback2(*enum_to_int,*caml_named_value(name),v);
CAMLreturn(caml_long_val(ret));
@@ -451,7 +451,7 @@
CAMLparam1(v);
void *outptr = NULL;
swig_type_info *outdescr = NULL;
- static CAML_VALUE *func_val = NULL;
+ static const CAML_VALUE *func_val = NULL;
if( v == Val_unit ) {
*out = 0;
@@ -574,7 +574,7 @@
CAMLparam0();
SWIG_CAMLlocal1(result);
- CAML_VALUE *fromval = caml_named_value(name);
+ const CAML_VALUE *fromval = caml_named_value(name);
if (fromval) {
result = caml_callback(*fromval, caml_val_ptr(ptr, descriptor));
} else {
diff --git a/Lib/octave/octrun.swg b/Lib/octave/octrun.swg
index ff614e6..325a4cc 100644
--- a/Lib/octave/octrun.swg
+++ b/Lib/octave/octrun.swg
@@ -507,10 +507,10 @@
delete this;
}
- long swig_this() const {
+ size_t swig_this() const {
if (!types.size())
- return (long) this;
- return (long) types[0].second.ptr;
+ return (size_t) this;
+ return (size_t) types[0].second.ptr;
}
const char* help_text() const {
if (!types.size())
diff --git a/Lib/python/builtin.swg b/Lib/python/builtin.swg
index 28051e6..5308748 100644
--- a/Lib/python/builtin.swg
+++ b/Lib/python/builtin.swg
@@ -256,6 +256,12 @@
#if PY_VERSION_HEX >= 0x03040000
0, /* tp_finalize */
#endif
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+ 0, /* tp_print */
+#endif
#ifdef COUNT_ALLOCS
0, /* tp_allocs */
0, /* tp_frees */
@@ -334,6 +340,12 @@
#if PY_VERSION_HEX >= 0x03040000
0, /* tp_finalize */
#endif
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+ 0, /* tp_print */
+#endif
#ifdef COUNT_ALLOCS
0, /* tp_allocs */
0, /* tp_frees */
diff --git a/Lib/python/pyinit.swg b/Lib/python/pyinit.swg
index dfbf40b..a6d609d 100644
--- a/Lib/python/pyinit.swg
+++ b/Lib/python/pyinit.swg
@@ -186,6 +186,12 @@
#if PY_VERSION_HEX >= 0x03040000
0, /* tp_finalize */
#endif
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+ 0, /* tp_print */
+#endif
#ifdef COUNT_ALLOCS
0, /* tp_allocs */
0, /* tp_frees */
diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg
index 82859b8..d6eeda9 100644
--- a/Lib/python/pyrun.swg
+++ b/Lib/python/pyrun.swg
@@ -183,6 +183,19 @@
}
}
+SWIGINTERN int
+SWIG_Python_CheckNoKeywords(PyObject *kwargs, const char *name) {
+ int no_kwargs = 1;
+ if (kwargs) {
+ assert(PyDict_Check(kwargs));
+ if (PyDict_Size(kwargs) > 0) {
+ PyErr_Format(PyExc_TypeError, "%s() does not take keyword arguments", name);
+ no_kwargs = 0;
+ }
+ }
+ return no_kwargs;
+}
+
/* A functor is a function object with one single object argument */
#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL);
@@ -696,6 +709,12 @@
#if PY_VERSION_HEX >= 0x03040000
0, /* tp_finalize */
#endif
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+ 0, /* tp_print */
+#endif
#ifdef COUNT_ALLOCS
0, /* tp_allocs */
0, /* tp_frees */
@@ -857,6 +876,12 @@
#if PY_VERSION_HEX >= 0x03040000
0, /* tp_finalize */
#endif
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+ 0, /* tp_print */
+#endif
#ifdef COUNT_ALLOCS
0, /* tp_allocs */
0, /* tp_frees */
diff --git a/Lib/ruby/rubyclasses.swg b/Lib/ruby/rubyclasses.swg
index f7b51bd..b345fce 100644
--- a/Lib/ruby/rubyclasses.swg
+++ b/Lib/ruby/rubyclasses.swg
@@ -174,7 +174,7 @@
return rb_inspect(_obj);
}
- static VALUE swig_rescue_swallow(VALUE)
+ static VALUE swig_rescue_swallow(VALUE, VALUE)
{
/*
VALUE errstr = rb_obj_as_string(rb_errinfo());
@@ -203,8 +203,8 @@
args.id = op_id;
args.nargs = 1;
args.target = VALUE(other);
- ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
- (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
+ ret = rb_rescue(VALUEFUNC(swig_rescue_funcall), VALUE(&args),
+ (VALUEFUNC(swig_rescue_swallow)), Qnil);
}
if (ret == Qnil) {
VALUE a = rb_funcall( _obj, hash_id, 0 );
@@ -243,8 +243,8 @@
args.id = op_id;
args.nargs = 0;
args.target = Qnil;
- ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
- (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
+ ret = rb_rescue(VALUEFUNC(swig_rescue_funcall), VALUE(&args),
+ (VALUEFUNC(swig_rescue_swallow)), Qnil);
SWIG_RUBY_THREAD_END_BLOCK;
return ret;
}
@@ -262,8 +262,8 @@
args.id = op_id;
args.nargs = 1;
args.target = VALUE(other);
- ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
- (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
+ ret = rb_rescue(VALUEFUNC(swig_rescue_funcall), VALUE(&args),
+ (VALUEFUNC(swig_rescue_swallow)), Qnil);
SWIG_RUBY_THREAD_END_BLOCK;
return GC_VALUE(ret);
}
diff --git a/Lib/ruby/rubyhead.swg b/Lib/ruby/rubyhead.swg
index 90f07cf..bf4e362 100644
--- a/Lib/ruby/rubyhead.swg
+++ b/Lib/ruby/rubyhead.swg
@@ -98,38 +98,46 @@
/*
- * Need to be very careful about how these macros are defined, especially
- * when compiling C++ code or C code with an ANSI C compiler.
+ * The following macros are used for providing the correct type of a
+ * function pointer to the Ruby C API.
+ * Starting with Ruby 2.7 (corresponding to RB_METHOD_DEFINITION_DECL being
+ * defined) these macros act transparently due to Ruby's moving away from
+ * ANYARGS and instead employing strict function signatures.
*
- * VALUEFUNC(f) is a macro used to typecast a C function that implements
- * a Ruby method so that it can be passed as an argument to API functions
- * like rb_define_method() and rb_define_singleton_method().
+ * Note: In case of C (not C++) the macros are transparent even before
+ * Ruby 2.7 due to the fact that the Ruby C API used function declarators
+ * with empty parentheses, which allows for an unspecified number of
+ * arguments.
*
- * VOIDFUNC(f) is a macro used to typecast a C function that implements
- * either the "mark" or "free" stuff for a Ruby Data object, so that it
- * can be passed as an argument to API functions like Data_Wrap_Struct()
+ * PROTECTFUNC(f) is used for the function pointer argument of the Ruby
+ * C API function rb_protect().
+ *
+ * VALUEFUNC(f) is used for the function pointer argument(s) of Ruby C API
+ * functions like rb_define_method() and rb_define_singleton_method().
+ *
+ * VOIDFUNC(f) is used to typecast a C function that implements either
+ * the "mark" or "free" stuff for a Ruby Data object, so that it can be
+ * passed as an argument to Ruby C API functions like Data_Wrap_Struct()
* and Data_Make_Struct().
+ *
+ * SWIG_RUBY_VOID_ANYARGS_FUNC(f) is used for the function pointer
+ * argument(s) of Ruby C API functions like rb_define_virtual_variable().
+ *
+ * SWIG_RUBY_INT_ANYARGS_FUNC(f) is used for the function pointer
+ * argument(s) of Ruby C API functions like st_foreach().
*/
-
-#ifdef __cplusplus
-# ifndef RUBY_METHOD_FUNC /* These definitions should work for Ruby 1.4.6 */
-# define PROTECTFUNC(f) ((VALUE (*)()) f)
-# define VALUEFUNC(f) ((VALUE (*)()) f)
-# define VOIDFUNC(f) ((void (*)()) f)
-# else
-# ifndef ANYARGS /* These definitions should work for Ruby 1.6 */
-# define PROTECTFUNC(f) ((VALUE (*)()) f)
-# define VALUEFUNC(f) ((VALUE (*)()) f)
-# define VOIDFUNC(f) ((RUBY_DATA_FUNC) f)
-# else /* These definitions should work for Ruby 1.7+ */
-# define PROTECTFUNC(f) ((VALUE (*)(VALUE)) f)
-# define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
-# define VOIDFUNC(f) ((RUBY_DATA_FUNC) f)
-# endif
-# endif
+#if defined(__cplusplus) && !defined(RB_METHOD_DEFINITION_DECL)
+# define PROTECTFUNC(f) ((VALUE (*)(VALUE)) f)
+# define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
+# define VOIDFUNC(f) ((RUBY_DATA_FUNC) f)
+# define SWIG_RUBY_VOID_ANYARGS_FUNC(f) ((void (*)(ANYARGS))(f))
+# define SWIG_RUBY_INT_ANYARGS_FUNC(f) ((int (*)(ANYARGS))(f))
#else
+# define PROTECTFUNC(f) (f)
# define VALUEFUNC(f) (f)
# define VOIDFUNC(f) (f)
+# define SWIG_RUBY_VOID_ANYARGS_FUNC(f) (f)
+# define SWIG_RUBY_INT_ANYARGS_FUNC(f) (f)
#endif
/* Don't use for expressions have side effect */
diff --git a/Lib/ruby/rubyprimtypes.swg b/Lib/ruby/rubyprimtypes.swg
index 3a84819..4b078de 100644
--- a/Lib/ruby/rubyprimtypes.swg
+++ b/Lib/ruby/rubyprimtypes.swg
@@ -10,15 +10,16 @@
%fragment("SWIG_ruby_failed","header")
{
SWIGINTERN VALUE
-SWIG_ruby_failed(void)
+SWIG_ruby_failed(VALUE SWIGUNUSEDPARM(arg1), VALUE SWIGUNUSEDPARM(arg2))
{
return Qnil;
}
}
%define %ruby_aux_method(Type, Method, Action)
-SWIGINTERN VALUE SWIG_AUX_##Method##(VALUE *args)
+SWIGINTERN VALUE SWIG_AUX_##Method##(VALUE arg)
{
+ VALUE *args = (VALUE *)arg;
VALUE obj = args[0];
VALUE type = TYPE(obj);
Type *res = (Type *)(args[1]);
@@ -79,7 +80,7 @@
VALUE a[2];
a[0] = obj;
a[1] = (VALUE)(&v);
- if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2LONG), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+ if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2LONG), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
if (val) *val = v;
return SWIG_OK;
}
@@ -111,7 +112,7 @@
VALUE a[2];
a[0] = obj;
a[1] = (VALUE)(&v);
- if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2ULONG), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+ if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2ULONG), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
if (val) *val = v;
return SWIG_OK;
}
@@ -149,7 +150,7 @@
VALUE a[2];
a[0] = obj;
a[1] = (VALUE)(&v);
- if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2LL), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+ if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2LL), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
if (val) *val = v;
return SWIG_OK;
}
@@ -187,7 +188,7 @@
VALUE a[2];
a[0] = obj;
a[1] = (VALUE)(&v);
- if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2ULL), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+ if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2ULL), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
if (val) *val = v;
return SWIG_OK;
}
@@ -215,7 +216,7 @@
VALUE a[2];
a[0] = obj;
a[1] = (VALUE)(&v);
- if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2DBL), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+ if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2DBL), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
if (val) *val = v;
return SWIG_OK;
}
diff --git a/Lib/ruby/rubytracking.swg b/Lib/ruby/rubytracking.swg
index b9fb249..1edcc56 100644
--- a/Lib/ruby/rubytracking.swg
+++ b/Lib/ruby/rubytracking.swg
@@ -32,7 +32,7 @@
*/
static st_table* swig_ruby_trackings = NULL;
-static VALUE swig_ruby_trackings_count(ANYARGS) {
+static VALUE swig_ruby_trackings_count(ID id, VALUE *var) {
return SWIG2NUM(swig_ruby_trackings->num_entries);
}
@@ -69,7 +69,9 @@
swig_ruby_trackings = (st_table*)NUM2SWIG(trackings_value);
}
- rb_define_virtual_variable("SWIG_TRACKINGS_COUNT", swig_ruby_trackings_count, NULL);
+ rb_define_virtual_variable("SWIG_TRACKINGS_COUNT",
+ VALUEFUNC(swig_ruby_trackings_count),
+ SWIG_RUBY_VOID_ANYARGS_FUNC((rb_gvar_setter_t*)NULL));
}
/* Add a Tracking from a C/C++ struct to a Ruby object */
@@ -118,13 +120,15 @@
to the passed callback function. */
/* Proxy method to abstract the internal trackings datatype */
-static int swig_ruby_internal_iterate_callback(void* ptr, VALUE obj, void(*meth)(void* ptr, VALUE obj)) {
- (*meth)(ptr, obj);
+static int swig_ruby_internal_iterate_callback(st_data_t ptr, st_data_t obj, st_data_t meth) {
+ ((void (*) (void *, VALUE))meth)((void *)ptr, (VALUE)obj);
return ST_CONTINUE;
}
SWIGRUNTIME void SWIG_RubyIterateTrackings( void(*meth)(void* ptr, VALUE obj) ) {
- st_foreach(swig_ruby_trackings, (int (*)(ANYARGS))&swig_ruby_internal_iterate_callback, (st_data_t)meth);
+ st_foreach(swig_ruby_trackings,
+ SWIG_RUBY_INT_ANYARGS_FUNC(swig_ruby_internal_iterate_callback),
+ (st_data_t)meth);
}
#ifdef __cplusplus
diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c
index ee3270b..4c1a038 100644
--- a/Source/CParse/cscanner.c
+++ b/Source/CParse/cscanner.c
@@ -448,10 +448,11 @@
/* Check for all possible Doxygen comment start markers while ignoring
comments starting with a row of asterisks or slashes just as
- Doxygen itself does. */
+ Doxygen itself does. Also skip empty comment (slash-star-star-slash),
+ which causes a crash due to begin > end. */
if (Len(cmt) > 3 && loc[0] == '/' &&
((loc[1] == '/' && ((loc[2] == '/' && loc[3] != '/') || loc[2] == '!')) ||
- (loc[1] == '*' && ((loc[2] == '*' && loc[3] != '*') || loc[2] == '!')))) {
+ (loc[1] == '*' && ((loc[2] == '*' && loc[3] != '*' && loc[3] != '/') || loc[2] == '!')))) {
comment_kind_t this_comment = loc[3] == '<' ? DOX_COMMENT_POST : DOX_COMMENT_PRE;
if (existing_comment != DOX_COMMENT_NONE && this_comment != existing_comment) {
/* We can't concatenate together Doxygen pre- and post-comments. */
@@ -893,10 +894,14 @@
return (USING);
if (strcmp(yytext, "namespace") == 0)
return (NAMESPACE);
- if (strcmp(yytext, "override") == 0)
+ if (strcmp(yytext, "override") == 0) {
+ last_id = 1;
return (OVERRIDE);
- if (strcmp(yytext, "final") == 0)
+ }
+ if (strcmp(yytext, "final") == 0) {
+ last_id = 1;
return (FINAL);
+ }
} else {
if (strcmp(yytext, "class") == 0) {
Swig_warning(WARN_PARSE_CLASS_KEYWORD, cparse_file, cparse_line, "class keyword used, but not in C++ mode.\n");
diff --git a/Source/DOH/README b/Source/DOH/README
index 8be5f65..be90f25 100644
--- a/Source/DOH/README
+++ b/Source/DOH/README
@@ -73,11 +73,17 @@
Chop(obj) Remove trailing whitespace
flags is one of the following:
- DOH_REPLACE_ANY
- DOH_REPLACE_NOQUOTE
- DOH_REPLACE_ID
- DOH_REPLACE_FIRST
-
+ DOH_REPLACE_ID
+ DOH_REPLACE_ID_BEGIN
+ DOH_REPLACE_ID_END
+ DOH_REPLACE_NUMBER_END
+
+and can be combined with one or more of the following:
+ DOH_REPLACE_ANY
+ DOH_REPLACE_NOQUOTE
+ DOH_REPLACE_NOCOMMENT
+ DOH_REPLACE_FIRST
+
Callable Operations
-------------------
Call(obj, args) Perform a function call with arguments args.
diff --git a/Source/DOH/doh.h b/Source/DOH/doh.h
index 7fb64c0..fd0530e 100644
--- a/Source/DOH/doh.h
+++ b/Source/DOH/doh.h
@@ -289,11 +289,12 @@
#define DOH_REPLACE_ANY 0x01
#define DOH_REPLACE_NOQUOTE 0x02
-#define DOH_REPLACE_ID 0x04
-#define DOH_REPLACE_FIRST 0x08
-#define DOH_REPLACE_ID_BEGIN 0x10
-#define DOH_REPLACE_ID_END 0x20
-#define DOH_REPLACE_NUMBER_END 0x40
+#define DOH_REPLACE_NOCOMMENT 0x04
+#define DOH_REPLACE_ID 0x08
+#define DOH_REPLACE_FIRST 0x10
+#define DOH_REPLACE_ID_BEGIN 0x20
+#define DOH_REPLACE_ID_END 0x40
+#define DOH_REPLACE_NUMBER_END 0x80
#define Replaceall(s,t,r) DohReplace(s,t,r,DOH_REPLACE_ANY)
#define Replaceid(s,t,r) DohReplace(s,t,r,DOH_REPLACE_ID)
diff --git a/Source/DOH/string.c b/Source/DOH/string.c
index 6c67285..3689f4f 100644
--- a/Source/DOH/string.c
+++ b/Source/DOH/string.c
@@ -595,6 +595,13 @@
}
}
+static char *end_comment(char *s) {
+ char *substring = strstr(s, "*/");
+ if (substring)
+ ++substring;
+ return substring;
+}
+
static char *match_simple(char *base, char *s, char *token, int tokenlen) {
(void) base;
(void) tokenlen;
@@ -677,6 +684,7 @@
int ic;
int rcount = 0;
int noquote = 0;
+ int nocomment = 0;
char *c, *s, *t, *first;
char *q, *q2;
char *base;
@@ -698,6 +706,11 @@
if (flags & DOH_REPLACE_NOQUOTE)
noquote = 1;
+ if (flags & DOH_REPLACE_NOCOMMENT)
+ nocomment = 1;
+
+ assert(!(noquote && nocomment)); /* quote and comment combination not implemented */
+
/* If we are not replacing inside quotes, we need to do a little extra work */
if (noquote) {
q = strpbrk(base, "\"\'");
@@ -723,6 +736,31 @@
}
}
+ /* If we are not replacing inside comments, we need to do a little extra work */
+ if (nocomment) {
+ q = strstr(base, "/*");
+ if (!q) {
+ nocomment = 0; /* Well, no comments to worry about. Oh well */
+ } else {
+ while (q && (q < s)) {
+ /* First match was found inside a comment. Try to find another match */
+ q2 = end_comment(q);
+ if (!q2) {
+ return 0;
+ }
+ if (q2 > s) {
+ /* Find next match */
+ s = (*match) (base, q2 + 1, token, tokenlen);
+ }
+ if (!s)
+ return 0; /* Oh well, no matches */
+ q = strstr(q2 + 1, "/*");
+ if (!q)
+ nocomment = 0; /* No more comments */
+ }
+ }
+ }
+
first = s;
replen = (int)strlen(rep);
@@ -768,6 +806,28 @@
}
}
}
+ if (nocomment) {
+ q = strstr(s, "/*");
+ if (!q) {
+ nocomment = 0;
+ } else {
+ while (q && (q < c)) {
+ /* First match was found inside a comment. Try to find another match */
+ q2 = end_comment(q);
+ if (!q2) {
+ c = 0;
+ break;
+ }
+ if (q2 > c)
+ c = (*match) (base, q2 + 1, token, tokenlen);
+ if (!c)
+ break;
+ q = strstr(q2 + 1, "/*");
+ if (!q)
+ nocomment = 0; /* No more comments */
+ }
+ }
+ }
if (delta) {
if (c) {
memmove(t, s, c - s);
@@ -823,6 +883,29 @@
}
}
}
+ if (nocomment) {
+ q = strstr(s, "/*");
+ if (!q) {
+ break;
+ } else {
+ while (q && (q < c)) {
+ /* First match was found inside a comment. Try to find another match */
+ q2 = end_comment(q);
+ if (!q2) {
+ c = 0;
+ break;
+ }
+ if (q2 > c) {
+ c = (*match) (base, q2 + 1, token, tokenlen);
+ if (!c)
+ break;
+ }
+ q = strstr(q2 + 1, "/*");
+ if (!q)
+ nocomment = 0;
+ }
+ }
+ }
if (c) {
rcount++;
ic--;
@@ -875,6 +958,29 @@
}
}
}
+ if (nocomment) {
+ q = strstr(s, "/*");
+ if (!q) {
+ nocomment = 0;
+ } else {
+ while (q && (q < c)) {
+ /* First match was found inside a comment. Try to find another match */
+ q2 = end_comment(q);
+ if (!q2) {
+ c = 0;
+ break;
+ }
+ if (q2 > c) {
+ c = (*match) (base, q2 + 1, token, tokenlen);
+ if (!c)
+ break;
+ }
+ q = strstr(q2 + 1, "/*");
+ if (!q)
+ nocomment = 0; /* No more comments */
+ }
+ }
+ }
if (i < (rcount - 1)) {
memcpy(t, s, c - s);
t += (c - s);
diff --git a/Source/Doxygen/doxycommands.h b/Source/Doxygen/doxycommands.h
index 1f7b5fa..b5d65af 100644
--- a/Source/Doxygen/doxycommands.h
+++ b/Source/Doxygen/doxycommands.h
@@ -18,11 +18,13 @@
const char *CMD_HTML_ONLY = "htmlonly";
// doxy commands are not processed inside this block
const char *CMD_VERBATIM = "verbatim";
+const char *CMD_CODE = "code";
const char *CMD_LATEX_1 = "f$";
const char *CMD_LATEX_2 = "f{";
const char *CMD_LATEX_3 = "f[";
const char *CMD_END_HTML_ONLY = "endhtmlonly";
const char *CMD_END_VERBATIM = "endverbatim";
+const char *CMD_END_CODE = "endcode";
const char *CMD_END_LATEX_1 = "f$";
const char *CMD_END_LATEX_2 = "f}";
const char *CMD_END_LATEX_3 = "f]";
diff --git a/Source/Doxygen/doxyparser.cxx b/Source/Doxygen/doxyparser.cxx
index 2e826b2..6bda9d2 100644
--- a/Source/Doxygen/doxyparser.cxx
+++ b/Source/Doxygen/doxyparser.cxx
@@ -34,6 +34,30 @@
const int TOKENSPERLINE = 8; //change this to change the printing behaviour of the token list
const std::string END_HTML_TAG_MARK("/");
+std::string getBaseCommand(const std::string &cmd) {
+ if (cmd.substr(0,5) == "param")
+ return "param";
+ else if (cmd.substr(0,4) == "code")
+ return "code";
+ else
+ return cmd;
+}
+
+// Find the first position beyond the word command. Extra logic is
+// used to avoid putting the characters "," and "." in
+// DOXYGEN_WORD_CHARS.
+static size_t getEndOfWordCommand(const std::string &line, size_t pos) {
+ size_t endOfWordPos = line.find_first_not_of(DOXYGEN_WORD_CHARS, pos);
+ if (line.substr(pos, 6) == "param[")
+ // include ",", which can appear in param[in,out]
+ endOfWordPos = line.find_first_not_of(string(DOXYGEN_WORD_CHARS)+ ",", pos);
+ else if (line.substr(pos, 5) == "code{")
+ // include ".", which can appear in e.g. code{.py}
+ endOfWordPos = line.find_first_not_of(string(DOXYGEN_WORD_CHARS)+ ".", pos);
+ return endOfWordPos;
+}
+
+
DoxygenParser::DoxygenParser(bool noisy) : noisy(noisy) {
fillTables();
}
@@ -118,7 +142,7 @@
}
DoxygenParser::DoxyCommandEnum DoxygenParser::commandBelongs(const std::string &theCommand) {
- DoxyCommandsMapIt it = doxygenCommands.find(stringToLower(theCommand));
+ DoxyCommandsMapIt it = doxygenCommands.find(stringToLower(getBaseCommand(theCommand)));
if (it != doxygenCommands.end()) {
return it->second;
@@ -312,7 +336,7 @@
} else if (endOfParagraph->m_tokenType == COMMAND) {
- if (isSectionIndicator(endOfParagraph->m_tokenString)) {
+ if (isSectionIndicator(getBaseCommand(endOfParagraph->m_tokenString))) {
return endOfParagraph;
} else {
endOfParagraph++;
@@ -666,7 +690,7 @@
// \f{ ... \f}
// \f{env}{ ... \f}
// \f$ ... \f$
- else if (theCommand == "code" || theCommand == "verbatim"
+ else if (getBaseCommand(theCommand) == "code" || theCommand == "verbatim"
|| theCommand == "dot" || theCommand == "msc" || theCommand == "f[" || theCommand == "f{" || theCommand == "f$") {
if (!endCommands.size()) {
// fill in static table of end commands
@@ -683,7 +707,7 @@
if (it != endCommands.end())
endCommand = it->second;
else
- endCommand = "end" + theCommand;
+ endCommand = "end" + getBaseCommand(theCommand);
std::string content = getStringTilEndCommand(endCommand, tokList);
aNewList.push_back(DoxygenEntity("plainstd::string", content));
@@ -1090,7 +1114,7 @@
size_t endOfWordPos = line.find_first_not_of(DOXYGEN_WORD_CHARS, pos);
string cmd = line.substr(pos, endOfWordPos - pos);
- if (cmd == CMD_END_HTML_ONLY || cmd == CMD_END_VERBATIM || cmd == CMD_END_LATEX_1 || cmd == CMD_END_LATEX_2 || cmd == CMD_END_LATEX_3) {
+ if (cmd == CMD_END_HTML_ONLY || cmd == CMD_END_VERBATIM || cmd == CMD_END_LATEX_1 || cmd == CMD_END_LATEX_2 || cmd == CMD_END_LATEX_3 || cmd == CMD_END_CODE) {
m_isVerbatimText = false;
addDoxyCommand(m_tokenList, cmd);
@@ -1154,22 +1178,34 @@
*/
void DoxygenParser::processWordCommands(size_t &pos, const std::string &line) {
pos++;
- size_t endOfWordPos = line.find_first_not_of(DOXYGEN_WORD_CHARS, pos);
+ size_t endOfWordPos = getEndOfWordCommand(line, pos);
string cmd = line.substr(pos, endOfWordPos - pos);
addDoxyCommand(m_tokenList, cmd);
- if (cmd == CMD_HTML_ONLY || cmd == CMD_VERBATIM || cmd == CMD_LATEX_1 || cmd == CMD_LATEX_2 || cmd == CMD_LATEX_3) {
+ // A flag for whether we want to skip leading spaces after the command
+ bool skipLeadingSpace = true;
+
+ if (cmd == CMD_HTML_ONLY || cmd == CMD_VERBATIM || cmd == CMD_LATEX_1 || cmd == CMD_LATEX_2 || cmd == CMD_LATEX_3 || getBaseCommand(cmd) == CMD_CODE) {
m_isVerbatimText = true;
- } else {
+ // Skipping leading space is necessary with inline \code command,
+ // and it won't hurt anything for block \code (TODO: are the other
+ // commands also compatible with skip leading space? If so, just
+ // do it every time.)
+ if (getBaseCommand(cmd) == CMD_CODE) skipLeadingSpace = true;
+ else skipLeadingSpace = false;
+ }
+
+ if (skipLeadingSpace) {
// skip any possible spaces after command, because some commands have parameters,
// and spaces between command and parameter must be ignored.
if (endOfWordPos != string::npos) {
endOfWordPos = line.find_first_not_of(" \t", endOfWordPos);
}
}
+
pos = endOfWordPos;
}
diff --git a/Source/Doxygen/doxyparser.h b/Source/Doxygen/doxyparser.h
index 96c71d2..e692729 100644
--- a/Source/Doxygen/doxyparser.h
+++ b/Source/Doxygen/doxyparser.h
@@ -21,6 +21,11 @@
#include "doxyentity.h"
+// Utility function to return the base part of a command that may
+// include options, e.g. param[in] -> param
+std::string getBaseCommand(const std::string &cmd);
+
+
class DoxygenParser {
private:
diff --git a/Source/Doxygen/javadoc.cxx b/Source/Doxygen/javadoc.cxx
index 72f84ab..d9313f9 100644
--- a/Source/Doxygen/javadoc.cxx
+++ b/Source/Doxygen/javadoc.cxx
@@ -334,7 +334,7 @@
void JavaDocConverter::translateEntity(DoxygenEntity &tag, std::string &translatedComment) {
std::map<std::string, std::pair<tagHandler, std::string> >::iterator it;
- it = tagHandlers.find(tag.typeOfEntity);
+ it = tagHandlers.find(getBaseCommand(tag.typeOfEntity));
if (it != tagHandlers.end()) {
(this->*(it->second.first))(tag, translatedComment, it->second.second);
diff --git a/Source/Doxygen/pydoc.cxx b/Source/Doxygen/pydoc.cxx
index eb48993..f2031f4 100644
--- a/Source/Doxygen/pydoc.cxx
+++ b/Source/Doxygen/pydoc.cxx
@@ -174,7 +174,8 @@
} else {
if (lastLineWasNonBlank &&
(line.compare(pos, 13, ".. code-block") == 0 ||
- line.compare(pos, 7, ".. math") == 0)) {
+ line.compare(pos, 7, ".. math") == 0 ||
+ line.compare(pos, 3, ">>>") == 0)) {
// Must separate code or math blocks from the previous line
result += '\n';
}
@@ -184,6 +185,21 @@
return result;
}
+// Helper function to extract the option value from a command,
+// e.g. param[in] -> in
+static std::string getCommandOption(const std::string &command, char openChar, char closeChar) {
+ string option;
+
+ size_t opt_begin, opt_end;
+ opt_begin = command.find(openChar);
+ opt_end = command.find(closeChar);
+ if (opt_begin != string::npos && opt_end != string::npos)
+ option = command.substr(opt_begin+1, opt_end-opt_begin-1);
+
+ return option;
+}
+
+
/* static */
PyDocConverter::TagHandlersMap::mapped_type PyDocConverter::make_handler(tagHandler handler) {
return make_pair(handler, std::string());
@@ -245,7 +261,7 @@
tagHandlers["date"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["deprecated"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["details"] = make_handler(&PyDocConverter::handleParagraph);
- tagHandlers["em"] = make_handler(&PyDocConverter::handleParagraph, " ");
+ tagHandlers["em"] = make_handler(&PyDocConverter::handleTagWrap, "*");
tagHandlers["example"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["exception"] = tagHandlers["throw"] = tagHandlers["throws"] = make_handler(&PyDocConverter::handleTagException);
tagHandlers["htmlonly"] = make_handler(&PyDocConverter::handleParagraph);
@@ -254,7 +270,7 @@
tagHandlers["link"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["manonly"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["note"] = make_handler(&PyDocConverter::handleParagraph);
- tagHandlers["p"] = make_handler(&PyDocConverter::handleParagraph);
+ tagHandlers["p"] = make_handler(&PyDocConverter::handleTagWrap, "``");
tagHandlers["partofdescription"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["rtfonly"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["remark"] = make_handler(&PyDocConverter::handleParagraph);
@@ -428,6 +444,23 @@
return type;
}
+std::string PyDocConverter::getParamValue(std::string param) {
+ std::string value;
+
+ ParmList *plist = CopyParmList(Getattr(currentNode, "parms"));
+ for (Parm *p = plist; p; p = nextSibling(p)) {
+ String *pname = Getattr(p, "name");
+ if (Char(pname) != param)
+ continue;
+
+ String *pval = Getattr(p, "value");
+ if (pval) value = Char(pval);
+ break;
+ }
+ Delete(plist);
+ return value;
+}
+
std::string PyDocConverter::translateSubtree(DoxygenEntity &doxygenEntity) {
std::string translatedComment;
@@ -456,7 +489,7 @@
void PyDocConverter::translateEntity(DoxygenEntity &doxyEntity, std::string &translatedComment) {
// check if we have needed handler and call it
std::map<std::string, std::pair<tagHandler, std::string> >::iterator it;
- it = tagHandlers.find(doxyEntity.typeOfEntity);
+ it = tagHandlers.find(getBaseCommand(doxyEntity.typeOfEntity));
if (it != tagHandlers.end())
(this->*(it->second.first)) (doxyEntity, translatedComment, it->second.second);
}
@@ -531,19 +564,29 @@
trimWhitespace(translatedComment);
- // Use the current indent for the code-block line itself.
- translatedComment += indent.getFirstLineIndent();
-
- // Go out on a limb and assume that examples in the C or C++ sources use C++.
- // In the worst case, we'll highlight C code using C++ syntax which is not a
- // big deal (TODO: handle Doxygen code command language argument).
- translatedComment += ".. code-block:: c++\n\n";
-
- // Specify the level of extra indentation that will be used for
- // subsequent lines within the code block. Note that the correct
- // "starting indentation" is already present in the input, so we
- // only need to add the desired code block indentation.
- string codeIndent = m_indent;
+ // Check for an option given to the code command (e.g. code{.py}),
+ // and try to set the code-block language accordingly.
+ string option = getCommandOption(tag.typeOfEntity, '{', '}');
+ // Set up the language option to the code-block command, which can
+ // be any language supported by pygments:
+ string codeLanguage;
+ if (option == ".py")
+ // Other possibilities here are "default" or "python3". In Sphinx
+ // 2.1.2, basic syntax doesn't render quite the same in these as
+ // with "python", which for basic keywords seems to provide
+ // slightly richer formatting. Another option would be to leave
+ // the language empty, but testing with Sphinx 1.8.5 has produced
+ // an error "1 argument required".
+ codeLanguage = "python";
+ else if (option == ".java")
+ codeLanguage = "java";
+ else if (option == ".c")
+ codeLanguage = "c";
+ else
+ // If there is not a match, or if no option was given, go out on a
+ // limb and assume that the examples in the C or C++ sources use
+ // C++.
+ codeLanguage = "c++";
std::string code;
handleTagVerbatim(tag, code, arg);
@@ -552,6 +595,27 @@
// command:
eraseLeadingNewLine(code);
+ // Check for python doctest blocks, and treat them specially:
+ bool isDocTestBlock = false;
+ size_t startPos;
+ // ">>>" would normally appear at the beginning, but doxygen comment
+ // style may have space in front, so skip leading whitespace
+ if ((startPos=code.find_first_not_of(" \t")) != string::npos && code.substr(startPos,3) == ">>>")
+ isDocTestBlock = true;
+
+ string codeIndent;
+ if (! isDocTestBlock) {
+ // Use the current indent for the code-block line itself.
+ translatedComment += indent.getFirstLineIndent();
+ translatedComment += ".. code-block:: " + codeLanguage + "\n\n";
+
+ // Specify the level of extra indentation that will be used for
+ // subsequent lines within the code block. Note that the correct
+ // "starting indentation" is already present in the input, so we
+ // only need to add the desired code block indentation.
+ codeIndent = m_indent;
+ }
+
translatedComment += codeIndent;
for (size_t n = 0; n < code.length(); n++) {
if (code[n] == '\n') {
@@ -636,8 +700,26 @@
const std::string ¶mName = paramNameEntity.data;
const std::string paramType = getParamType(paramName);
+ const std::string paramValue = getParamValue(paramName);
+
+ // Get command option, e.g. "in", "out", or "in,out"
+ string commandOpt = getCommandOption(tag.typeOfEntity, '[', ']');
+ if (commandOpt == "in,out") commandOpt = "in/out";
+
+ // If provided, append the parameter direction to the type
+ // information via a suffix:
+ std::string suffix;
+ if (commandOpt.size() > 0)
+ suffix = ", " + commandOpt;
+
+ // If the parameter has a default value, flag it as optional in the
+ // generated type definition. Particularly helpful when the python
+ // call is generated with *args, **kwargs.
+ if (paramValue.size() > 0)
+ suffix += ", optional";
+
if (!paramType.empty()) {
- translatedComment += ":type " + paramName + ": " + paramType + "\n";
+ translatedComment += ":type " + paramName + ": " + paramType + suffix + "\n";
translatedComment += indent.getFirstLineIndent();
}
@@ -909,3 +991,4 @@
return NewString(pyDocString.c_str());
}
+
diff --git a/Source/Doxygen/pydoc.h b/Source/Doxygen/pydoc.h
index df8997d..07c5ce5 100644
--- a/Source/Doxygen/pydoc.h
+++ b/Source/Doxygen/pydoc.h
@@ -178,6 +178,11 @@
*/
std::string getParamType(std::string name);
+ /*
+ * Simple helper function to retrieve the parameter value
+ */
+ std::string getParamValue(std::string name);
+
private:
// temporary thing, should be refactored somehow
Node *currentNode;
diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx
index 17100b3..d08884b 100644
--- a/Source/Modules/csharp.cxx
+++ b/Source/Modules/csharp.cxx
@@ -4064,11 +4064,10 @@
/* Get the C# parameter type */
if ((tm = Getattr(p, "tmap:cstype"))) {
substituteClassname(pt, tm);
- if (Strncmp(tm, "ref ", 4) == 0) {
- Replace(tm, "ref ", "", DOH_REPLACE_FIRST);
+ int flags = DOH_REPLACE_FIRST | DOH_REPLACE_ID_BEGIN | DOH_REPLACE_NOCOMMENT;
+ if (Replace(tm, "ref ", "", flags) || Replace(tm, "ref\t", "", flags)) {
Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm);
- } else if (Strncmp(tm, "out ", 4) == 0) {
- Replace(tm, "out ", "", DOH_REPLACE_FIRST);
+ } else if (Replace(tm, "out ", "", flags) || Replace(tm, "out\t", "", flags)) {
Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm);
} else {
Printf(proxy_method_types, "typeof(%s)", tm);
diff --git a/Source/Modules/ocaml.cxx b/Source/Modules/ocaml.cxx
index 6f2a349..9f7504b 100644
--- a/Source/Modules/ocaml.cxx
+++ b/Source/Modules/ocaml.cxx
@@ -1619,7 +1619,7 @@
/* pass the method call on to the OCaml object */
Printv(w->code,
"swig_result = caml_swig_alloc(1,C_list);\n" "SWIG_Store_field(swig_result,0,args);\n" "args = swig_result;\n" "swig_result = Val_unit;\n", 0);
- Printf(w->code, "static CAML_VALUE *swig_ocaml_func_val = NULL;\n" "if (!swig_ocaml_func_val) {\n");
+ Printf(w->code, "static const CAML_VALUE *swig_ocaml_func_val = NULL;\n" "if (!swig_ocaml_func_val) {\n");
Printf(w->code, " swig_ocaml_func_val = caml_named_value(\"swig_runmethod\");\n }\n");
Printf(w->code, "swig_result = caml_callback3(*swig_ocaml_func_val,swig_get_self(),caml_copy_string(\"%s\"),args);\n", Getattr(n, "name"));
/* exception handling */
diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx
index ea31af0..1dbedad 100644
--- a/Source/Modules/python.cxx
+++ b/Source/Modules/python.cxx
@@ -2493,7 +2493,7 @@
String *symname = Getattr(n, "sym:name");
String *wname = Swig_name_wrapper(symname);
- const char *builtin_kwargs = builtin_ctor ? ", PyObject *SWIGUNUSEDPARM(kwargs)" : "";
+ const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : "";
Printv(f->def, linkage, builtin_ctor ? "int " : "PyObject *", wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL);
Wrapper_add_local(f, "argc", "Py_ssize_t argc");
@@ -2503,6 +2503,9 @@
if (!fastunpack) {
Wrapper_add_local(f, "ii", "Py_ssize_t ii");
+ if (builtin_ctor)
+ Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname);
+
if (maxargs - (add_self ? 1 : 0) > 0) {
Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n");
Append(f->code, "argc = PyObject_Length(args);\n");
@@ -2518,8 +2521,9 @@
if (add_self)
Append(f->code, "argc++;\n");
} else {
- String *iname = Getattr(n, "sym:name");
- Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args, \"%s\", 0, %d, argv%s))) SWIG_fail;\n", iname, maxargs, add_self ? "+1" : "");
+ if (builtin_ctor)
+ Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname);
+ Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args, \"%s\", 0, %d, argv%s))) SWIG_fail;\n", symname, maxargs, add_self ? "+1" : "");
if (add_self)
Append(f->code, "argv[0] = self;\n");
else
@@ -2700,8 +2704,12 @@
--tuple_required;
}
num_fixed_arguments = tuple_required;
+
+ // builtin handles/checks kwargs by default except in constructor wrappers so we need to explicitly handle them in the C constructor wrapper
+ // The check below is for zero arguments. Sometimes (eg directors) self is the first argument for a method with zero arguments.
if (((num_arguments == 0) && (num_required == 0)) || ((num_arguments == 1) && (num_required == 1) && Getattr(l, "self")))
- allow_kwargs = 0;
+ if (!builtin_ctor)
+ allow_kwargs = 0;
varargs = emit_isvarargs(l);
String *wname = Copy(wrapper_name);
@@ -2709,7 +2717,7 @@
Append(wname, overname);
}
- const char *builtin_kwargs = builtin_ctor ? ", PyObject *SWIGUNUSEDPARM(kwargs)" : "";
+ const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : "";
if (!allow_kwargs || overname) {
if (!varargs) {
Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL);
@@ -2727,7 +2735,7 @@
}
Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args, PyObject *kwargs) {", NIL);
}
- if (!builtin || !in_class || tuple_arguments > 0) {
+ if (!builtin || !in_class || tuple_arguments > 0 || builtin_ctor) {
if (!allow_kwargs) {
Append(parse_args, " if (!PyArg_ParseTuple(args, \"");
} else {
@@ -2876,14 +2884,13 @@
Printv(f->locals, " char * kwnames[] = ", kwargs, ";\n", NIL);
}
- if (builtin && !funpack && in_class && tuple_arguments == 0) {
- Printf(parse_args, " if (args && PyTuple_Check(args) && PyTuple_GET_SIZE(args) > 0) SWIG_exception_fail(SWIG_TypeError, \"%s takes no arguments\");\n", iname);
- } else if (use_parse || allow_kwargs) {
+ if (use_parse || allow_kwargs) {
Printf(parse_args, ":%s\"", iname);
Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL);
funpack = 0;
} else {
Clear(parse_args);
+
if (funpack) {
Clear(f->def);
if (overname) {
@@ -2896,6 +2903,8 @@
} else {
int is_tp_call = Equal(Getattr(n, "feature:python:slot"), "tp_call");
Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL);
+ if (builtin_ctor)
+ Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname);
if (onearg && !builtin_ctor && !is_tp_call) {
Printf(parse_args, "if (!args) SWIG_fail;\n");
Append(parse_args, "swig_obj[0] = args;\n");
@@ -2906,8 +2915,14 @@
}
}
} else {
- Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments);
- Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL);
+ if (builtin_ctor)
+ Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname);
+ if (builtin && in_class && tuple_arguments == 0) {
+ Printf(parse_args, " if (args && PyTuple_Check(args) && PyTuple_GET_SIZE(args) > 0) SWIG_exception_fail(SWIG_TypeError, \"%s takes no arguments\");\n", iname);
+ } else {
+ Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments);
+ Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL);
+ }
}
}
@@ -4128,6 +4143,13 @@
Printv(f, "#if PY_VERSION_HEX >= 0x03040000\n", NIL);
printSlot(f, getSlot(n, "feature:python:tp_finalize"), "tp_finalize", "destructor");
Printv(f, "#endif\n", NIL);
+ Printv(f, "#if PY_VERSION_HEX >= 0x03080000\n", NIL);
+ printSlot(f, getSlot(n, "feature:python:tp_vectorcall"), "tp_vectorcall", "vectorcallfunc");
+ Printv(f, "#endif\n", NIL);
+ Printv(f, "#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)\n", NIL);
+ printSlot(f, getSlot(), "tp_print");
+ Printv(f, "#endif\n", NIL);
+
Printv(f, "#ifdef COUNT_ALLOCS\n", NIL);
printSlot(f, getSlot(n, "feature:python:tp_allocs"), "tp_allocs", "Py_ssize_t");
printSlot(f, getSlot(n, "feature:python:tp_frees"), "tp_frees", "Py_ssize_t");
diff --git a/Source/Modules/ruby.cxx b/Source/Modules/ruby.cxx
index 6a1e16d..48b0efa 100644
--- a/Source/Modules/ruby.cxx
+++ b/Source/Modules/ruby.cxx
@@ -2191,6 +2191,12 @@
String *tm;
String *getfname, *setfname;
Wrapper *getf, *setf;
+ const int assignable = is_assignable(n);
+
+ // Determine whether virtual global variables shall be used
+ // which have different getter and setter signatures,
+ // see https://docs.ruby-lang.org/en/2.6.0/extension_rdoc.html#label-Global+Variables+Shared+Between+C+and+Ruby
+ const bool use_virtual_var = (current == NO_CPP && useGlobalModule);
getf = NewWrapper();
setf = NewWrapper();
@@ -2201,7 +2207,7 @@
getfname = Swig_name_wrapper(getname);
Setattr(n, "wrap:name", getfname);
Printv(getf->def, "SWIGINTERN VALUE\n", getfname, "(", NIL);
- Printf(getf->def, "VALUE self");
+ Printf(getf->def, (use_virtual_var) ? "ID id, VALUE *data" : "VALUE self");
Printf(getf->def, ") {");
Wrapper_add_local(getf, "_val", "VALUE _val");
@@ -2224,8 +2230,8 @@
Wrapper_print(getf, f_wrappers);
- if (!is_assignable(n)) {
- setfname = NewString("NULL");
+ if (!assignable) {
+ setfname = NewString("(rb_gvar_setter_t *)NULL");
} else {
/* create setter */
String* docs = docstring(n, AUTODOC_SETTER);
@@ -2235,8 +2241,12 @@
String *setname = Swig_name_set(NSPACE_TODO, iname);
setfname = Swig_name_wrapper(setname);
Setattr(n, "wrap:name", setfname);
- Printv(setf->def, "SWIGINTERN VALUE\n", setfname, "(VALUE self, ", NIL);
- Printf(setf->def, "VALUE _val) {");
+ Printf(setf->def, "SWIGINTERN ");
+ if (use_virtual_var) {
+ Printv(setf->def, "void\n", setfname, "(VALUE _val, ID id, VALUE *data) {", NIL);
+ } else {
+ Printv(setf->def, "VALUE\n", setfname, "(VALUE self, VALUE _val) {", NIL);
+ }
tm = Swig_typemap_lookup("varin", n, name, 0);
if (tm) {
Replaceall(tm, "$input", "_val");
@@ -2247,28 +2257,31 @@
} else {
Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s\n", SwigType_str(t, 0));
}
- Printv(setf->code, tab4, "return _val;\n", NIL);
- Printf(setf->code, "fail:\n");
- Printv(setf->code, tab4, "return Qnil;\n", NIL);
+ if (use_virtual_var) {
+ Printf(setf->code, "fail:\n");
+ Printv(setf->code, tab4, "return;\n", NIL);
+ } else {
+ Printv(setf->code, tab4, "return _val;\n", NIL);
+ Printf(setf->code, "fail:\n");
+ Printv(setf->code, tab4, "return Qnil;\n", NIL);
+ }
Printf(setf->code, "}\n");
Wrapper_print(setf, f_wrappers);
Delete(setname);
}
- /* define accessor method */
- if (CPlusPlus) {
- Insert(getfname, 0, "VALUEFUNC(");
- Append(getfname, ")");
- Insert(setfname, 0, "VALUEFUNC(");
- Append(setfname, ")");
- }
+ /* define accessor methods */
+ Insert(getfname, 0, "VALUEFUNC(");
+ Append(getfname, ")");
+ Insert(setfname, 0, (use_virtual_var) ? "SWIG_RUBY_VOID_ANYARGS_FUNC(" : "VALUEFUNC(");
+ Append(setfname, ")");
String *s = NewString("");
switch (current) {
case STATIC_VAR:
/* C++ class variable */
Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "\", ", getfname, ", 0);\n", NIL);
- if (!GetFlag(n, "feature:immutable")) {
+ if (assignable) {
Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "=\", ", setfname, ", 1);\n", NIL);
}
Printv(klass->init, s, NIL);
@@ -2279,14 +2292,11 @@
assert(current == NO_CPP);
if (!useGlobalModule) {
Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "\", ", getfname, ", 0);\n", NIL);
- if (!GetFlag(n, "feature:immutable")) {
+ if (assignable) {
Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "=\", ", setfname, ", 1);\n", NIL);
}
} else {
- Printv(s, tab4, "rb_define_global_method(\"", iname, "\", ", getfname, ", 0);\n", NIL);
- if (!GetFlag(n, "feature:immutable")) {
- Printv(s, tab4, "rb_define_global_method(\"", iname, "=\", ", setfname, ", 1);\n", NIL);
- }
+ Printv(s, tab4, "rb_define_virtual_variable(\"$", iname, "\", ", getfname, ", ", setfname, ");\n", NIL);
}
Printv(f_init, s, NIL);
Delete(s);
diff --git a/Tools/travis-linux-install.sh b/Tools/travis-linux-install.sh
index e902137..c8347d2 100755
--- a/Tools/travis-linux-install.sh
+++ b/Tools/travis-linux-install.sh
@@ -23,8 +23,8 @@
travis_retry sudo apt-get -qq install mono-devel
;;
"d")
- travis_retry wget http://downloads.dlang.org/releases/2014/dmd_2.066.0-0_amd64.deb
- travis_retry sudo dpkg -i dmd_2.066.0-0_amd64.deb
+ travis_retry wget http://downloads.dlang.org/releases/2.x/${VER}/dmd_${VER}-0_amd64.deb
+ travis_retry sudo dpkg -i dmd_${VER}-0_amd64.deb
;;
"go")
if [[ "$VER" ]]; then
@@ -95,6 +95,12 @@
travis_retry sudo apt-get -qq install r-base
;;
"ruby")
+ if [[ "$VER" == "2.7" ]]; then
+ # Ruby 2.7 support is currently only rvm master (30 Dec 2019)
+ travis_retry rvm get master
+ rvm reload
+ rvm list known
+ fi
if [[ "$VER" ]]; then
travis_retry rvm install $VER
fi
diff --git a/appveyor.yml b/appveyor.yml
index 42eaa36..f87cefd 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -16,10 +16,10 @@
- SWIGLANG: python
VSVER: 14
VER: 27
- - SWIGLANG: python
- VSVER: 14
- VER: 36
- PY3: 3
+# - SWIGLANG: python
+# VSVER: 14
+# VER: 36
+# PY3: 3
- SWIGLANG: python
OSVARIANT: cygwin
- SWIGLANG: python
diff --git a/configure.ac b/configure.ac
index ea469c2..b4cadef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1348,6 +1348,33 @@
JAVAC="$JAVACBIN"
fi
+# Check Java version: we require Java 9 or later for Doxygen tests.
+if test -n "$JAVAC"; then
+ AC_MSG_CHECKING(if java version is 9 or greater)
+ javac_version=`"$JAVAC" -version 2>&1`
+ java_version_num=`echo $javac_version | sed -n 's/^javac //p'`
+ if test -z "$java_version_num"; then
+ AC_MSG_WARN([unknown format for Java version returned by "$JAVAC" ($javac_version)])
+ JAVA_SKIP_DOXYGEN_TEST_CASES=1
+ AC_MSG_RESULT(unknown)
+ else
+ dnl Until Java 8 version number was in format "1.x", starting from
+ dnl Java 9 it's just "x".
+ case $java_version_num in
+ 1.*)
+ JAVA_SKIP_DOXYGEN_TEST_CASES=1
+ AC_MSG_RESULT([no, disabling Doxygen tests])
+ ;;
+
+ *)
+ AC_MSG_RESULT(yes)
+ ;;
+ esac
+ fi
+
+ AC_SUBST(JAVA_SKIP_DOXYGEN_TEST_CASES)
+fi
+
AC_MSG_CHECKING(for java include file jni.h)
AC_ARG_WITH(javaincl, [ --with-javaincl=path Set location of Java include directory], [JAVAINCDIR="$withval"], [JAVAINCDIR=])
@@ -1408,15 +1435,6 @@
fi
fi
-# Javadoc support required for the Java test-suite is available by default in jdk9+ and in tools.jar in earlier jdk versions
-AC_MSG_CHECKING(for java tools.jar)
-if test -n "$JAVA_HOME" && test -r "$JAVA_HOME/lib/tools.jar" ; then
- JAVA_TOOLS_JAR="$JAVA_HOME/lib/tools.jar"
- AC_MSG_RESULT([$JAVA_TOOLS_JAR])
-else
- AC_MSG_RESULT(not found)
-fi
-
case $host in
*-*-cygwin*)
# TODO: Only use this flag if the compiler supports it, later versions of gcc no longer have it
@@ -1483,7 +1501,6 @@
AC_SUBST(JAVAC)
AC_SUBST(JAVAINC)
AC_SUBST(JAVA_CLASSPATH_SEP)
-AC_SUBST(JAVA_TOOLS_JAR)
AC_SUBST(JAVADYNAMICLINKING)
AC_SUBST(JAVALIBRARYPREFIX)
AC_SUBST(JAVASO)