Add a possibility to flexibly ignore custom Doxygen tags.
Add %feature("doxygen:ignore:<command>") implementation, documentation and
test case.
This feature allows to use custom tags in C++ Doxygen comments for
C++-specific things that don't make sense in the context of the target
language and also allows to insert contents specific to the target language in
the C++ comments using (different) custom commands, which is very useful in
practice to explain the particularities of the API wrappers.
This commit is contained in:
parent
cd1f4619d2
commit
05b5ed11bc
7 changed files with 360 additions and 0 deletions
|
|
@ -226,6 +226,126 @@ instead of the corresponding language tool (<tt>javadoc</tt>, <tt>sphinx</tt>,
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>doxygen:ignore:<command-name></h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Specify that the Doxygen command with the given name should be ignored. This is
|
||||||
|
useful for custom Doxygen commands which can be defined using <tt>ALIASES</tt>
|
||||||
|
option for Doxygen itself but which are unknown to SWIG. <tt>"command-name"</tt>
|
||||||
|
is the real name of the command, e.g. you could use
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code"><pre>
|
||||||
|
%feature("doxygen:ignore:transferfull");
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
if you use a custom Doxygen <tt>transferfull</tt> 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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Doxygen syntax is rather rich and, in addition to simple commands such as
|
||||||
|
<tt>@transferfull</tt>, it is also possible to define commands with arguments.
|
||||||
|
As explained in <a href="http://www.stack.nl/~dimitri/doxygen/manual/commands.html">Doxygen documentation</a>,
|
||||||
|
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 <tt>range="line"</tt> argument of the
|
||||||
|
feature directive:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code"><pre>
|
||||||
|
// 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");
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In addition, it is also possible to have custom pairs of begin/end tags,
|
||||||
|
similarly to the standard Doxygen <tt>@code/@endcode</tt>, for example. Such
|
||||||
|
tags can also be ignored using the special value of <tt>range</tt> starting with
|
||||||
|
<tt>end</tt> to indicate that the range is an interval, for example:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code"><pre>
|
||||||
|
%feature("doxygen:ignore:forcpponly", range="end"); // same as "end:endforcpponly"
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
would ignore everything between <tt>@forcpponly</tt> and <tt>@endforcpponly</tt>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
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
|
||||||
|
<tt>contents="parse"</tt> can be used for this:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code"><pre>
|
||||||
|
%feature("doxygen:ignore:beginPythonOnly", range="end:endPythonOnly", contents="parse");
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Putting everything together, if these directives are in effect:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code"><pre>
|
||||||
|
%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");
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
then the following C++ Doxygen comment:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code"><pre>
|
||||||
|
/**
|
||||||
|
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();
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
would be translated to this comment in Python:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code"><pre>
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
|
||||||
<h4>doxygen:nolinkranslate (Java-only currently)</h4>
|
<h4>doxygen:nolinkranslate (Java-only currently)</h4>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
|
|
@ -551,6 +551,7 @@ $(eval HAS_DOXYGEN := $($(LANGUAGE)_HAS_DOXYGEN))
|
||||||
ifdef HAS_DOXYGEN
|
ifdef HAS_DOXYGEN
|
||||||
DOXYGEN_TEST_CASES += \
|
DOXYGEN_TEST_CASES += \
|
||||||
doxygen_parsing \
|
doxygen_parsing \
|
||||||
|
doxygen_ignore \
|
||||||
doxygen_basic_translate \
|
doxygen_basic_translate \
|
||||||
doxygen_basic_notranslate \
|
doxygen_basic_notranslate \
|
||||||
doxygen_translate \
|
doxygen_translate \
|
||||||
|
|
|
||||||
41
Examples/test-suite/doxygen_ignore.i
Normal file
41
Examples/test-suite/doxygen_ignore.i
Normal file
|
|
@ -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() { }
|
||||||
|
|
||||||
|
%}
|
||||||
44
Examples/test-suite/java/doxygen_ignore_runme.java
Normal file
44
Examples/test-suite/java/doxygen_ignore_runme.java
Normal file
|
|
@ -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<String, String> wantedComments = new HashMap<String, String>();
|
||||||
|
wantedComments.put("doxygen_ignore.doxygen_ignore.func()",
|
||||||
|
" A contrived example of ignoring too many commands in one comment.<br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
" This is specific to <i>Java</i>.<br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
" Command ignored, but anything here is still included.<br>\n" +
|
||||||
|
" <br>\n" +
|
||||||
|
"\n" +
|
||||||
|
"\n" +
|
||||||
|
"\n" +
|
||||||
|
"");
|
||||||
|
|
||||||
|
System.exit(parser.check(wantedComments));
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Examples/test-suite/python/doxygen_ignore_runme.py
Normal file
21
Examples/test-suite/python/doxygen_ignore_runme.py
Normal file
|
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
""")
|
||||||
|
|
@ -135,6 +135,28 @@ int DoxygenParser::commandBelongs(const std::string &theCommand)
|
||||||
if (it != doxygenCommands.end()) {
|
if (it != doxygenCommands.end()) {
|
||||||
return it->second;
|
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;
|
return NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -878,6 +900,95 @@ int DoxygenParser::addCommandUnique(const std::string &theCommand,
|
||||||
return 0;
|
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 <word-arg>, (line-arg) and {para-arg} respectively in Doxygen
|
||||||
|
// documentation).
|
||||||
|
if (Strcmp(range, "line") == 0) {
|
||||||
|
// Consume everything until the end of line.
|
||||||
|
m_tokenListIt = getOneLine(tokList);
|
||||||
|
skipEndOfLine();
|
||||||
|
} else {
|
||||||
|
Swig_error(m_fileName.c_str(), m_fileLineNo,
|
||||||
|
"Invalid \"doxygen:ignore\" feature \"range\" attribute \"%s\".\n",
|
||||||
|
Char(range)
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int DoxygenParser::addCommand(const std::string &commandString,
|
int DoxygenParser::addCommand(const std::string &commandString,
|
||||||
const TokenList &tokList,
|
const TokenList &tokList,
|
||||||
DoxygenEntityList &doxyList)
|
DoxygenEntityList &doxyList)
|
||||||
|
|
@ -920,6 +1031,8 @@ int DoxygenParser::addCommand(const std::string &commandString,
|
||||||
return addCommandHtml(theCommand, tokList, doxyList);
|
return addCommandHtml(theCommand, tokList, doxyList);
|
||||||
case COMMAND_HTML_ENTITY:
|
case COMMAND_HTML_ENTITY:
|
||||||
return addCommandHtmlEntity(theCommand, tokList, doxyList);
|
return addCommandHtmlEntity(theCommand, tokList, doxyList);
|
||||||
|
case COMMAND_IGNORE:
|
||||||
|
return ignoreCommand(commandString, tokList, doxyList);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ private:
|
||||||
COMMANDUNIQUE,
|
COMMANDUNIQUE,
|
||||||
COMMAND_HTML,
|
COMMAND_HTML,
|
||||||
COMMAND_HTML_ENTITY,
|
COMMAND_HTML_ENTITY,
|
||||||
|
COMMAND_IGNORE,
|
||||||
END_LINE,
|
END_LINE,
|
||||||
PARAGRAPH_END,
|
PARAGRAPH_END,
|
||||||
PLAINSTRING,
|
PLAINSTRING,
|
||||||
|
|
@ -98,6 +99,17 @@ private:
|
||||||
std::string m_fileName;
|
std::string m_fileName;
|
||||||
int m_fileLineNo;
|
int m_fileLineNo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the end command for a command appearing in "ignore" feature or empty
|
||||||
|
* string if this is a simple command and not a block one.
|
||||||
|
*/
|
||||||
|
std::string getIgnoreFeatureEndCommand(const std::string& theCommand) const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper for getting the value of doxygen:ignore feature or its argument.
|
||||||
|
*/
|
||||||
|
String* getIgnoreFeature(const std::string& theCommand, const char* argument = NULL) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Whether to print lots of debug info during parsing
|
* Whether to print lots of debug info during parsing
|
||||||
*/
|
*/
|
||||||
|
|
@ -334,6 +346,14 @@ private:
|
||||||
const TokenList &tokList,
|
const TokenList &tokList,
|
||||||
DoxygenEntityList &doxyList);
|
DoxygenEntityList &doxyList);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simply ignore the given command, possibly with the word following it or
|
||||||
|
* until the matching end command.
|
||||||
|
*/
|
||||||
|
int ignoreCommand(const std::string& theCommand,
|
||||||
|
const TokenList &tokList,
|
||||||
|
DoxygenEntityList &doxyList);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The actual "meat" of the doxygen parser. Calls the correct addCommand...()
|
* The actual "meat" of the doxygen parser. Calls the correct addCommand...()
|
||||||
* function.
|
* function.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue