diff --git a/Doc/Manual/Doxygen.html b/Doc/Manual/Doxygen.html index 916bd5e87..8b63d5b2b 100644 --- a/Doc/Manual/Doxygen.html +++ b/Doc/Manual/Doxygen.html @@ -226,6 +226,126 @@ instead of the corresponding language tool (javadoc, sphinx,
++Specify that the Doxygen command with the given name should be ignored. This is +useful for custom Doxygen commands which can be defined using ALIASES +option for Doxygen itself but which are unknown to SWIG. "command-name" +is the real name of the command, e.g. you could use +
+ +
+%feature("doxygen:ignore:transferfull");
++if you use a custom Doxygen transferfull command to indicate that the +return value ownership is transferred to the caller, as this information doesn't +make much sense for the other languages without explicit ownership management. +
+ ++Doxygen syntax is rather rich and, in addition to simple commands such as +@transferfull, it is also possible to define commands with arguments. +As explained in Doxygen documentation, +the arguments can have a range of a single word, everything until the end of +line or everything until the end of the next paragraph. Currently, only the "end +of line" case is supported using the range="line" argument of the +feature directive: +
+ +
+// Ignore occurrences of
+//
+// @compiler-options Some special C++ compiler options.
+//
+// in Doxygen comments as C++ options are not interested for the target language
+// developers.
+%feature("doxygen:ignore:compileroptions", range="line");
++In addition, it is also possible to have custom pairs of begin/end tags, +similarly to the standard Doxygen @code/@endcode, for example. Such +tags can also be ignored using the special value of range starting with +end to indicate that the range is an interval, for example: +
+ +
+%feature("doxygen:ignore:forcpponly", range="end"); // same as "end:endforcpponly"
++would ignore everything between @forcpponly and @endforcpponly +commands in Doxygen comments. By default, the name of the end command is the +same as of the start one with "end" prefix, following Doxygen conventions, but +this can be overridden by providing the end command name after the colon. +
++This example shows how custom tags can be used to bracket anything specific to +C++ and prevent it from appearing in the target language documentation. +Conversely, another pair of custom tags could be used to put target language +specific information in the C++ comments. In this case, only the custom tags +themselves should be ignored, but their contents should be parsed as usual and +contents="parse" can be used for this: +
+ +
+%feature("doxygen:ignore:beginPythonOnly", range="end:endPythonOnly", contents="parse");
++Putting everything together, if these directives are in effect: +
+ +
+%feature("doxygen:ignore:transferfull");
+%feature("doxygen:ignore:compileroptions", range="line");
+%feature("doxygen:ignore:forcpponly", range="end");
+%feature("doxygen:ignore:beginPythonOnly", range="end:endPythonOnly", contents="parse");
++then the following C++ Doxygen comment: +
+ ++/** + A contrived example of ignoring too many commands in one comment. + + @forcpponly + This is C++-specific. + @endforcpponly + + @beginPythonOnly + This is specific to @b Python. + @endPythonOnly + + @transferfull Command ignored, but anything here is still included. + + @compileroptions This function must be compiled with /EHa when using MSVC. + */ +void func(); +
+would be translated to this comment in Python: +
+ ++def func(): + r""" + A contrived example of ignoring too many commands in one comment. + + This is specific to **Python**. + + Command ignored, but anything here is still included. + """ + ... +
diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk
index 39ad4c012..76c088cf7 100644
--- a/Examples/test-suite/common.mk
+++ b/Examples/test-suite/common.mk
@@ -551,6 +551,7 @@ $(eval HAS_DOXYGEN := $($(LANGUAGE)_HAS_DOXYGEN))
ifdef HAS_DOXYGEN
DOXYGEN_TEST_CASES += \
doxygen_parsing \
+ doxygen_ignore \
doxygen_basic_translate \
doxygen_basic_notranslate \
doxygen_translate \
diff --git a/Examples/test-suite/doxygen_ignore.i b/Examples/test-suite/doxygen_ignore.i
new file mode 100644
index 000000000..d15110257
--- /dev/null
+++ b/Examples/test-suite/doxygen_ignore.i
@@ -0,0 +1,41 @@
+%module doxygen_ignore
+
+%feature("doxygen:ignore:transferfull");
+%feature("doxygen:ignore:compileroptions", range="line");
+%feature("doxygen:ignore:forcpponly", range="end");
+
+#ifdef SWIGJAVA
+%feature("doxygen:ignore:beginJavaOnly", range="end:endJavaOnly", contents="parse");
+%feature("doxygen:ignore:beginPythonOnly", range="end:endPythonOnly");
+#elif defined(SWIGPYTHON)
+%feature("doxygen:ignore:beginJavaOnly", range="end:endJavaOnly");
+%feature("doxygen:ignore:beginPythonOnly", range="end:endPythonOnly", contents="parse");
+#else
+%feature("doxygen:ignore:beginJavaOnly", range="end:endJavaOnly");
+%feature("doxygen:ignore:beginPythonOnly", range="end:endPythonOnly");
+#endif
+
+%inline %{
+
+/**
+ A contrived example of ignoring too many commands in one comment.
+
+ @forcpponly
+ This is C++-specific.
+ @endforcpponly
+
+ @beginJavaOnly
+ This is specific to @e Java.
+ @endJavaOnly
+
+ @beginPythonOnly
+ This is specific to @b Python.
+ @endPythonOnly
+
+ @transferfull Command ignored, but anything here is still included.
+
+ @compileroptions This function must be compiled with /EHa when using MSVC.
+ */
+void func() { }
+
+%}
diff --git a/Examples/test-suite/java/doxygen_ignore_runme.java b/Examples/test-suite/java/doxygen_ignore_runme.java
new file mode 100644
index 000000000..d6a4d8c8d
--- /dev/null
+++ b/Examples/test-suite/java/doxygen_ignore_runme.java
@@ -0,0 +1,44 @@
+
+import doxygen_ignore.*;
+import com.sun.javadoc.*;
+import java.util.HashMap;
+
+public class doxygen_ignore_runme {
+ static {
+ try {
+ System.loadLibrary("doxygen_ignore");
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
+ System.exit(1);
+ }
+ }
+
+ public static void main(String argv[])
+ {
+ CommentParser parser = new CommentParser();
+ com.sun.tools.javadoc.Main.execute("doxygen_ignore runtime test",
+ "CommentParser",
+ new String[]{"-quiet", "doxygen_ignore"});
+
+ HashMap
\n" +
+ "
\n" +
+ "
\n" +
+ "
\n" +
+ "
\n" +
+ " This is specific to Java.
\n" +
+ "
\n" +
+ "
\n" +
+ "
\n" +
+ "
\n" +
+ " Command ignored, but anything here is still included.
\n" +
+ "
\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "");
+
+ System.exit(parser.check(wantedComments));
+ }
+}
diff --git a/Examples/test-suite/python/doxygen_ignore_runme.py b/Examples/test-suite/python/doxygen_ignore_runme.py
new file mode 100644
index 000000000..7fe2667d3
--- /dev/null
+++ b/Examples/test-suite/python/doxygen_ignore_runme.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+
+import doxygen_ignore
+import commentVerifier
+
+commentVerifier.check(doxygen_ignore.func.__doc__,
+ r"""
+ A contrived example of ignoring too many commands in one comment.
+
+
+
+
+
+
+ This is specific to **Python**.
+
+
+ Command ignored, but anything here is still included.
+
+
+ """)
diff --git a/Source/DoxygenTranslator/src/DoxygenParser.cpp b/Source/DoxygenTranslator/src/DoxygenParser.cpp
index 5e1f3a5d3..c8cb40ab8 100644
--- a/Source/DoxygenTranslator/src/DoxygenParser.cpp
+++ b/Source/DoxygenTranslator/src/DoxygenParser.cpp
@@ -135,6 +135,28 @@ int DoxygenParser::commandBelongs(const std::string &theCommand)
if (it != doxygenCommands.end()) {
return it->second;
}
+
+ // Check if this command should be ignored.
+ if (String* const ignore = getIgnoreFeature(theCommand)) {
+ // Check that no value is specified for this feature ("1" is the implicit
+ // one given to it by SWIG itself), we may use the value in the future, but
+ // for now we only use the attributes.
+ if (Strcmp(ignore, "1") != 0) {
+ Swig_warning(WARN_PP_UNEXPECTED_TOKENS, m_fileName.c_str(), m_fileLineNo,
+ "Feature \"doxygen:ignore\" value ignored for Doxygen command \"%s\".\n",
+ theCommand.c_str());
+ }
+
+ // Also ensure that the matching end command, if any, will be recognized.
+ const string endCommand = getIgnoreFeatureEndCommand(theCommand);
+ if (!endCommand.empty()) {
+ Setattr(m_node, ("feature:doxygen:ignore:" + endCommand).c_str(),
+ NewString("1"));
+ }
+
+ return COMMAND_IGNORE;
+ }
+
return NONE;
}
@@ -878,6 +900,95 @@ int DoxygenParser::addCommandUnique(const std::string &theCommand,
return 0;
}
+String* DoxygenParser::getIgnoreFeature(const std::string& theCommand,
+ const char* argument) const
+{
+ string feature_name = "feature:doxygen:ignore:" + theCommand;
+ if (argument) {
+ feature_name += ':';
+ feature_name += argument;
+ }
+
+ return Getattr(m_node, feature_name.c_str());
+}
+
+string DoxygenParser::getIgnoreFeatureEndCommand(const std::string& theCommand) const
+{
+ // We may be dealing either with a simple command or with the starting command
+ // of a block, as indicated by the value of "range" starting with "end".
+ string endCommand;
+ if (String* const range = getIgnoreFeature(theCommand, "range")) {
+ const char* const p = Char(range);
+ if (strncmp(p, "end", 3) == 0) {
+ if (p[3] == ':') {
+ // Normally the end command name follows after the colon.
+ endCommand = p + 4;
+ } else if (p[3] == '\0') {
+ // But it may be omitted in which case the default Doxygen convention of
+ // using "something"/"endsomething" is used.
+ endCommand = "end" + theCommand;
+ }
+ }
+ }
+
+ return endCommand;
+}
+
+int DoxygenParser::ignoreCommand(const std::string& theCommand,
+ const TokenList &tokList,
+ DoxygenEntityList &doxyList)
+{
+ const string endCommand = getIgnoreFeatureEndCommand(theCommand);
+ if (!endCommand.empty()) {
+ TokenListCIt itEnd = getEndCommand(endCommand, tokList);
+ if (itEnd == tokList.end()) {
+ printListError(WARN_DOXYGEN_COMMAND_EXPECTED, "Expected " + endCommand);
+ return 0;
+ }
+
+ // Determine what to do with the part of the comment between the start and
+ // end commands: by default, we simply throw it away, but "contents"
+ // attribute may be used to change this.
+ if (String* const contents = getIgnoreFeature(theCommand, "contents")) {
+ // Currently only "parse" is supported but we may need to add "copy" to
+ // handle custom tags which contain text that is supposed to be copied
+ // verbatim in the future.
+ if (Strcmp(contents, "parse") == 0) {
+ DoxygenEntityList aNewList = parse(itEnd, tokList);
+ doxyList.splice(doxyList.end(), aNewList);
+ } else {
+ Swig_error(m_fileName.c_str(), m_fileLineNo,
+ "Invalid \"doxygen:ignore\" feature \"contents\" attribute \"%s\".\n",
+ Char(contents)
+ );
+ return 0;
+ }
+ }
+
+ m_tokenListIt = itEnd;
+ m_tokenListIt++;
+ } else if (String* const range = getIgnoreFeature(theCommand, "range")) {
+ // Currently we only support "line" but, in principle, we should also
+ // support "word" and "paragraph" for consistency with the built-in Doxygen
+ // commands which can have either of these three ranges (which are indicated
+ // using