Merge branch 'vadz-doxygen'

This is the Doxygen work begun in Google Summer of Code projects 2008
and 2012 and subsequently improved by numerous contributors.

* vadz-doxygen: (314 commits)
  Add changes entry for Doxygen support
  Add some missing doctype tyemaps
  Doxygen warnings cleanup
  Move doxygen warning numbers
  Add Python doxygen example
  Doxygen example
  Add Doxygen to include paths
  Doxygen source rename
  More merge fixes from doxygen branches
  Correct python example headers
  Correct source code headers
  Another merge fix from doxygen branches
  Java enums output format fixes
  Add omitted doxygen_parsing_enums testcase
  PEP8 conformance for comment verifier module
  Clean up merge problem
  Doxygen html tweaks
  Update html chapter numbering for added Doxygen chapter
  Fixes to makechap.py to detect ill-formed headers
  html fixes for Doxygen
  Add missing CPlusPlus17.html file
  Format files to unix format
  Doxygen testcase tweak to match that in the html docs
  Doxygen html documentation updates and corrections
  Remove doxygen Examples subdirectory
  Beautify doxygen source code
  Code formatting fixes in doxygen code
  Remove unused doxygen code
  new_node refactor
  Various merge fixes in doxygen branches
  Unused variable warning fix
  Fix wrongly resetting indent after formulae in Doxygen comments
  Add support for doxygen:alias feature
  Get rid of meaningless return type of DoxygenParser methods
  Return enum, not untyped int, when classifying Doxygen commands
  Get rid of unnecessary "typedef enum" in C++ code
  Use slash, not backslash, in "C/C++" in the documentation
  Replace literal "<" with "&lt;" in HTML documentation
  Fix broken link to java.sun.com in Doxygen documentation
  Fix using com.sun.tools.javadoc package under macOS
  Fix error reporting for special characters in Doxygen parsing code
  Switch Python Doxygen unit tests to use inspect.getdoc()
  Use correct separator in Java class path under Windows.
  Remove executable permission from appveyor.yml.
  Use JAVA_HOME value in configure to detect Java.
  Display JAVA_HOME value in "make java_version".
  Fix harmless MSVC warning in DoxygenTranslator code.
  Reset "_last" for all but first enum elements.
  Don't duplicate Javadoc from global enum Doxygen comments twice.
  Move Doxygen comments concatenation from the parser to the lexer.
  Fix shift/reduce conflicts in Doxygen pre/post comment parsing.
  Rewrote part of the grammar dealing with Doxygen comments for enums.
  No changes, just remove spurious white space only differences.
  Move Doxygen comment mangling from the parser to the lexer.
  Merge "-builtin" autodoc bugs workarounds from master into test.
  Quote JAVA_HOME variable value in Java test suite makefile.
  Remove unused C_COMMENT_STRING terminal from the grammar.
  Fix missing returns in the Doxygen test suite code.
  Fix trimming whitespace from Doxygen comments.
  Remove code not doing anything from PyDocConverter.
  Remove unused <sstream> header.
  Remove unreferenced struct declaration.
  Remove unused Swig_warn() function.
  Remove any whitespace before ignored Doxygen commands.
  Remove trailing space from one of Doxygen tests.
  Fix autodoc strings generated in Python builtin case and the test.
  Fix Doxygen unit test in Python "-builtin" case.
  Use class docstrings in "-builtin" Python case.
  Don't indent Doxygen doc strings in generated Python code.
  Add a possibility to flexibly ignore custom Doxygen tags.
  Stop completely ignoring many Doxygen comments.
  Fix structural Doxygen comment recognition in the parser.
  No changes, just make checking for Doxygen structural tags more sane.
  Use "//", not "#", for comments in SWIG input.
  Allow upper case letters and digits in Doxygen words.
  Pass the node the Doxygen comment is attached to to DoxygenParser.
  Get rid of findCommand() which duplicaed commandBelongs().
  Recognize unknown Doxygen tags correctly.
  No real changes, just pass original command to commandBelongs().
  Describe Doxygen-specific %features in a single place.
  Give warnings for unknown Doxygen commands in Doxygen parser.
  Document the return type when translating Doxygen @return to Python.
  Fix translated Doxygen comments for overloaded functions in Python.
  Also merge Doxygen comments for overloaded constructors in Python.
  Allow using enum elements as default values for Python functions.
  Don't always use "*args" for all Python wrapper functions.
  No real changes, just make PYTHON::check_kwargs() const.
  Refactor: move makeParameterName() to common Language base class.
  Remove long line wrapping from Python parameter list generation code.
  Simplify and make more efficient building Python docstrings.
  Translate Doxygen code blocks to Sphinx code blocks.
  Add a simple test of multiple parameters to Doxygen test suite.
  Make Python parameters types hyperlinks in the doc strings.
  Make Language::classLookup() and enumLookup() static.
  Fix arguments of @param, @return etc translations to Python.
  Remove unused method from PyDocConverter.
  No real changes, just remove an unnecessary variable.
  Preserve relative indentation when parsing Doxygen comments.
  Use Sphinx-friendly formatting for overloaded functions documentation.
  Add poor man trailing white space detection to Doxygen Python tests.
  ...
This commit is contained in:
William S Fulton 2018-06-07 08:13:10 +01:00
commit 33921666a1
123 changed files with 12964 additions and 1344 deletions

View file

@ -17,6 +17,7 @@
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include "pydoc.h"
#include <iostream>
#include <stdint.h>
@ -90,6 +91,7 @@ static int buildnone = 0;
static int nobuildnone = 0;
static int safecstrings = 0;
static int dirvtable = 0;
static int doxygen = 0;
static int proxydel = 1;
static int fastunpack = 0;
static int fastproxy = 0;
@ -111,7 +113,8 @@ enum autodoc_t {
AUTODOC_DTOR,
AUTODOC_STATICFUNC,
AUTODOC_FUNC,
AUTODOC_METHOD
AUTODOC_METHOD,
AUTODOC_CONST
};
@ -125,6 +128,9 @@ Python Options (available with -python)\n\
-classptr - Generate shadow 'ClassPtr' as in older swig versions\n\
-cppcast - Enable C++ casting operators (default) \n\
-dirvtable - Generate a pseudo virtual table for directors for faster dispatch \n\
-doxygen - Convert C++ doxygen comments to pydoc comments in proxy classes \n\
-debug-doxygen-parser - Display doxygen parser module debugging information\n\
-debug-doxygen-translator - Display doxygen translator module debugging information\n\
-extranative - Return extra native C++ wraps for std containers when possible \n\
-fastinit - Use fast init mechanism for classes (default)\n\
-fastunpack - Use fast unpack mechanism to parse the argument functions \n\
@ -261,6 +267,11 @@ public:
director_multiple_inheritance = 1;
director_language = 1;
}
~PYTHON() {
delete doxygenTranslator;
}
/* ------------------------------------------------------------
* Thread Implementation
* ------------------------------------------------------------ */
@ -336,6 +347,8 @@ public:
SWIG_library_directory("python");
int doxygen_translator_flags = 0;
for (int i = 1; i < argc; i++) {
if (argv[i]) {
if (strcmp(argv[i], "-interface") == 0) {
@ -426,6 +439,16 @@ public:
} else if (strcmp(argv[i], "-nodirvtable") == 0) {
dirvtable = 0;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-doxygen") == 0) {
doxygen = 1;
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], "-fastunpack") == 0) {
fastunpack = 1;
Swig_mark_arg(i);
@ -547,6 +570,9 @@ public:
if (cppcast) {
Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0);
}
if (doxygen)
doxygenTranslator = new PyDocConverter(doxygen_translator_flags);
if (!global_name)
global_name = NewString("cvar");
@ -1654,7 +1680,89 @@ public:
bool have_docstring(Node *n) {
String *str = Getattr(n, "feature:docstring");
return (str && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc"));
return ((str && Len(str) > 0)
|| (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc"))
|| (doxygen && doxygenTranslator->hasDocumentation(n))
);
}
/* ------------------------------------------------------------
* build_combined_docstring()
*
* Build the full docstring which may be a combination of the
* explicit docstring and autodoc string or, if none of them
* is specified, obtained by translating Doxygen comment to
* Python.
*
* Return new string to be deleted by caller (never NIL but
* may be empty if there is no docstring).
* ------------------------------------------------------------ */
String *build_combined_docstring(Node *n, autodoc_t ad_type, const String *indent = "") {
String *docstr = Getattr(n, "feature:docstring");
if (docstr && Len(docstr)) {
docstr = Copy(docstr);
char *t = Char(docstr);
if (*t == '{') {
Delitem(docstr, 0);
Delitem(docstr, DOH_END);
}
}
if (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) {
String *autodoc = make_autodoc(n, ad_type);
if (autodoc && Len(autodoc) > 0) {
if (docstr && Len(docstr)) {
Append(autodoc, "\n");
Append(autodoc, docstr);
}
String *tmp = autodoc;
autodoc = docstr;
docstr = tmp;
}
Delete(autodoc);
}
if (!docstr || !Len(docstr)) {
if (doxygen) {
docstr = Getattr(n, "python:docstring");
if (!docstr && doxygenTranslator->hasDocumentation(n)) {
docstr = doxygenTranslator->getDocumentation(n);
// Avoid rebuilding it again the next time: notice that we can't do
// this for the combined doc string as autodoc part of it depends on
// the sym:name of the node and it is changed while handling it, so
// the cached results become incorrect. But Doxygen docstring only
// depends on the comment which is not going to change, so we can
// safely cache it.
Setattr(n, "python:docstring", Copy(docstr));
}
}
}
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, "\n");
Append(tmp, indent_docstring(docstr, indent));
Append(tmp, indent);
Delete(docstr);
docstr = tmp;
}
return docstr;
}
/* ------------------------------------------------------------
@ -1665,74 +1773,39 @@ public:
* set then it will build a combined docstring.
* ------------------------------------------------------------ */
String *docstring(Node *n, autodoc_t ad_type, const String *indent, bool use_triple = true) {
String *str = Getattr(n, "feature:docstring");
bool have_ds = (str && Len(str) > 0);
bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc"));
const char *triple_double = use_triple ? "\"\"\"" : "";
String *autodoc = NULL;
String *doc = NULL;
String *docstring(Node *n, autodoc_t ad_type, const String *indent) {
String *docstr = build_combined_docstring(n, ad_type, indent);
if (!Len(docstr))
return docstr;
if (have_ds) {
char *t = Char(str);
if (*t == '{') {
Delitem(str, 0);
Delitem(str, DOH_END);
}
}
// Notice that all comments are created as raw strings (prefix "r"),
// because '\' is used often in comments, but may break Python module from
// loading. For example, in doxy comment one may write path in quotes:
//
// This is path to file "C:\x\file.txt"
//
// Python will not load the module with such comment because of illegal
// escape '\x'. '\' may additionally appear in verbatim or htmlonly sections
// of doxygen doc, Latex expressions, ...
String *doc = NewString("");
Append(doc, "r\"\"\"");
Append(doc, docstr);
Append(doc, "\"\"\"");
Delete(docstr);
if (have_auto) {
autodoc = make_autodoc(n, ad_type);
have_auto = (autodoc && Len(autodoc) > 0);
}
// 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 (have_auto && have_ds) { // Both autodoc and docstring are present
doc = NewString("");
Printv(doc, triple_double, "\n",
indent_docstring(autodoc, indent), "\n",
indent_docstring(str, indent), indent, triple_double, NIL);
} else if (!have_auto && have_ds) { // only docstring
if (Strchr(str, '\n') == 0) {
doc = NewStringf("%s%s%s", triple_double, str, triple_double);
} else {
doc = NewString("");
Printv(doc, triple_double, "\n", indent_docstring(str, indent), indent, triple_double, NIL);
}
} else if (have_auto && !have_ds) { // only autodoc
if (Strchr(autodoc, '\n') == 0) {
doc = NewStringf("%s%s%s", triple_double, autodoc, triple_double);
} else {
doc = NewString("");
Printv(doc, triple_double, "\n", indent_docstring(autodoc, indent), indent, triple_double, NIL);
}
} else
doc = NewString("");
// Save the generated strings in the parse tree in case they are used later
// by post processing tools
Setattr(n, "python:docstring", doc);
Setattr(n, "python:autodoc", autodoc);
return doc;
}
}
/* ------------------------------------------------------------
* cdocstring()
*
* Get the docstring text as it would appear in C-language
* source code.
* source code (but without quotes around it).
* ------------------------------------------------------------ */
String *cdocstring(Node *n, autodoc_t ad_type)
{
String *ds = docstring(n, ad_type, "", false);
String *ds = build_combined_docstring(n, ad_type);
Replaceall(ds, "\\", "\\\\");
Replaceall(ds, "\"", "\\\"");
Replaceall(ds, "\n", "\\n\"\n\t\t\"");
@ -2008,17 +2081,24 @@ public:
break;
case AUTODOC_METHOD:
String *paramList = make_autodocParmList(n, showTypes);
Printf(doc, "%s(", symname);
if (showTypes)
Printf(doc, "%s ", class_name);
if (Len(paramList))
Printf(doc, "self, %s)", paramList);
else
Printf(doc, "self)");
if (type_str)
Printf(doc, " -> %s", type_str);
{
String *paramList = make_autodocParmList(n, showTypes);
Printf(doc, "%s(", symname);
if (showTypes)
Printf(doc, "%s ", class_name);
if (Len(paramList))
Printf(doc, "self, %s)", paramList);
else
Printf(doc, "self)");
if (type_str)
Printf(doc, " -> %s", type_str);
}
break;
case AUTODOC_CONST:
// There is no autodoc support for constants currently, this enum
// element only exists to allow calling docstring() with it.
return NULL;
}
Delete(type_str);
}
@ -3641,20 +3721,21 @@ public:
}
if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) {
String *f_s;
if (!in_class) {
if(needs_swigconstant(n)) {
Printv(f_shadow, "\n",NIL);
Printv(f_shadow, module, ".", iname, "_swigconstant(",module,")\n", NIL);
}
Printv(f_shadow, iname, " = ", module, ".", iname, "\n", NIL);
f_s = f_shadow;
} else {
if (!(Getattr(n, "feature:python:callback"))) {
if(needs_swigconstant(n)) {
Printv(f_shadow_stubs, "\n",NIL);
Printv(f_shadow_stubs, module, ".", iname, "_swigconstant(", module, ")\n", NIL);
}
Printv(f_shadow_stubs, iname, " = ", module, ".", iname, "\n", NIL);
f_s = Getattr(n, "feature:python:callback") ? NIL : f_shadow_stubs;
}
if (f_s) {
if (needs_swigconstant(n)) {
Printv(f_s, "\n",NIL);
Printv(f_s, module, ".", iname, "_swigconstant(",module,")\n", NIL);
}
Printv(f_s, iname, " = ", module, ".", iname, "\n", NIL);
if (have_docstring(n))
Printv(f_s, docstring(n, AUTODOC_CONST, tab4), "\n", NIL);
}
}
return SWIG_OK;
@ -4137,7 +4218,16 @@ public:
Printv(f, "#else\n", NIL);
printSlot(f, getSlot(n, "feature:python:tp_flags", tp_flags), "tp_flags");
Printv(f, "#endif\n", NIL);
printSlot(f, quoted_tp_doc_str, "tp_doc");
if (have_docstring(n)) {
String *ds = cdocstring(n, AUTODOC_CLASS);
String *tp_doc = NewString("");
Printf(tp_doc, "\"%s\"", ds);
Delete(ds);
printSlot(f, tp_doc, "tp_doc");
Delete(tp_doc);
} else {
printSlot(f, quoted_tp_doc_str, "tp_doc");
}
printSlot(f, getSlot(n, "feature:python:tp_traverse"), "tp_traverse", "traverseproc");
printSlot(f, getSlot(n, "feature:python:tp_clear"), "tp_clear", "inquiry");
printSlot(f, getSlot(n, "feature:python:tp_richcompare", richcompare_func), "tp_richcompare", "richcmpfunc");
@ -4473,6 +4563,8 @@ public:
}
Printf(f_shadow, ":\n");
// write docstrings if requested
if (have_docstring(n)) {
String *str = docstring(n, AUTODOC_CLASS, tab4);
if (str && Len(str))
@ -4703,7 +4795,7 @@ public:
String *wname = Swig_name_wrapper(fullname);
Setattr(class_members, symname, n);
int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2;
String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_FUNC) : NewString("");
String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_METHOD) : NewString("");
if (check_kwargs(n)) {
Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_VARARGS|METH_KEYWORDS, (char *) \"%s\" },\n", symname, wname, ds);
} else if (argcount == 0) {
@ -5218,6 +5310,8 @@ public:
Swig_restore(n);
} else if (shadow) {
Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), "\n", NIL);
if (have_docstring(n))
Printv(f_shadow, tab4, docstring(n, AUTODOC_CONST, tab4), "\n", NIL);
}
return SWIG_OK;
}