Merge branch 'fbo/indus_doc_csharp'

This commit is contained in:
Olly Betts 2024-09-15 09:59:05 +12:00
commit e02efe25db
22 changed files with 2695 additions and 23 deletions

View File

@ -137,6 +137,12 @@ swig -csharp -help
</td>
</tr>
<tr>
<td>-doxygen</td>
<td> Convert C++ doxygen comments to CSharp comments
</td>
</tr>
</table>
<p>

View File

@ -37,6 +37,13 @@
<li><a href="#Doxygen_python_unsupported_tags">Unsupported tags</a>
<li><a href="#Doxygen_python_further_details">Further details</a>
</ul>
<li><a href="#Doxygen_to_csharpXml">Doxygen to CSharp XML</a>
<ul>
<li><a href="#Doxygen_csharp_basic_example">Basic example</a>
<li><a href="#Doxygen_csharp_tags">CSharp XML tags</a>
<li><a href="#Doxygen_csharp_unsupported_tags">Unsupported tags</a>
<li><a href="#Doxygen_csharp_further_details">Further details</a>
</ul>
<li><a href="#Doxygen_troubleshooting">Troubleshooting</a>
<ul>
<li><a href="#troubleshooting_ifndef">Problem with conditional compilation</a>
@ -1550,7 +1557,570 @@ Here is the list of these tags:
TO BE ADDED.
</p>
<H2><a name="Doxygen_troubleshooting">18.5 Troubleshooting</a></H2>
<H2><a name="Doxygen_to_csharpXml">18.5 Doxygen to XML Csharp documentation</a></H2>
<p>
If translation is enabled, XML formatted comments should be
automatically placed in the correct locations in the resulting module
and proxy files.
</p>
<H3><a name="Doxygen_csharp_basic_example">18.5.1 Basic example</a></H3>
<p>
Here is an example segment from an included header file
</p>
<div class="code"><pre>
/*! This is describing class Shape
\author Bob
*/
class Shape {
public:
Shape() {
nshapes++;
}
virtual ~Shape() {
nshapes--;
};
/** Important Variables x*/
double x;
/** Important Variables y*/
double y;
/** Moves the Shape
* @param dx delta on x
* @param dy delta on y */
void move(double dx, double dy);
/** \return the area */
virtual double area(void) = 0;
/** \return the perimeter */
virtual double perimeter(void) = 0;
static int nshapes;
};
</pre></div>
<p>
Simply running SWIG should result in the following code being present in Shapes.cs
</p>
<div class="targetlang"><pre>
/// &lt;summary&gt;This is describing class Shape
/// Author: Bob
/// &lt;/summary&gt;
public class Shape {
...
/// Important Variables x
public double x {
set {
ShapesCsPINVOKE.Shape_x_set(swigCPtr, value);
}
get {
double ret = ShapesCsPINVOKE.Shape_x_get(swigCPtr);
return ret;
}
}
/// Important Variables y
public double y {
set {
ShapesCsPINVOKE.Shape_y_set(swigCPtr, value);
}
get {
double ret = ShapesCsPINVOKE.Shape_y_get(swigCPtr);
return ret;
}
}
/// Moves the Shape
/// &lt;param name="dx"&gt; delta on x&lt;/param&gt;
/// &lt;param name="dy"&gt; delta on y&lt;/param&gt;
public void move(double dx, double dy) {
ShapesCsPINVOKE.Shape_move(swigCPtr, dx, dy);
}
/// &lt;returns&gt;the area&lt;/returns&gt;
public virtual double area() {
double ret = ShapesCsPINVOKE.Shape_area(swigCPtr);
return ret;
}
/// &lt;returns&gt;the perimeter&lt;/returns&gt;
public virtual double perimeter() {
double ret = ShapesCsPINVOKE.Shape_perimeter(swigCPtr);
return ret;
}
public static int nshapes {
set {
ShapesCsPINVOKE.Shape_nshapes_set(value);
}
get {
int ret = ShapesCsPINVOKE.Shape_nshapes_get();
return ret;
}
}
}
</pre></div>
<p>
The code CSharp-wise should be identical to what would have been
generated without the doxygen functionality enabled. When the Doxygen Translator
module encounters a comment that contains nothing useful or a doxygen comment that it cannot
parse, it will not affect the functionality of the SWIG generated
code.
</p>
<p>
The translator will handle most of the tags conversions (see the
table below). It will also automatically translate link-objects
params, in &lt;seealso&gt; tags .
Also all '\param' and '\tparam' commands are stripped out, if the specified parameter is not present in
the function. Use 'doxygen:nostripparams' to avoid.
</p>
<p>
CSharp translator features summary
(see <a href="Customization.html#Customization_features">%feature
directives</a>):
</p>
<H3><a name="Doxygen_csharp_tags">18.5.2 CSharp tags</a></H3>
<p>
Here is the list of all Doxygen tags and the description of how they are translated to CSharp XML
</p>
<div class="diagram">
<table border="0" summary="CSharp XML Doxygen tags">
<tr>
<th align="left">Doxygen tags</th>
</tr>
<tr>
<td>\a</td>
<td>wrapped with '*' markdown character</td>
</tr>
<tr>
<td>\arg</td>
<td>prefixed with '*' markdown character</td>
</tr>
<tr>
<td>\author</td>
<td>Made simple text with prefix 'Author:'</td>
</tr>
<tr>
<td>\authors</td>
<td>Made simple text with prefix 'Author:'</td>
</tr>
<tr>
<td>\b</td>
<td>wrapped with '**' markdown character</td>
</tr>
<tr>
<td>\c</td>
<td>wrapped with `` markdown character</td>
</tr>
<tr>
<td>\cite</td>
<td>started with ' markdown character</td>
</tr>
<tr>
<td>\code</td>
<td>wrapped in &lt;code&gt; tag </td>
</tr>
<tr>
<td>\code{&lt;ext&gt;}</td>
<td>wrapped in &lt;code&gt; tag. code language extension is ignored</td>
</tr>
<tr>
<td>\cond</td>
<td>Ignored</td>
</tr>
<tr>
<td>\copyright</td>
<td>wrapped in &lt;remark&gt; tag</td>
</tr>
<tr>
<td>\deprecated</td>
<td>Made simple text with prefix 'Deprecated:' </td>
</tr>
<tr>
<td>\e</td>
<td>prefixed with '*' markdown character</td>
</tr>
<tr>
<td>\else</td>
<td>Ignored</td>
</tr>
<tr>
<td>\elseif</td>
<td>Ignored</td>
</tr>
<tr>
<td>\em</td>
<td>prefixed with '*' markdown character</td>
</tr>
<tr>
<td>\endcode</td>
<td>wrapped in &lt;code&gt; tag. code language extension is ignored</td>
</tr>
<tr>
<td>\endcond</td>
<td>Ignored</td>
</tr>
<tr>
<td>\endif</td>
<td>Ignored</td>
</tr>
<tr>
<td>\endlink</td>
<td>Ignored</td>
</tr>
<tr>
<td>\endverbatim</td>
<td>see note for \verbatim</td>
</tr>
<tr>
<td>\exception</td>
<td>translated to &lt;exception&gt; section</td>
</tr>
<tr>
<td>\f$, \f[, \f], \f{, \f}</td>
<td>Ignored</td>
</tr>
<tr>
<td>\if</td>
<td>Ignored</td>
</tr>
<tr>
<td>\ifnot</td>
<td>Ignored</td>
</tr>
<tr>
<td>\image</td>
<td>Ignored</td>
</tr>
<tr>
<td>\li</td>
<td>Ignored</td>
</tr>
<tr>
<td>\link</td>
<td>Ignored</td>
</tr>
<tr>
<td>\n</td>
<td>replaced with newline char</td>
</tr>
<tr>
<td>\note</td>
<td>Content copied</td>
</tr>
<tr>
<td>\overload</td>
<td>Ignored</td>
</tr>
<tr>
<td>\p</td>
<td>wrapped with `` markdown characters</td>
</tr>
<tr>
<td>\par</td>
<td>Made simple text with prefix "Title:"</td>
</tr>
<tr>
<td>\param</td>
<td>translated to &lt;param&gt; xml section</td>
</tr>
<tr>
<td>\param[&lt;dir&gt;]</td>
<td>translated to &lt;param&gt; xml section; parameter direction ('in'; 'out'; or 'in,out') is ignored</td>
</tr>
<tr>
<td>\remark</td>
<td>Made simple text with prefix "remarks:"</td>
</tr>
<tr>
<td>\remarks</td>
<td>Made simple text with prefix "remarks:"</td>
</tr>
<tr>
<td>\result</td>
<td>translated to &lt;return&gt; xml section</td>
</tr>
<tr>
<td>\return</td>
<td>translated to &lt;return&gt; xml section</td>
</tr>
<tr>
<td>\returns</td>
<td>translated to &lt;return&gt; xml section</td>
</tr>
<tr>
<td>\sa</td>
<td>translated to &lt;seealso&gt; xml section</td>
</tr>
<tr>
<td>\see</td>
<td>translated to &lt;seealso&gt; xml section</td>
</tr>
<tr>
<td>\since</td>
<td>Content copied</td>
</tr>
<tr>
<td>\throw</td>
<td>translated to &lt;exception&gt;</td>
</tr>
<tr>
<td>\throws</td>
<td>translated to &lt;exception&gt;</td>
</tr>
<tr>
<td>\todo</td>
<td>Prefixed with 'TODO:'</td>
</tr>
<tr>
<td>\tparam</td>
<td>translated to &lt;exception&gt; xml section</td>
</tr>
<tr>
<td>\verbatim</td>
<td>copied without any processing</td>
</tr>
<tr>
<td>\version</td>
<td>Made simple text with prefix 'Version:"</td>
</tr>
<tr>
<td>\warning</td>
<td>Made simple text with prefix 'remarks:"</td>
</tr>
<tr>
<td>\$</td>
<td>prints $ char</td>
</tr>
<tr>
<td>\@</td>
<td>prints @ char</td>
</tr>
<tr>
<td>\\</td>
<td>prints \ char</td>
</tr>
<tr>
<td>\&amp;</td>
<td>prints &amp; char</td>
</tr>
<tr>
<td>\~</td>
<td>prints ~ char</td>
</tr>
<tr>
<td>\&lt;</td>
<td>prints &lt; char</td>
</tr>
<tr>
<td>\&gt;</td>
<td>prints &gt; char</td>
</tr>
<tr>
<td>\#</td>
<td>prints # char</td>
</tr>
<tr>
<td>\%</td>
<td>prints % char</td>
</tr>
<tr>
<td>\&quot;</td>
<td>prints &quot; char</td>
</tr>
<tr>
<td>\.</td>
<td>prints . char</td>
</tr>
<tr>
<td>\::</td>
<td>prints ::</td>
</tr>
</table>
</div>
<H3><a name="Doxygen_csharp_unsupported_tags">18.5.3 Unsupported tags</a></H3>
<p>
Doxygen has a wealth of tags such as @latexonly that have no
equivalent in CSharp XML (all supported tags are listed in
<a href="https://www.doxygen.nl/manual/xmlcmds.html">XML documentation</a>).
As a result several tags have no
translation or particular use, such as some linking and section tags.
These are suppressed with their content just printed out (if the tag has any
sense, typically text content).
Here is the list of these tags:
</p>
<div class="diagram">
<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>
If one of the following Doxygen tags appears as the first tag in a
comment, the whole comment block is ignored:
<!-- see parser.y, function isStructuralDoxygen() -->
</p>
<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>
<H3><a name="Doxygen_csharp_further_details">18.5.4 Further details</a></H3>
<H2><a name="Doxygen_troubleshooting">18.6 Troubleshooting</a></H2>
<p>
@ -1572,7 +2142,7 @@ include the option and fix problems with Doxygen comments.
</p>
<H3><a name="troubleshooting_ifndef">18.5.1 Problem with conditional compilation</a></H3>
<H3><a name="troubleshooting_ifndef">18.6.1 Problem with conditional compilation</a></H3>
<p>
@ -1612,14 +2182,14 @@ class A {
</pre></div>
<H2><a name="Doxygen_developer_details">18.6 Developer information</a></H2>
<H2><a name="Doxygen_developer_details">18.7 Developer information</a></H2>
<p>
This section contains information for developers enhancing the Doxygen translator.
</p>
<H3><a name="Doxygen_translator_design">18.6.1 Doxygen translator design</a></H3>
<H3><a name="Doxygen_translator_design">18.7.1 Doxygen translator design</a></H3>
<p>
@ -1645,7 +2215,7 @@ class for translation into the target documentation language. For
example, <tt>JavaDocConverter</tt> is the Javadoc module class.
</p>
<H3><a name="Doxygen_debugging_commands">18.6.2 Debugging the Doxygen parser and translator</a></H3>
<H3><a name="Doxygen_debugging_commands">18.7.2 Debugging the Doxygen parser and translator</a></H3>
<p>
@ -1658,7 +2228,7 @@ detailed debug information printing.
-debug-doxygen-translator - Display Doxygen translator module debugging information
</pre></div>
<H3><a name="Doxygen_tests">18.6.3 Tests</a></H3>
<H3><a name="Doxygen_tests">18.7.3 Tests</a></H3>
<p>
@ -1690,7 +2260,7 @@ tool, for example:
Examples/test-suite/java $ kdiff3 expected.txt got.txt
</pre></div>
<p>
Runtime tests in Java are implemented using Javadoc doclets. To make that work, you
should have tools.jar from the JDK in your classpath. Or you should have JAVA_HOME
@ -1710,7 +2280,7 @@ Runtime tests in Python are just plain string comparisons of the __doc__
properties.
</p>
<H2><a name="Doxygen_language_extension">18.7 Extending to other languages</a></H2>
<H2><a name="Doxygen_language_extension">18.8 Extending to other languages</a></H2>
<p>

View File

@ -711,11 +711,12 @@ CPP20_TEST_CASES += \
CPP20_TEST_BROKEN = \
# Doxygen support test cases: can only be used with languages supporting
# Doxygen comment translation (currently Python and Java) and only if not
# Doxygen comment translation (currently a subset of languages) and only if not
# disabled by configure via SKIP_DOXYGEN_TEST_CASES.
ifneq ($(SKIP_DOXYGEN_TEST_CASES),1)
python_HAS_DOXYGEN := 1
csharp_HAS_DOXYGEN := 1
java_HAS_DOXYGEN := 1
python_HAS_DOXYGEN := 1
HAS_DOXYGEN := $($(LANGUAGE)_HAS_DOXYGEN)
endif

View File

@ -59,11 +59,14 @@ SWIGOPT += -namespace $*Namespace
CSHARPFLAGSSPECIAL =
# Custom tests - tests with additional commandline options
intermediary_classname.cpptest: SWIGOPT += -dllimport intermediary_classname
complextest.cpptest: CSHARPFLAGSSPECIAL = -r:System.Numerics.dll
csharp_lib_arrays.cpptest: CSHARPFLAGSSPECIAL = -unsafe
csharp_lib_arrays_bool.cpptest: CSHARPFLAGSSPECIAL = -unsafe
csharp_swig2_compatibility.cpptest: SWIGOPT += -DSWIG2_CSHARP
# Doxygen tests have specific flags to generate XML documentation and deactivate warnings about XML generation
doxygen_%.cpptest: CSHARPFLAGSSPECIAL = -doc:./$*/$*.xml -nowarn:"CS0419,CS1572,CS1573,CS1574,CS1584,CS1591"
doxygen_%.cpptest: CSHARPSRCS_EXTRA_RUN = `$(CSHARPCONVERTPATH) $(SCRIPTDIR)/doxygen_checker.cs`
intermediary_classname.cpptest: SWIGOPT += -dllimport intermediary_classname
# Rules for the different types of tests
%.cpptest:
@ -100,13 +103,12 @@ run_testcase = \
if [ -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then \
$(MAKE) -f $*/$(top_builddir)/$(EXAMPLES)/Makefile \
CSHARPFLAGS='-nologo -debug+ $(CSHARPFLAGSSPECIAL) -out:$*_runme.exe' \
CSHARPSRCS='`$(CSHARPCONVERTPATH) $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX)` `find $* -name "*.cs" -exec $(CSHARPCONVERTPATH) "{}" \+`' csharp_compile && \
CSHARPSRCS='`$(CSHARPCONVERTPATH) $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX)` `find $* -name "*.cs" -exec $(CSHARPCONVERTPATH) "{}" \+` $(CSHARPSRCS_EXTRA_RUN)' csharp_compile && \
env LD_LIBRARY_PATH="$*:$$LD_LIBRARY_PATH" PATH="$*:$$PATH" SHLIB_PATH="$*:$$SHLIB_PATH" DYLD_FALLBACK_LIBRARY_PATH= $(RUNTOOL) $(CSHARPCILINTERPRETER) $(CSHARPCILINTERPRETER_FLAGS) ./$*_runme.exe; \
else \
cd $* && \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile \
CSHARPFLAGS='-nologo -debug+ $(CSHARPFLAGSSPECIAL) -t:module -out:$*.netmodule' \
CSHARPSRCS='`find . -name "*.cs" -exec ../$(CSHARPCONVERTPATH) "{}" \+`' csharp_compile; \
$(MAKE) -f $*/$(top_builddir)/$(EXAMPLES)/Makefile \
CSHARPFLAGS='-nologo -debug+ $(CSHARPFLAGSSPECIAL) -t:module -out:$*/$*.netmodule' \
CSHARPSRCS='`find $* -name "*.cs" -exec $(CSHARPCONVERTPATH) "{}" \+`' csharp_compile; \
fi
# Clean: remove testcase directories

View File

@ -0,0 +1,138 @@
using System;
using System.Xml;
using System.IO;
using doxygen_basic_translateNamespace;
public class doxygen_basic_translate_runme {
doxygen_checker _checker;
public static void Main() {
doxygen_basic_translate_runme runme = new doxygen_basic_translate_runme();
runme.test_function1();
runme.test_function2();
runme.test_function3();
runme.test_function3_bis();
runme.test_function4();
runme.test_function5();
runme.test_function6();
runme.test_function6_bis();
runme.test_function7();
runme.test_atan2();
runme.test_function8();
runme.test_function9();
}
public doxygen_basic_translate_runme()
{
_checker = new doxygen_checker("doxygen_basic_translate", "doxygen_basic_translate","./doxygen_basic_translate/doxygen_basic_translate.xml");
}
public void test_function1()
{
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "function", "summary", 0, "Brief description.");
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function", @"
The comment text.
Author: Some author
");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "function", "returns", 0, "Some number");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, "function", "seealso", 0, "cref", "M:doxygen_basic_translateNamespace.doxygen_basic_translate.function2");
}
public void test_function2()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function2", @"
A test of a very very very very very very very very very very very very very very very very
very very very very very long comment string.
");
}
public void test_function3()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function3(System.Int32)", @"
A test for overloaded functions
This is function **one**
");
}
public void test_function3_bis()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function3(System.Int32,System.Int32)", @"
A test for overloaded functions
This is function **two**
");
}
public void test_function4()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function4", @"
A test of some mixed tag usage
This *code* fragment shows us something .
Title: Minuses:
* it's senseless
* it's stupid
* it's null
");
}
public void test_function5()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function5(System.Int32)", @"
This is a post comment.
");
}
public void test_function6()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function6(System.Int32)", @"
Test for default args
");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, "function6(System.Int32)", "param", 0, "name", "a");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "function6(System.Int32)", "param", 0, " Some parameter, default is 42");
}
public void test_function6_bis()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function6", @"
Test for default args
");
}
public void test_function7()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "function7(doxygen_basic_translateNamespace.SWIGTYPE_p_p_p_Shape)", @"
Test for a parameter with difficult type
(mostly for python)
");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, "function7(doxygen_basic_translateNamespace.SWIGTYPE_p_p_p_Shape)", "param", 0, "name", "a");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "function7(doxygen_basic_translateNamespace.SWIGTYPE_p_p_p_Shape)", "param", 0, " Very strange param");
}
public void test_atan2()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "Atan2(System.Double,System.Double)", @"
Multiple parameters test.
");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, "Atan2(System.Double,System.Double)", "param", 0, "name", "y");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, "Atan2(System.Double,System.Double)", "param", 1, "name", "x");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "Atan2(System.Double,System.Double)", "param", 0, " Vertical coordinate.");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "Atan2(System.Double,System.Double)", "param", 1, " Horizontal coordinate.");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "Atan2(System.Double,System.Double)", "returns", 0, "Arc tangent of ``y/x``.");
}
public void test_function8()
{
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "function8", "summary", 0, "Test variadic function");
}
public void test_function9()
{
_checker.checkObject(doxygen_checker.CodeType.MEMBER, "function9(System.Int32)", "summary", 0, "Test unnamed argument");
}
}

View File

@ -0,0 +1,183 @@
using System;
using System.Xml;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
/// Class used to check XML documentation content generated
/// by C# compiler for Doxygen tests.
/// Methods allow to look for the documentation of a specific object (method, type, variable)
/// and to check its content.
public class doxygen_checker{
private XmlElement _root;
private string _namespace_prefix;
/// Enum to identify the different types of objects in XML
public enum CodeType
{
/// <summary>member of a class/type</summary>
MEMBER,
/// <summary>class/type itself</summary>
TYPE
};
/// <summary> Constructor </summary>
///
/// <param name="namespaceName"> The name of namespace to consider </param>
/// <param name="className"> The name of the class inside the namespace </param>
/// <param name="xmlFilePath"> The file path where the XML to parse is located</param>
public doxygen_checker(string namespaceName, string className, string xmlFilePath)
{
XmlDocument doc = new XmlDocument();
string fileContent;
try{
fileContent = File.ReadAllText(xmlFilePath);
}
catch (Exception e)
{
throw new ApplicationException("Error: " + e.Message);
}
doc.LoadXml(fileContent);
_root = doc.DocumentElement; //get the root element.
_namespace_prefix = namespaceName +"Namespace." + className + ".";
}
/// <summary>Check general content (not included in a tag) of an object </summary>
///
/// <param name="codeType"> The type of object to check </param>
/// <param name="objectName"> The name of the object (function mostly) to check </param>
/// <param name="expectedContent"> The content of the documentation for the given object </param>
/// <exception cref="ApplicationException"> When object or expected content is not found </exception>
public void checkText(CodeType codeType, string objectName, string expectedContent)
{
string completeObjectName = _createObjectName(codeType, objectName);
bool found = false;
_root.SelectNodes("members/member").Cast<XmlElement>().ToList().ForEach(member =>
{
if (member.Attributes["name"].Value == completeObjectName)
{
found = true;
// parse all children of member until #text is found
string valMember = member.ChildNodes.Cast<XmlNode>().ToList().Find(node => node.Name == "#text").InnerText;
if (uniformizeString(expectedContent) != uniformizeString(valMember))
{
throw new ApplicationException("Error: " + objectName + " contains '" + valMember + "', expected '" + expectedContent + "'");
}
return;
}
});
if (!found)
throw new ApplicationException("Object '" + objectName + "' not found");
}
/// <summary>Check field content from an object</summary>
///
/// <param name="codeType">The type of object to check </param>
/// <param name="objectName">The name of object (function mostly) to check </param>
/// <param name="fieldName">The name of the XML tag (summary, param,...) of the object to check </param>
/// <param name="itemIndex"> The index of the field (0 for the first one, 1 for the second, etc) to check </param>
/// <param name="expectedContent"> The content of the documentation for the given object </param>
/// <exception cref="ApplicationException"> When object, field, or expected content is not found </exception>
public void checkObject(CodeType codeType, string objectName, string fieldName, int itemIndex, string expectedContent)
{
string completeObjectName = _createObjectName(codeType, objectName);
bool found = false;
_root.SelectNodes("members/member").Cast<XmlElement>().ToList().ForEach(member =>
{
if (member.Attributes["name"].Value == completeObjectName)
{
found = true;
var field = member.SelectNodes(fieldName);
if (field == null)
throw new ApplicationException("Field " + fieldName + " is not found");
if (itemIndex >= field.Count)
{
throw new ApplicationException("Error: " + objectName + " has " + field.Count + " fields, "+ itemIndex +"th value does not exist");
}
else
{
var valField = field.Item(itemIndex).InnerText;
if (uniformizeString(expectedContent) != uniformizeString(valField))
{
throw new ApplicationException("Error: " + objectName + " field '" + fieldName + "' is '" + valField + "', expected '" + expectedContent + "'");
}
}
return;
}
});
if(!found)
throw new ApplicationException("Object '" + objectName + "' not found" );
}
private string _createObjectName(CodeType codeType, string objectName)
{
if(codeType == CodeType.MEMBER)
return "M:" + _namespace_prefix + objectName;
else
return "T:" + _namespace_prefix + objectName;
}
/// Returns a string without break lines so as to avoid issues during string comparison
private string uniformizeString(string str)
{
// remove line breaks in string
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return Regex.Replace(str, @"\t|\n|\r", "");
else
return Regex.Replace(str, @"\s|\n|\r", "");
}
/// <summary> Check field attribute from an object </summary>
///
/// <param name="codeType">The type of object to check </param>
/// <param name="objectName">The name of object (function mostly) to check </param>
/// <param name="fieldName">The name of the XML tag (summary, param,...) of the object to check </param>
/// <param name="itemIndex"> The index of the field (0 for the first one, 1 for the second, etc) to check </param>
/// <param name="attributeName"> The XML attribute to consider </param>
/// <param name="expectedContent"> The content of the documentation for the given object </param>
/// <exception cref="ApplicationException"> When object, field, attribute or expected content is not found </exception>
public void checkObjectAttribute(CodeType codeType, string objectName, string fieldName, int itemIndex, string attributeName, string expectedContent)
{
string completeObjectName = _createObjectName(codeType, objectName);
bool found = false;
_root.SelectNodes("members/member").Cast<XmlElement>().ToList().ForEach(member =>
{
if (member.Attributes["name"].Value == completeObjectName)
{
found = true;
var field = member.SelectNodes(fieldName);
if (field == null)
throw new ApplicationException("Field " + fieldName + " is not found");
if(field.Count == 0)
throw new ApplicationException("Field " + fieldName + " is empty");
// read attribute of first field's item
string valItem = field.Item(itemIndex).Attributes[attributeName].Value;
if(uniformizeString(valItem) != uniformizeString(expectedContent))
throw new ApplicationException("Error: " + objectName + " field " + fieldName + " is '" + valItem + "', expected '" + expectedContent + "'");
return;
}
});
if (!found)
throw new ApplicationException("Object '" + objectName + "' not found");
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Xml;
using System.IO;
using doxygen_nested_classNamespace;
public class doxygen_nested_class_runme {
doxygen_checker _checker;
public static void Main() {
doxygen_nested_class_runme runme = new doxygen_nested_class_runme();
runme.test_class();
}
public doxygen_nested_class_runme()
{
_checker = new doxygen_checker("doxygen_nested_class", "DoxOuter", "./doxygen_nested_class/doxygen_nested_class.xml");
}
public void test_class()
{
_checker.checkText(doxygen_checker.CodeType.MEMBER, "#ctor", @"
DoxOuter constructor
");
_checker.checkText(doxygen_checker.CodeType.TYPE, "DoxInner", @"
DoxInner class description
");
_checker.checkText(doxygen_checker.CodeType.MEMBER, "DoxInner.#ctor", @"
DoxInner constructor
");
_checker.checkText(doxygen_checker.CodeType.MEMBER, "DoxInner.doxMethod", @"
doxMethod description
");
_checker.checkText(doxygen_checker.CodeType.MEMBER, "DoxInner.doxStaticMethod", @"
doxStaticMethod description
");
}
}

View File

@ -0,0 +1,189 @@
using System;
using System.Xml;
using System.IO;
using doxygen_translateNamespace;
public class doxygen_translate_runme {
doxygen_checker _checker;
public static void Main() {
doxygen_translate_runme runme = new doxygen_translate_runme();
runme.test_function1();
runme.test_function2();
runme.test_function3();
runme.test_function4();
}
public doxygen_translate_runme()
{
_checker = new doxygen_checker("doxygen_translate", "doxygen_translate", "./doxygen_translate/doxygen_translate.xml");
}
public void test_function1()
{
string function_name = "function(System.Int32,System.Single)";
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "code", 0, " some test code");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "remarks", 0, "some copyright");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, function_name, "exception", 0, "cref", "!:SuperError");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, function_name, "param", 0, "name", "a");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "param", 0, " the first param");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "remarks", 1, "Some remark text");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "remarks", 2, "Another remarks section");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "returns", 0, "Whatever");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "returns", 1, "it");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "returns", 2, "may return");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, function_name, "seealso", 0, "cref", "!:someOtherMethod");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, function_name, "seealso", 1, "cref", "M:doxygen_translateNamespace.doxygen_translate.function(System.Int32,System.Single)");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, function_name, "exception", 1, "cref", "!:superException");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, function_name, "exception", 2, "cref", "!:RuntimeError");
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, function_name, "param", 1, "name", "b");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "param", 1, " B is mentioned again...");
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "remarks", 3, "This is senseless!");
string description = @"
*Hello*
* some list item
Author: lots of them
Author: Zubr
**boldword**
``codeword``
'citationword'
";
_checker.checkText(doxygen_checker.CodeType.MEMBER, function_name, description);
}
public void test_function2()
{
string function_name = "htmlFunction(System.Int32,System.Single)";
string description = @"
Test for html tags. See Doxygen doc for list of tags recognized by Doxygen.
This is link (""http://acme.com/index.html"")
**bold**
Quote:
Quotation block.
(""http://www.worldwildlife.org/who/index.html"")
center
``this is code``
Starts an item title.
Starts an item description.
Starts a piece of text displayed in a typewriter font.
Starts a section with a specific style (HTML only)
**Starts a piece of text displayed in an italic font.**
'Form' does not generate any output.
--------------------------------------------------------------------
# Heading 1
## Heading 2
### Heading 3
*Starts a piece of text displayed in an italic font.*
Input tag.
Image: src=""slika.png""
Meta tag.
Multicol is ignored by doxygen.
* List item 1.
* List item 2.
Starts a new paragraph.
Starts a preformatted fragment.
Starts a section of text displayed in a smaller font.
'Starts an inline text fragment with a specific style.'
**Starts a section of bold text.**
Starts a piece of text displayed in subscript.
Starts a piece of text displayed in superscript.
Animals
| Column 1 | Column 2 |
-----------------------
| cow | dog |
| cat | mouse |
| horse | parrot |
Starts a piece of text displayed in a typewriter font.
Starts a piece of text displayed in a typewriter font.
* List item 1.
* List item 2.
* List item 3.
*Starts a piece of text displayed in an italic font.*
<u>underlined \b bold text - doxy commands are ignored inside 'htmlonly' section </u>
";
_checker.checkText(doxygen_checker.CodeType.MEMBER, function_name, description);
}
public void test_function3()
{
string function_name = "htmlTableFunction(System.Int32)";
_checker.checkObjectAttribute(doxygen_checker.CodeType.MEMBER, function_name, "param", 0, "name", "byFlags");
string paramDesc = @" bits marking required items:
| Size in bits| Items Required |
--------------------------------
| 1 - 8 | 1 |
| 9 - 16 | 2 |
| 17 - 32 | 4 |
Almost all combinations of above flags are supported by
``htmlTable...`` functions.";
_checker.checkObject(doxygen_checker.CodeType.MEMBER, function_name, "param", 0, paramDesc);
}
public void test_function4()
{
string function_name = "htmlEntitiesFunction(System.Int32,System.Single)";
string description = @"
All entities are treated as commands (C) TM (R)
should work also<in text
>
&
'
""
`
'
""
""
-
--
x
-
.
~
<=
>=
<--
-->
Not an html entity - ignored by Doxygen.
Not an &text html entity - ampersand is replaced with entity.
";
_checker.checkText(doxygen_checker.CodeType.MEMBER, function_name, description);
}
}

View File

@ -42,6 +42,12 @@ int someVar=42;
*/
#define CONSTANT_VALUE 4242
/**
* A two line
* constant comment
*/
#define CONSTANT_VALUE_TWO_LINE 5353
/// SomeAnotherClass description
class SomeAnotherClass
{
@ -63,6 +69,12 @@ public:
int classAttr3; ///< The class attribute post-comment
//!< with details
/**
* The class attribute comment with
* two lines of comments
*/
int classAttr4;
/**
* The class method comment.
*
@ -105,6 +117,12 @@ struct SomeAnotherStruct
int structAttr3; ///< The struct attribute post-comment
//!< with details
/**
* The struct attribute comment with
* two lines of comments
*/
int structAttr4;
/**
* The struct method comment
*/
@ -131,6 +149,24 @@ struct SomeAnotherStruct
void structMethodExtended2(int a, int b)
{
}
/**
* The struct static method one line comment
*/
static void structStaticMethod(int xxx, int yyy)
{
}
/**
* The struct static method with parameters
* Two lines of comments
*
* @param aaa Parameter aaa
* @param bbb Parameter bbb
*/
static void structStaticMethod2(int aaa, int bbb)
{
}
};
struct Foo1636

View File

@ -5,6 +5,7 @@
/**
* Testing comments before enum items
* Including two line comments
*/
enum SomeAnotherEnum
{
@ -19,7 +20,12 @@
/**
* The comment for the third item
*/
SOME_ITEM_3
SOME_ITEM_3,
/**
* The comment for the fourth item
* over two lines
*/
SOME_ITEM_4
};
/**

View File

@ -27,6 +27,7 @@ public class doxygen_parsing_enums_proper_runme {
"");
wantedComments.put("doxygen_parsing_enums_proper.SomeAnotherEnum",
" Testing comments before enum items \n" +
" Including two line comments \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_proper.SomeAnotherEnum2.SOME_ITEM_30",
@ -36,6 +37,11 @@ public class doxygen_parsing_enums_proper_runme {
" Testing comments after enum items \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_proper.SomeAnotherEnum.SOME_ITEM_4",
" The comment for the fourth item \n" +
" over two lines \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_proper.SomeAnotherEnum.SOME_ITEM_3",
" The comment for the third item \n" +
" \n" +

View File

@ -25,6 +25,11 @@ public class doxygen_parsing_enums_simple_runme {
" The comment for the third item \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_simple.doxygen_parsing_enums_simpleConstants.SOME_ITEM_4",
" The comment for the fourth item \n" +
" over two lines \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_simple.doxygen_parsing_enums_simpleConstants.SOME_ITEM_2",
" The comment for the second item \n" +
" \n" +

View File

@ -35,6 +35,7 @@ public class doxygen_parsing_enums_typesafe_runme {
"");
wantedComments.put("doxygen_parsing_enums_typesafe.SomeAnotherEnum",
" Testing comments before enum items \n" +
" Including two line comments \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_typesafe.SomeAnotherEnum2.SOME_ITEM_10",
@ -44,6 +45,11 @@ public class doxygen_parsing_enums_typesafe_runme {
" The comment for the third item \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_typesafe.SomeAnotherEnum.SOME_ITEM_4",
" The comment for the fourth item \n" +
" over two lines \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_typesafe.SomeAnotherEnum2.SOME_ITEM_30",
"Post comment for the third item \n" +
"");

View File

@ -26,6 +26,11 @@ public class doxygen_parsing_enums_typeunsafe_runme {
" The comment for the third item \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_typeunsafe.SomeAnotherEnum.SOME_ITEM_4",
" The comment for the fourth item \n" +
" over two lines \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_typeunsafe.SomeAnotherEnum.SOME_ITEM_1",
" The comment for the first item \n" +
" \n" +
@ -35,6 +40,7 @@ public class doxygen_parsing_enums_typeunsafe_runme {
"");
wantedComments.put("doxygen_parsing_enums_typeunsafe.SomeAnotherEnum",
" Testing comments before enum items \n" +
" Including two line comments \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing_enums_typeunsafe.SomeAnotherEnum2",

View File

@ -31,9 +31,17 @@ public class doxygen_parsing_runme {
wantedComments.put("doxygen_parsing.SomeAnotherClass.setClassAttr3(int)",
"The class attribute post-comment with details \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherClass.setClassAttr4(int)",
" The class attribute comment with \n" +
" two lines of comments \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherStruct.setStructAttr3(int)",
"The struct attribute post-comment with details \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherStruct.setStructAttr4(int)",
" The struct attribute comment with \n" +
" two lines of comments \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherClass.classMethodExtended2(int, int)",
" The class method with parameter \n" +
" \n" +
@ -90,6 +98,10 @@ public class doxygen_parsing_runme {
wantedComments.put("doxygen_parsing.SomeAnotherStruct.getStructAttr3()",
"The struct attribute post-comment with details \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherStruct.getStructAttr4()",
" The struct attribute comment with \n" +
" two lines of comments \n" +
"");
wantedComments.put("doxygen_parsing.doxygen_parsing.getSomeVar()",
" The var comment \n" +
" \n" +
@ -114,6 +126,10 @@ public class doxygen_parsing_runme {
wantedComments.put("doxygen_parsing.SomeAnotherClass.getClassAttr3()",
"The class attribute post-comment with details \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherClass.getClassAttr4()",
" The class attribute comment with \n" +
" two lines of comments \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherClass.classMethod()",
" The class method comment.<br>\n" +
" <br>\n" +
@ -126,12 +142,28 @@ public class doxygen_parsing_runme {
" @param b Parameter b \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherStruct.structStaticMethod(int, int)",
" The struct static method one line comment \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherStruct.structStaticMethod2(int, int)",
" The struct static method with parameters \n" +
" Two lines of comments \n" +
" \n" +
" @param aaa Parameter aaa \n" +
" @param bbb Parameter bbb \n" +
" \n" +
"");
wantedComments.put("doxygen_parsing.SomeAnotherClass.setClassAttr2(int)",
"The class attribute post-comment \n" +
"");
wantedComments.put("doxygen_parsing.doxygen_parsingConstants.CONSTANT_VALUE",
"The constant comment \n" +
"");
wantedComments.put("doxygen_parsing.doxygen_parsingConstants.CONSTANT_VALUE_TWO_LINE",
" A two line \n" +
" constant comment \n" +
"");
wantedComments.put("doxygen_parsing.Foo1636.getGroupmember1()",
"groupmember1 description");
wantedComments.put("doxygen_parsing.Foo1636.setGroupmember1(int)",

View File

@ -0,0 +1,989 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* csharpdoc.cxx
*
* Module to return documentation for nodes formatted for CSharpDoc
* ----------------------------------------------------------------------------- */
#include "csharpdoc.h"
#include "doxyparser.h"
#include <sstream>
#include <string>
#include <vector>
#include <iostream>
#include "swigmod.h"
// define static tables, they are filled in CSharpDocConverter's constructor
CSharpDocConverter::TagHandlersMap CSharpDocConverter::tagHandlers;
using std::string;
// Helper class increasing the provided indent string in its ctor and decreasing
// it in its dtor.
class IndentGuard {
public:
// One indent level.
static const char *Level() {
return " ";
}
// Default ctor doesn't do anything and prevents the dtor from doing anything// too and should only be used when the guard needs to be initialized// conditionally as Init() can then be called after checking some condition.// Otherwise, prefer to use the non default ctor below.
IndentGuard() {
m_initialized = false;
}
// Ctor takes the output to determine the current indent and to remove the
// extra indent added to it in the dtor and the variable containing the indent
// to use, which must be used after every new line by the code actually
// updating the output.
IndentGuard(string &output, string &indent) {
Init(output, indent);
}
// Really initializes the object created using the default ctor.
void Init(string &output, string &indent) {
m_output = &output;
m_indent = &indent;
const string::size_type lastNonSpace = m_output->find_last_not_of(' ');
if (lastNonSpace == string::npos) {
m_firstLineIndent = m_output->length();
} else if ((*m_output)[lastNonSpace] == '\n') {
m_firstLineIndent = m_output->length() - (lastNonSpace + 1);
} else {
m_firstLineIndent = 0;
}
// Notice that the indent doesn't include the first line indent because it's
// implicit, i.e. it is present in the input and so is copied into the
// output anyhow.
*m_indent = Level();
m_initialized = true;
}
// Get the indent for the first line of the paragraph, which is smaller than
// the indent for the subsequent lines.
string getFirstLineIndent() const {
return string(m_firstLineIndent, ' ');
}
~IndentGuard() {
if (!m_initialized)
return;
m_indent->clear();
// Get rid of possible remaining extra indent, e.g. if there were any trailing
// new lines: we shouldn't add the extra indent level to whatever follows
// this paragraph.
static const size_t lenIndentLevel = strlen(Level());
if (m_output->length() > lenIndentLevel) {
const size_t start = m_output->length() - lenIndentLevel;
if (m_output->compare(start, string::npos, Level()) == 0)
m_output->erase(start);
}
}
private:
string *m_output;
string *m_indent;
string::size_type m_firstLineIndent;
bool m_initialized;
IndentGuard(const IndentGuard &);
};
static void replaceAll(std::string &src, const std::string &token, const std::string &replace) {
std::string::size_type pos = src.find(token);
while (pos != std::string::npos) {
src.replace(pos, token.size(), replace);
pos = src.find(token, pos + replace.size());
}
}
static void trimWhitespace(string &s) {
const string::size_type lastNonSpace = s.find_last_not_of(' ');
if (lastNonSpace == string::npos)
s.clear();
else
s.erase(lastNonSpace + 1);
}
// Erase the first character in the string if it is a newline
static void eraseLeadingNewLine(string &s) {
if (!s.empty() && s[0] == '\n')
s.erase(s.begin());
}
// Erase the first character in the string if it is a newline
static void eraseAllNewLine(string &str) {
for (size_t i = 0; i < str.size(); i++) {
// if the character is a newline character
if (str[i] == '\n') {
// remove the character
str.erase(i, 1);
// decrement the index to account for the removed character
i--;
}
}
}
// Erase last characters in the string if it is a newline or a space
static void eraseTrailingSpaceNewLines(string &s) {
while (!s.empty() && (s[s.size() - 1] == '\n' || s[s.size() - 1] == ' '))
s.erase(s.size() - 1);
}
// escape some characters which cannot appear as it in C# comments
static void escapeSpecificCharacters(string &str) {
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '<') {
str.replace(i, 1, "&lt;");
} else if (str[i] == '>') {
str.replace(i, 1, "&gt;");
} else if (str[i] == '&') {
str.replace(i, 1, "&amp;");
}
}
}
// Check the generated docstring line by line and make sure that any
// code and verbatim blocks have an empty line preceding them, which
// is necessary for Sphinx. Additionally, this strips any empty lines
// appearing at the beginning of the docstring.
static string padCodeAndVerbatimBlocks(const string &docString) {
std::string result;
std::istringstream iss(docString);
// Initialize to false because there is no previous line yet
bool lastLineWasNonBlank = false;
for (string line; std::getline(iss, line); result += line) {
if (!result.empty()) {
// Terminate the previous line
result += '\n';
}
const size_t pos = line.find_first_not_of(" \t");
if (pos == string::npos) {
lastLineWasNonBlank = false;
} else {
if (lastLineWasNonBlank &&
(line.compare(pos, 13, ".. code-block") == 0 ||
line.compare(pos, 7, ".. math") == 0 ||
line.compare(pos, 3, ">>>") == 0)) {
// Must separate code or math blocks from the previous line
result += '\n';
}
lastLineWasNonBlank = true;
}
}
return result;
}
/* static */
CSharpDocConverter::TagHandlersMap::mapped_type CSharpDocConverter::make_handler(tagHandler handler) {
return make_pair(handler, std::string());
}
/* static */
CSharpDocConverter::TagHandlersMap::mapped_type CSharpDocConverter::make_handler(tagHandler handler, const char *arg) {
return make_pair(handler, arg);
}
void CSharpDocConverter::fillStaticTables() {
if (tagHandlers.size()) // fill only once
return;
tagHandlers["a"] = make_handler(&CSharpDocConverter::handleTagWrap, "*");
tagHandlers["b"] = make_handler(&CSharpDocConverter::handleTagWrap, "**");
// \c command is translated as single quotes around next word
tagHandlers["c"] = make_handler(&CSharpDocConverter::handleTagWrap, "``");
tagHandlers["cite"] = make_handler(&CSharpDocConverter::handleTagWrap, "'");
tagHandlers["e"] = make_handler(&CSharpDocConverter::handleTagWrap, "*");
// these commands insert just a single char, some of them need to be escaped
tagHandlers["$"] = make_handler(&CSharpDocConverter::handleTagChar);
tagHandlers["@"] = make_handler(&CSharpDocConverter::handleTagChar);
tagHandlers["\\"] = make_handler(&CSharpDocConverter::handleTagChar);
tagHandlers["<"] = make_handler(&CSharpDocConverter::handleTagCharReplace, "&lt;");
tagHandlers[">"] = make_handler(&CSharpDocConverter::handleTagCharReplace, "&gt;");
tagHandlers["&"] = make_handler(&CSharpDocConverter::handleTagCharReplace, "&amp;");
tagHandlers["#"] = make_handler(&CSharpDocConverter::handleTagChar);
tagHandlers["%"] = make_handler(&CSharpDocConverter::handleTagChar);
tagHandlers["~"] = make_handler(&CSharpDocConverter::handleTagChar);
tagHandlers["\""] = make_handler(&CSharpDocConverter::handleTagChar);
tagHandlers["."] = make_handler(&CSharpDocConverter::handleTagChar);
tagHandlers["::"] = make_handler(&CSharpDocConverter::handleTagChar);
// these commands are stripped out, and only their content is printed
tagHandlers["attention"] = make_handler(&CSharpDocConverter::handleParagraph, "remarks");
tagHandlers["author"] = make_handler(&CSharpDocConverter::handleTagWord, "Author");
tagHandlers["authors"] = make_handler(&CSharpDocConverter::handleTagWord, "Author");
tagHandlers["brief"] = make_handler(&CSharpDocConverter::handleSummary);
tagHandlers["bug"] = make_handler(&CSharpDocConverter::handleTagWord, "Bug:");
tagHandlers["code"] = make_handler(&CSharpDocConverter::handleCode);
tagHandlers["copyright"] = make_handler(&CSharpDocConverter::handleParagraph, "remarks");
tagHandlers["date"] = make_handler(&CSharpDocConverter::handleTagWord, "Date");
tagHandlers["deprecated"] = make_handler(&CSharpDocConverter::handleTagWord, "Deprecated");
tagHandlers["details"] = make_handler(&CSharpDocConverter::handleParagraph, "remarks");
tagHandlers["em"] = make_handler(&CSharpDocConverter::handleTagWrap, "*");
tagHandlers["example"] = make_handler(&CSharpDocConverter::handleTagWord, "Example");
tagHandlers["exception"] = tagHandlers["throw"] = tagHandlers["throws"] = make_handler(&CSharpDocConverter::handleTagException);
tagHandlers["htmlonly"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["invariant"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["latexonly"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["link"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["manonly"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["note"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["p"] = make_handler(&CSharpDocConverter::handleTagWrap, "``");
tagHandlers["partofdescription"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["rtfonly"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["remark"] = make_handler(&CSharpDocConverter::handleParagraph, "remarks");
tagHandlers["remarks"] = make_handler(&CSharpDocConverter::handleParagraph, "remarks");
tagHandlers["sa"] = make_handler(&CSharpDocConverter::handleTagSee);
tagHandlers["see"] = make_handler(&CSharpDocConverter::handleTagSee);
tagHandlers["since"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["short"] = make_handler(&CSharpDocConverter::handleNotHandled);
tagHandlers["todo"] = make_handler(&CSharpDocConverter::handleTagWord, "TODO");
tagHandlers["version"] = make_handler(&CSharpDocConverter::handleTagWord, "Version");
tagHandlers["verbatim"] = make_handler(&CSharpDocConverter::handleVerbatimBlock);
tagHandlers["warning"] = make_handler(&CSharpDocConverter::handleLine, "remarks");
tagHandlers["xmlonly"] = make_handler(&CSharpDocConverter::handleNotHandled);
// these commands have special handlers
tagHandlers["arg"] = make_handler(&CSharpDocConverter::handleAddList);
tagHandlers["cond"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["else"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["elseif"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["endcond"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["if"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["ifnot"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["image"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["li"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["overload"] = make_handler(&CSharpDocConverter::handleIgnore);
tagHandlers["par"] = make_handler(&CSharpDocConverter::handleTagWord, "Title");
tagHandlers["param"] = tagHandlers["tparam"] = make_handler(&CSharpDocConverter::handleTagParam);
tagHandlers["ref"] = make_handler(&CSharpDocConverter::handleTagRef);
tagHandlers["result"] = tagHandlers["return"] = tagHandlers["returns"] = make_handler(&CSharpDocConverter::handleTagReturn);
// this command just prints its contents
// (it is internal command of swig's parser, contains plain text)
tagHandlers["plainstd::string"] = make_handler(&CSharpDocConverter::handlePlainString);
tagHandlers["plainstd::endl"] = make_handler(&CSharpDocConverter::handleNewLine);
tagHandlers["n"] = make_handler(&CSharpDocConverter::handleNewLine);
// \f commands output literal Latex formula, which is still better than nothing.
tagHandlers["f$"] = tagHandlers["f["] = tagHandlers["f{"] = make_handler(&CSharpDocConverter::handleMath);
// HTML tags
tagHandlers["<a"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag_A);
tagHandlers["<b"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag2, "**");
tagHandlers["<blockquote"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag_A, "Quote: ");
tagHandlers["<body"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<br"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, "\n");
// there is no formatting for this tag as it was deprecated in HTML 4.01 and
// not used in HTML 5
tagHandlers["<center"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<caption"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<code"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag2, "``");
tagHandlers["<dl"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<dd"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, " ");
tagHandlers["<dt"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<dfn"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<div"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<em"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag2, "**");
tagHandlers["<form"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<hr"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, "--------------------------------------------------------------------\n");
tagHandlers["<h1"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, "# ");
tagHandlers["<h2"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, "## ");
tagHandlers["<h3"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, "### ");
tagHandlers["<i"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag2, "*");
tagHandlers["<input"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<img"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, "Image:");
tagHandlers["<li"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, "* ");
tagHandlers["<meta"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<multicol"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<ol"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<p"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, "\n");
tagHandlers["<pre"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<small"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<span"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag2, "'");
tagHandlers["<strong"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag2, "**");
// make a space between text and super/sub script.
tagHandlers["<sub"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, " ");
tagHandlers["<sup"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag, " ");
tagHandlers["<table"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTagNoParam);
tagHandlers["<td"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag_td);
tagHandlers["<th"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag_th);
tagHandlers["<tr"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag_tr);
tagHandlers["<tt"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<kbd"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<ul"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag);
tagHandlers["<var"] = make_handler(&CSharpDocConverter::handleDoxyHtmlTag2, "*");
// HTML entities
tagHandlers["&copy"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "(C)");
tagHandlers["&trade"] = make_handler(&CSharpDocConverter::handleHtmlEntity, " TM");
tagHandlers["&reg"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "(R)");
tagHandlers["&lt"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "<");
tagHandlers["&gt"] = make_handler(&CSharpDocConverter::handleHtmlEntity, ">");
tagHandlers["&amp"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "&");
tagHandlers["&apos"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "'");
tagHandlers["&quot"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "\"");
tagHandlers["&lsquo"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "`");
tagHandlers["&rsquo"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "'");
tagHandlers["&ldquo"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "\"");
tagHandlers["&rdquo"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "\"");
tagHandlers["&ndash"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "-");
tagHandlers["&mdash"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "--");
tagHandlers["&nbsp"] = make_handler(&CSharpDocConverter::handleHtmlEntity, " ");
tagHandlers["&times"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "x");
tagHandlers["&minus"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "-");
tagHandlers["&sdot"] = make_handler(&CSharpDocConverter::handleHtmlEntity, ".");
tagHandlers["&sim"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "~");
tagHandlers["&le"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "<=");
tagHandlers["&ge"] = make_handler(&CSharpDocConverter::handleHtmlEntity, ">=");
tagHandlers["&larr"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "<--");
tagHandlers["&rarr"] = make_handler(&CSharpDocConverter::handleHtmlEntity, "-->");
}
CSharpDocConverter::CSharpDocConverter(int flags):
DoxygenTranslator(flags), m_tableLineLen(0), m_prevRowIsTH(false) {
fillStaticTables();
}
// Return the type as it should appear in the output documentation.
static std::string getCSharpDocType(Node *n, const_String_or_char_ptr lname = "") {
std::string type;
String *s = Swig_typemap_lookup("doctype", n, lname, 0);
if (!s) {
if (String *t = Getattr(n, "type"))
s = SwigType_str(t, "");
}
/////////////////
if (!s)
return type;
type = Char(s);
Delete(s);
return type;
}
std::string CSharpDocConverter::getParamType(std::string param) {
std::string type;
ParmList *plist = CopyParmList(Getattr(currentNode, "parms"));
for (Parm *p = plist; p; p = nextSibling(p)) {
String *pname = Getattr(p, "name");
if (pname && Char(pname) == param) {
type = getCSharpDocType(p, pname);
break;
}
}
Delete(plist);
return type;
}
std::string CSharpDocConverter::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 (pname && Char(pname) == param) {
String *pval = Getattr(p, "value");
if (pval)
value = Char(pval);
break;
}
}
Delete(plist);
return value;
}
/**
* Returns true, if the given parameter exists in the current node
* (for example param is a name of function parameter). If feature
* 'doxygen:nostripparams' is set, then this method always returns
* true - parameters are copied to output regardless of presence in
* function params list.
*/
bool CSharpDocConverter::paramExists(std::string param) {
if (GetFlag(currentNode, "feature:doxygen:nostripparams")) {
return true;
}
ParmList *plist = CopyParmList(Getattr(currentNode, "parms"));
for (Parm *p = plist; p;) {
if (Getattr(p, "name") && Char(Getattr(p, "name")) == param) {
return true;
}
/* doesn't seem to work always: in some cases (especially for 'self' parameters)
* tmap:in is present, but tmap:in:next is not and so this code skips all the parameters
*/
//p = Getattr(p, "tmap:in") ? Getattr(p, "tmap:in:next") : nextSibling(p);
p = nextSibling(p);
}
Delete(plist);
return false;
}
std::string CSharpDocConverter::translateSubtree(DoxygenEntity &doxygenEntity) {
std::string translatedComment;
if (doxygenEntity.isLeaf)
return translatedComment;
std::string currentSection;
std::list<DoxygenEntity>::iterator p = doxygenEntity.entityList.begin();
while (p != doxygenEntity.entityList.end()) {
translateEntity(*p, translatedComment);
translateSubtree(*p);
p++;
}
return translatedComment;
}
void CSharpDocConverter::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(getBaseCommand(doxyEntity.typeOfEntity));
if (it != tagHandlers.end())
(this->*(it->second.first)) (doxyEntity, translatedComment, it->second.second);
}
void CSharpDocConverter::handleIgnore(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
if (tag.entityList.size()) {
tag.entityList.pop_front();
}
translatedComment += translateSubtree(tag);
}
void CSharpDocConverter::handleSummary(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
translatedComment += "<summary>";
std::string summary = translateSubtree(tag);
eraseAllNewLine(summary);
trimWhitespace(summary);
// remove final newlines
eraseTrailingSpaceNewLines(summary);
escapeSpecificCharacters(summary);
translatedComment += summary;
translatedComment += "</summary>";
translatedComment += "\n";
}
void CSharpDocConverter::handleLine(DoxygenEntity &tag, std::string &translatedComment, const std::string &tagName) {
translatedComment += "<" + tagName + ">";
if (tag.entityList.size()) {
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
}
translatedComment += "</" + tagName + ">";
}
void CSharpDocConverter::handleNotHandled(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
std::string paragraph = translateSubtree(tag);
eraseLeadingNewLine(paragraph);
eraseTrailingSpaceNewLines(paragraph);
trimWhitespace(paragraph);
escapeSpecificCharacters(paragraph);
translatedComment += paragraph;
translatedComment += "\n";
}
void CSharpDocConverter::handleAddList(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
std::string listItem = translateSubtree(tag);
eraseAllNewLine(listItem);
translatedComment += "* ";
translatedComment += listItem;
translatedComment += "\n";
}
void CSharpDocConverter::handleParagraph(DoxygenEntity &tag, std::string &translatedComment, const std::string &tagName) {
translatedComment += "<";
translatedComment += tagName;
translatedComment += ">";
std::string paragraph = translateSubtree(tag);
eraseAllNewLine(paragraph);
trimWhitespace(paragraph);
eraseTrailingSpaceNewLines(paragraph);
escapeSpecificCharacters(paragraph);
translatedComment += paragraph;
translatedComment += "</";
translatedComment += tagName;
translatedComment += ">\n";
}
void CSharpDocConverter::handleVerbatimBlock(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
string verb = translateSubtree(tag);
eraseLeadingNewLine(verb);
// Remove the last newline to prevent doubling the newline already present after \endverbatim
trimWhitespace(verb); // Needed to catch trailing newline below
eraseTrailingSpaceNewLines(verb);
escapeSpecificCharacters(verb);
translatedComment += verb;
}
void CSharpDocConverter::handleMath(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
IndentGuard indent;
// Only \f$ is translated to inline formulae, \f[ and \f{ are for the block ones.
const bool inlineFormula = tag.typeOfEntity == "f$";
string formulaNL;
if (inlineFormula) {
translatedComment += ":math:`";
} else {
indent.Init(translatedComment, m_indent);
trimWhitespace(translatedComment);
const string formulaIndent = indent.getFirstLineIndent();
translatedComment += formulaIndent;
translatedComment += ".. math::\n";
formulaNL = '\n';
formulaNL += formulaIndent;
formulaNL += m_indent;
translatedComment += formulaNL;
}
std::string formula;
handleTagVerbatim(tag, formula, arg);
// It is important to ensure that we have no spaces around the inline math
// contents, so strip them.
const size_t start = formula.find_first_not_of(" \t\n");
const size_t end = formula.find_last_not_of(" \t\n");
if (start != std::string::npos) {
for (size_t n = start; n <= end; n++) {
if (formula[n] == '\n') {
// New lines must be suppressed in inline maths and indented in the block ones.
if (!inlineFormula)
translatedComment += formulaNL;
} else {
// Just copy everything else.
translatedComment += formula[n];
}
}
}
if (inlineFormula) {
translatedComment += "`";
}
}
void CSharpDocConverter::handleCode(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
IndentGuard indent(translatedComment, m_indent);
trimWhitespace(translatedComment);
translatedComment += "<code>";
std::string code;
handleTagVerbatim(tag, code, arg);
// Try and remove leading newline, which is present for block \code
// command:
escapeSpecificCharacters(code);
eraseLeadingNewLine(code);
trimWhitespace(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();
// 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') {
// Don't leave trailing white space, this results in PEP8 validation
// errors in Python code (which are performed by our own unit tests).
trimWhitespace(translatedComment);
translatedComment += '\n';
// Ensure that we indent all the lines by the code indent.
translatedComment += codeIndent;
} else {
// Just copy everything else.
translatedComment += code[n];
}
}
trimWhitespace(translatedComment);
// For block commands, the translator adds the newline after
// \endcode, so try and compensate by removing the last newline from
// the code text:
eraseTrailingSpaceNewLines(translatedComment);
translatedComment += "</code>";
translatedComment += "\n";
}
void CSharpDocConverter::handlePlainString(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
translatedComment += tag.data;
}
void CSharpDocConverter::handleTagVerbatim(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
translatedComment += arg;
for (DoxygenEntityListCIt it = tag.entityList.begin(); it != tag.entityList.end(); it++) {
translatedComment += it->data;
}
}
void CSharpDocConverter::handleTagMessage(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
translatedComment += arg;
handleParagraph(tag, translatedComment);
translatedComment += "\">\n";
}
void CSharpDocConverter::handleTagSee(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
translatedComment += "<seealso cref=\"";
std::string seeAlso = translateSubtree(tag);
escapeSpecificCharacters(seeAlso);
// Remove parameter list
// Alternative would be to try and convert them into C# types similar to Java implementation
std::string::size_type lbrace = seeAlso.find('(');
if (lbrace != std::string::npos)
seeAlso.erase(lbrace);
replaceAll(seeAlso, "::", ".");
eraseTrailingSpaceNewLines(seeAlso);
translatedComment += seeAlso;
translatedComment += "\"/>\n";
}
void CSharpDocConverter::handleTagCharReplace(DoxygenEntity &, std::string &translatedComment, const std::string &arg) {
translatedComment += arg;
}
void CSharpDocConverter::handleTagChar(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
translatedComment += tag.typeOfEntity;
}
void CSharpDocConverter::handleTagIf(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
translatedComment += arg;
if (tag.entityList.size()) {
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
translatedComment += " {" + translateSubtree(tag) + "}";
}
}
void CSharpDocConverter::handleTagWord(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
translatedComment += arg + ": ";
if (tag.entityList.size())
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
translatedComment += translateSubtree(tag);
translatedComment += "\n";
}
void CSharpDocConverter::handleTagImage(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
if (tag.entityList.size() < 2)
return;
tag.entityList.pop_front();
translatedComment += "Image: ";
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
if (tag.entityList.size())
translatedComment += "(" + tag.entityList.begin()->data + ")";
}
void CSharpDocConverter::handleTagParam(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
if (tag.entityList.size() < 2)
return;
if (!paramExists(tag.entityList.begin()->data))
return;
IndentGuard indent(translatedComment, m_indent);
DoxygenEntity paramNameEntity = *tag.entityList.begin();
tag.entityList.pop_front();
const std::string &paramName = paramNameEntity.data;
const std::string paramValue = getParamValue(paramName);
translatedComment += "<param name=\"" + paramName + "\">";
translatedComment += translateSubtree(tag);
eraseTrailingSpaceNewLines(translatedComment);
translatedComment += "</param> \n";
}
void CSharpDocConverter::handleTagReturn(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
IndentGuard indent(translatedComment, m_indent);
translatedComment += "<returns>";
translatedComment += translateSubtree(tag);
eraseTrailingSpaceNewLines(translatedComment);
translatedComment += "</returns> \n";
}
void CSharpDocConverter::handleTagException(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
IndentGuard indent(translatedComment, m_indent);
DoxygenEntity paramNameEntity = *tag.entityList.begin();
tag.entityList.pop_front();
const std::string &paramName = paramNameEntity.data;
const std::string paramType = getParamType(paramName);
const std::string paramValue = getParamValue(paramName);
translatedComment += "<exception cref=\"" + paramName + "\">";
translatedComment += translateSubtree(tag);
eraseTrailingSpaceNewLines(translatedComment);
translatedComment += "</exception> \n";
}
void CSharpDocConverter::handleTagRef(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
if (!tag.entityList.size())
return;
string anchor = tag.entityList.begin()->data;
tag.entityList.pop_front();
string anchorText = anchor;
size_t pos = anchorText.find('#');
if (pos != string::npos) {
anchorText = anchorText.substr(pos + 1);
}
if (!tag.entityList.empty()) {
anchorText = tag.entityList.begin()->data;
}
translatedComment += "\\ref " + anchorText;
}
void CSharpDocConverter::handleTagWrap(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
if (tag.entityList.size()) { // do not include empty tags
std::string tagData = translateSubtree(tag);
// wrap the thing, ignoring whitespace
size_t wsPos = tagData.find_last_not_of("\n\t ");
if (wsPos != std::string::npos && wsPos != tagData.size() - 1)
translatedComment += arg + tagData.substr(0, wsPos + 1) + arg + tagData.substr(wsPos + 1);
else
translatedComment += arg + tagData + arg;
}
}
void CSharpDocConverter::handleDoxyHtmlTag(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, for example "</ul>
// translatedComment += "</" + arg.substr(1) + ">";
} else {
translatedComment += arg + htmlTagArgs;
}
}
void CSharpDocConverter::handleDoxyHtmlTagNoParam(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, for example "</ul>
} else {
translatedComment += arg;
}
}
void CSharpDocConverter::handleDoxyHtmlTag_A(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, "</a>
translatedComment += " (" + m_url + ')';
m_url.clear();
} else {
m_url.clear();
size_t pos = htmlTagArgs.find('=');
if (pos != string::npos) {
m_url = htmlTagArgs.substr(pos + 1);
}
translatedComment += arg;
}
}
void CSharpDocConverter::handleDoxyHtmlTag2(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, for example "</em>
translatedComment += arg;
} else {
translatedComment += arg;
}
}
void CSharpDocConverter::handleDoxyHtmlTag_tr(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
std::string htmlTagArgs = tag.data;
size_t nlPos = translatedComment.rfind('\n');
if (htmlTagArgs == "/") {
// end tag, </tr> appends vertical table line '|'
translatedComment += '|';
if (nlPos != string::npos) {
size_t startOfTableLinePos = translatedComment.find_first_not_of(" \t", nlPos + 1);
if (startOfTableLinePos != string::npos) {
m_tableLineLen = translatedComment.size() - startOfTableLinePos;
}
}
} else {
if (m_prevRowIsTH) {
// if previous row contained <th> tag, add horizontal separator
// but first get leading spaces, because they'll be needed for the next row
size_t numLeadingSpaces = translatedComment.size() - nlPos - 1;
translatedComment += string(m_tableLineLen, '-') + '\n';
if (nlPos != string::npos) {
translatedComment += string (numLeadingSpaces, ' ');
}
m_prevRowIsTH = false;
}
}
}
void CSharpDocConverter::handleDoxyHtmlTag_th(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end tag, </th> is ignored
} else {
translatedComment += '|';
m_prevRowIsTH = true;
}
}
void CSharpDocConverter::handleDoxyHtmlTag_td(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end tag, </td> is ignored
} else {
translatedComment += '|';
}
}
void CSharpDocConverter::handleHtmlEntity(DoxygenEntity &, std::string &translatedComment, const std::string &arg) {
// html entities
translatedComment += arg;
}
void CSharpDocConverter::handleNewLine(DoxygenEntity &, std::string &translatedComment, const std::string &) {
trimWhitespace(translatedComment);
translatedComment += "\n";
if (!m_indent.empty())
translatedComment += m_indent;
}
String *CSharpDocConverter::makeDocumentation(Node *n) {
String *documentation;
std::string csharpDocString;
// store the node, we may need it later
currentNode = n;
documentation = getDoxygenComment(n);
if (documentation != NULL) {
if (GetFlag(n, "feature:doxygen:notranslate")) {
String *comment = NewString("");
Append(comment, documentation);
Replaceall(comment, "\n *", "\n");
csharpDocString = Char(comment);
Delete(comment);
} else {
std::list<DoxygenEntity> entityList = parser.createTree(n, documentation);
DoxygenEntity root("root", entityList);
csharpDocString = translateSubtree(root);
}
}
// if we got something log the result
if (!csharpDocString.empty()) {
// remove the last spaces and '\n' since additional one is added during writing to file
eraseTrailingSpaceNewLines(csharpDocString);
// ensure that a blank line occurs before code or math blocks
csharpDocString = padCodeAndVerbatimBlocks(csharpDocString);
if (m_flags & debug_translator) {
std::cout << "\n---RESULT IN CSHARPDOC---" << std::endl;
std::cout << csharpDocString;
std::cout << std::endl;
}
}
return NewString(csharpDocString.c_str());
}

243
Source/Doxygen/csharpdoc.h Normal file
View File

@ -0,0 +1,243 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* csharpdoc.h
*
* Module to return documentation for nodes formatted for CSharp
* ----------------------------------------------------------------------------- */
#ifndef CSHARPDOCCONVERTER_H_
#define CSHARPDOCCONVERTER_H_
#include <list>
#include <string>
#include "swig.h"
#include "doxyentity.h"
#include "doxytranslator.h"
#define DOC_STRING_LENGTH 64 // characters per line allowed
#define DOC_PARAM_STRING_LENGTH 30 // characters reserved for param name / type
class CSharpDocConverter : public DoxygenTranslator {
public:
CSharpDocConverter(int flags = 0);
String *makeDocumentation(Node *node);
protected:
size_t m_tableLineLen;
bool m_prevRowIsTH;
std::string m_url;
/*
* Translate every entity in a tree, also manages sections
* display. Prints title for every group of tags that have
* a section title associated with them
*/
std::string translateSubtree(DoxygenEntity &doxygenEntity);
/*
* Translate one entity with the appropriate handler, according
* to the tagHandlers
*/
void translateEntity(DoxygenEntity &doxyEntity, std::string &translatedComment);
/*
* Typedef for the function that handles one tag
* arg - some string argument to easily pass it through lookup table
*/
typedef void (CSharpDocConverter::*tagHandler) (DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Wrap the command data with the some string
* arg - string to wrap with, like '_' or '*'
*/
void handleTagWrap(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Just prints new line
*/
void handleNewLine(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Replace char by the one ine argument
*/
void handleTagCharReplace(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Print the name of tag to the output, used for escape-commands
*/
void handleTagChar(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Format the contents of the \exception tag or its synonyms.
*/
void handleTagException(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/**
* Print the content without any tag
*/
void handleNotHandled(DoxygenEntity &tag, std::string &translatedComment, const std::string &tagName);
/**
* Print the content as an item of a list
*/
void handleAddList(DoxygenEntity &tag, std::string &translatedComment, const std::string &tagName);
/*
* Print only the content and strip original tag
*/
void handleParagraph(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg = std::string());
/*
* Ignore the tag
*/
void handleIgnore(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg = std::string());
/*
* Print only the line content and strip original tag
*/
void handleLine(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg = std::string());
/*
* Print summary
*/
void handleSummary(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg = std::string());
/*
* Handle Doxygen verbatim tag
*/
void handleVerbatimBlock(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg = std::string());
/*
* Handle one of the Doxygen formula-related tags.
*/
void handleMath(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Handle a code snippet.
*/
void handleCode(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Print only data part of code
*/
void handlePlainString(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/**
* Copies verbatim args of the tag to output, used for commands like \f$, ...
*/
void handleTagVerbatim(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Print the if-elseif-else-endif section
*/
void handleTagIf(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Prints the specified message, than the contents of the tag
* arg - message
*/
void handleTagMessage(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Prints the seealso tag
*/
void handleTagSee(DoxygenEntity &tag, std::string &translatedComment, const std::string &);
/*
* Insert 'Word: ...'
*/
void handleTagWord(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Insert 'Image: ...'
*/
void handleTagImage(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Format nice param description with type information
*/
void handleTagParam(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Format the contents of the \return tag or its synonyms.
*/
void handleTagReturn(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Writes text for \ref tag.
*/
void handleTagRef(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML tags recognized by Doxygen, like <A ...>, <ul>, <table>, ... */
void handleDoxyHtmlTag(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/** Does not output params of HTML tag, for example in <table border='1'>
* 'border=1' is not written to output.
*/
void handleDoxyHtmlTagNoParam(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/** Translates tag <a href = "url">text</a> to: text ("url"). */
void handleDoxyHtmlTag_A(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Handles HTML tags, which are translated to markdown-like syntax, for example
* <i>text</i> --> _text_. Appends arg for start HTML tag and end HTML tag.
*/
void handleDoxyHtmlTag2(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML table, tag <tr> */
void handleDoxyHtmlTag_tr(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML table, tag <th> */
void handleDoxyHtmlTag_th(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML table, tag <td> */
void handleDoxyHtmlTag_td(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML entities recognized by Doxygen, like &lt;, &copy;, ... */
void handleHtmlEntity(DoxygenEntity &, std::string &translatedComment, const std::string &arg);
/*
* Simple helper function that calculates correct parameter type
* of the node stored in 'currentNode'
* If param with specified name is not found, empty string is returned
*/
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;
// Extra indent for the current paragraph, must be output after each new line.
std::string m_indent;
// this contains the handler pointer and one string argument
typedef std::map<std::string, std::pair<tagHandler, std::string> >TagHandlersMap;
static TagHandlersMap tagHandlers;
// Helper functions for fillStaticTables(): make a new tag handler object.
TagHandlersMap::mapped_type make_handler(tagHandler handler);
TagHandlersMap::mapped_type make_handler(tagHandler handler, const char *arg);
void fillStaticTables();
bool paramExists(std::string param);
};
#endif

View File

@ -15,7 +15,6 @@
#include "swigwarn.h"
#include <iostream>
#include <algorithm>
#include <vector>
using std::string;

View File

@ -34,6 +34,8 @@ eswig_SOURCES = CParse/cscanner.c \
DOH/memory.c \
DOH/string.c \
DOH/void.c \
Doxygen/csharpdoc.cxx \
Doxygen/csharpdoc.h \
Doxygen/doxyentity.cxx \
Doxygen/doxyentity.h \
Doxygen/doxyparser.cxx \
@ -121,7 +123,7 @@ distclean-local:
# swig executable as a way of checking before and after the 'beautifying'.
# Single files can be beautified with the beautify-file target, eg: 'make beautify-file INDENTFILE=chosenfile.c'
SWIGTYPEDEFS=-T bool -T File -T DohObjInfo -T Parm -T Language -T List -T TargetLanguageModule -T Typetab -T ModuleFactory -T ErrorMessageFormat -T Symtab -T Hash -T Scanner -T String -T DohBase -T Node -T String_or_char -T SwigType -T Dispatcher -T Wrapper -T DohStringMethods -T DohFileMethods -T DohListMethods -T DohHashMethods -T DOH -T DohIterator -T ParmList -T FILE -T HashNode -T DOHObj_or_char -T DOHFile -T DOHString -T DOHString_or_char -T UpcallData
SWIGTYPEDEFS=-T bool -T File -T DohObjInfo -T Parm -T Language -T List -T TargetLanguageModule -T Typetab -T ModuleFactory -T ErrorMessageFormat -T Symtab -T Hash -T Scanner -T String -T DohBase -T Node -T String_or_char -T SwigType -T Dispatcher -T Wrapper -T DohStringMethods -T DohFileMethods -T DohListMethods -T DohHashMethods -T DOH -T DohIterator -T ParmList -T FILE -T HashNode -T DOHObj_or_char -T DOHFile -T DOHString -T DOHString_or_char -T UpcallData -T DoxygenEntity -T string
INDENTBAKSDIR=../IndentBaks
beautify:

View File

@ -15,6 +15,7 @@
#include "cparse.h"
#include <limits.h> // for INT_MAX
#include <ctype.h>
#include <csharpdoc.h>
/* Hash type used for upcalls from C/C++ */
typedef DOH UpcallData;
@ -46,6 +47,7 @@ class CSHARP:public Language {
bool global_variable_flag; // Flag for when wrapping a global variable
bool old_variable_names; // Flag for old style variable names in the intermediary class
bool generate_property_declaration_flag; // Flag for generating properties
bool doxygen; // Flag for Doxygen generation
String *imclass_name; // intermediary class name
String *module_class_name; // module class name
@ -123,6 +125,7 @@ public:
global_variable_flag(false),
old_variable_names(false),
generate_property_declaration_flag(false),
doxygen(false),
imclass_name(NULL),
module_class_name(NULL),
imclass_class_code(NULL),
@ -171,6 +174,14 @@ public:
directorLanguage();
}
/* -----------------------------------------------------------------------------
* ~CSHARP()
* ----------------------------------------------------------------------------- */
~CSHARP() {
delete doxygenTranslator;
}
/* -----------------------------------------------------------------------------
* getProxyName()
*
@ -223,6 +234,8 @@ public:
SWIG_library_directory("csharp");
int doxygen_translator_flags = 0;
// Look for certain command line options
for (int i = 1; i < argc; i++) {
if (argv[i]) {
@ -266,12 +279,25 @@ public:
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i], "-doxygen") == 0) {
doxygen = true;
scan_doxygen_comments = 1;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-debug-doxygen-translator") == 0) {
doxygen_translator_flags |= DoxygenTranslator::debug_translator;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-debug-doxygen-parser") == 0) {
doxygen_translator_flags |= DoxygenTranslator::debug_parser;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-help") == 0) {
Printf(stdout, "%s\n", usage);
}
}
}
if (doxygen)
doxygenTranslator = new CSharpDocConverter(doxygen_translator_flags);
// Add a symbol to the parser for conditional compilation
Preprocessor_define("SWIGCSHARP 1", 0);
@ -1185,6 +1211,13 @@ public:
EnumFeature enum_feature = decodeEnumFeature(n);
String *typemap_lookup_type = Getattr(n, "name");
// Translate documentation comments
if (have_docstring(n)) {
String *ds = docstring(n, tab0);
Printv(enum_code, ds, NIL);
Delete(ds);
}
if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) {
// Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum
@ -1394,6 +1427,12 @@ public:
if (csattributes)
Printf(enum_code, " %s\n", csattributes);
// Translate documentation comments
if (have_docstring(n)) {
String *ds = docstring(n, tab2);
Printv(enum_code, ds, NIL);
Delete(ds);
}
Printf(enum_code, " %s", symname);
// Check for the %csconstvalue feature
@ -1551,6 +1590,13 @@ public:
const String *methodmods = Getattr(n, "feature:cs:methodmodifiers");
methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string);
// Translate documentation comments
if (have_docstring(n)) {
String *ds = docstring(n, tab2);
Printv(constants_code, ds, NIL);
Delete(ds);
}
Printf(constants_code, " %s %s %s %s = ", methodmods, (const_feature_flag ? "const" : "static readonly"), return_type, itemname);
// Check for the %csconstvalue feature
@ -2227,6 +2273,13 @@ public:
Language::classHandler(n);
// Translate documentation comments
if (have_docstring(n)) {
String *ds = docstring(n, tab0);
Printv(proxy_class_def, ds, NIL);
Delete(ds);
}
if (proxy_flag) {
emitProxyClassDefAndCPPCasts(n);
@ -2404,6 +2457,7 @@ public:
Parm *p;
Parm *last_parm = 0;
int i;
String *comment_code = NewString("");
String *imcall = NewString("");
String *return_type = NewString("");
String *function_code = NewString("");
@ -2501,7 +2555,6 @@ public:
Printf(function_code, "%s %s(", return_type, proxy_function_name);
if (is_interface)
Printf(interface_class_code, " %s %s(", return_type, proxy_function_name);
Printv(imcall, full_imclass_name, ".$imfuncname(", NIL);
if (!static_flag)
@ -2601,6 +2654,13 @@ public:
if (is_interface)
Printf(interface_class_code, ");\n");
// Translate documentation comments
if (have_docstring(n)) {
String *ds = docstring(n, tab2);
Printv(comment_code, ds, NIL);
Delete(ds);
}
// Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in proxy class)
if ((tm = Swig_typemap_lookup("csout", n, "", 0))) {
excodeSubstitute(n, tm, "csout", n);
@ -2695,6 +2755,13 @@ public:
if (!methodmods)
methodmods = (is_public(n) ? public_string : protected_string);
// Translate documentation comments
if (have_docstring(n)) {
String *ds = docstring(n, tab2);
Printv(proxy_class_code, ds, NIL);
Delete(ds);
}
// Start property declaration
Printf(proxy_class_code, " %s %s%s %s {", methodmods, static_flag ? "static " : "", variable_type, variable_name);
}
@ -2734,6 +2801,7 @@ public:
} else {
// Normal function call
Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string);
Printv(proxy_class_code, comment_code, NIL);
Printv(proxy_class_code, function_code, NIL);
}
@ -2756,6 +2824,7 @@ public:
Parm *p;
int i;
String *function_code = NewString("");
String *comment_code = NewString("");
String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the csin typemap has code in the pre or post attributes
String *helper_args = NewString("");
String *pre_code = NewString("");
@ -2952,6 +3021,14 @@ public:
Replaceall(function_code, "$imcall", imcall);
}
// Translate documentation comments
if (have_docstring(n)) {
String *ds = docstring(n, tab2);
Printv(comment_code, ds, NIL);
Delete(ds);
}
Printv(proxy_class_code, comment_code, NIL);
Printv(proxy_class_code, function_code, "\n", NIL);
Delete(helper_args);
@ -3132,6 +3209,14 @@ public:
Printf(function_code, " %s\n", csattributes);
const String *methodmods = Getattr(n, "feature:cs:methodmodifiers");
methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string);
// Translate documentation comments
if (have_docstring(n)) {
String *ds = docstring(n, tab2);
Printv(function_code, ds, NIL);
Delete(ds);
}
Printf(function_code, " %s static %s %s(", methodmods, return_type, func_name);
Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL);
@ -4665,6 +4750,134 @@ public:
Delete(dirclassname);
}
/* ------------------------------------------------------------
* have_docstring()
*
* Check for Doxygen comments
*--------------------------------------------------------------------*/
bool have_docstring(Node *n) {
/* autodoc and docstring features not supported in C#
String *str = Getattr(n, "feature:docstring");
return ((str && Len(str) > 0)
|| (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc"))
|| (doxygen && doxygenTranslator->hasDocumentation(n))
);
*/
return doxygen && doxygenTranslator->hasDocumentation(n);
}
/* ------------------------------------------------------------
* docstring()
*
* Get documentation comments, if any
*
* Return new documentation string to be deleted by caller (never NULL but
* may be empty if there is no docstring).
*--------------------------------------------------------------------*/
String *docstring(Node *n, const char *indent = "") {
String *docstr = NULL;
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
docstr = doxygenTranslator->getDocumentation(n, 0);
}
if (!docstr)
docstr = NewString("");
// If there is more than one line then make docstrings like this:
//
// This is line1
// And here is line2 followed by the rest of them
//
// otherwise, put it all on a single line
if (Strchr(docstr, '\n')) {
String *tmp = NewString("");
Append(tmp, indent_docstring(docstr, indent));
Delete(docstr);
docstr = tmp;
} else {
String *tmp = NewString(indent);
Append(tmp, "/// ");
Append(tmp, docstr);
Append(tmp, "\n");
Delete(docstr);
docstr = tmp;
}
return docstr;
}
/* ------------------------------------------------------------
* indent_docstring()
*
* Format (indent) a CSharp docstring.
* Remove leading whitespace from 'code' and re-indent using
* the indentation string in 'indent'.
* ------------------------------------------------------------ */
String *indent_docstring(const String *code, const char *indent) {
String *out = NewString("");
String *temp;
char *t;
if (!indent)
indent = "";
temp = NewString(code);
t = Char(temp);
if (*t == '{') {
Delitem(temp, 0);
Delitem(temp, DOH_END);
}
/* Split the input text into lines */
List *clist = SplitLines(temp);
Delete(temp);
Iterator si;
int truncate_characters_count = INT_MAX;
for (si = First(clist); si.item; si = Next(si)) {
const char *c = Char(si.item);
int i;
for (i = 0; isspace((unsigned char)c[i]); i++) {
// Scan forward until we find a non-space (which may be a null byte).
}
char ch = c[i];
if (ch) {
// Found a line which isn't just whitespace
if (i < truncate_characters_count)
truncate_characters_count = i;
}
}
if (truncate_characters_count == INT_MAX)
truncate_characters_count = 0;
for (si = First(clist); si.item; si = Next(si)) {
const char *c = Char(si.item);
int i;
for (i = 0; isspace((unsigned char)c[i]); i++) {
// Scan forward until we find a non-space (which may be a null byte).
}
char ch = c[i];
if (!ch) {
// Line is just whitespace - emit an empty line.
Printv(out, indent, "///", NIL);
Putc('\n', out);
continue;
}
Printv(out, indent, "/// ", c + truncate_characters_count, "\n", NIL);
}
Delete(clist);
return out;
}
/*----------------------------------------------------------------------
* nestedClassesSupport()
*--------------------------------------------------------------------*/

View File

@ -1384,7 +1384,7 @@ public:
* the indentation string in 'indent'.
* ------------------------------------------------------------ */
String *indent_docstring(const String *code, const_String_or_char_ptr indent) {
String *indent_docstring(const String *code, const char *indent) {
String *out = NewString("");
String *temp;
char *t;
@ -1523,7 +1523,7 @@ public:
* may be empty if there is no docstring).
* ------------------------------------------------------------ */
String *build_combined_docstring(Node *n, autodoc_t ad_type, const String *indent = "", bool low_level = false) {
String *build_combined_docstring(Node *n, autodoc_t ad_type, const char *indent = "", bool low_level = false) {
bool add_autodoc = true;
String *docstr = Getattr(n, "feature:docstring");
if (docstr) {
@ -1612,7 +1612,7 @@ public:
* set then it will build a combined docstring.
* ------------------------------------------------------------ */
String *docstring(Node *n, autodoc_t ad_type, const String *indent, bool low_level = false) {
String *docstring(Node *n, autodoc_t ad_type, const char *indent, bool low_level = false) {
String *docstr = build_combined_docstring(n, ad_type, indent, low_level);
const int len = Len(docstr);
if (!len)

View File

@ -40,6 +40,7 @@ extern String *argc_template_string;
/* Miscellaneous stuff */
#define tab0 ""
#define tab2 " "
#define tab4 " "
#define tab8 " "