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>
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
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()) {
|
||||
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 <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,
|
||||
const TokenList &tokList,
|
||||
DoxygenEntityList &doxyList)
|
||||
|
|
@ -920,6 +1031,8 @@ int DoxygenParser::addCommand(const std::string &commandString,
|
|||
return addCommandHtml(theCommand, tokList, doxyList);
|
||||
case COMMAND_HTML_ENTITY:
|
||||
return addCommandHtmlEntity(theCommand, tokList, doxyList);
|
||||
case COMMAND_IGNORE:
|
||||
return ignoreCommand(commandString, tokList, doxyList);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ private:
|
|||
COMMANDUNIQUE,
|
||||
COMMAND_HTML,
|
||||
COMMAND_HTML_ENTITY,
|
||||
COMMAND_IGNORE,
|
||||
END_LINE,
|
||||
PARAGRAPH_END,
|
||||
PLAINSTRING,
|
||||
|
|
@ -98,6 +99,17 @@ private:
|
|||
std::string m_fileName;
|
||||
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
|
||||
*/
|
||||
|
|
@ -334,6 +346,14 @@ private:
|
|||
const TokenList &tokList,
|
||||
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...()
|
||||
* function.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue