diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index ec47ffaa0..ed2d74cd9 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -188,6 +188,7 @@ CPP_TEST_CASES += \ director_wombat \ disown \ doxygen_parsing \ + doxygen_basic_translate \ dynamic_cast \ empty \ enum_rename \ diff --git a/Examples/test-suite/doxygen_basic_translate.i b/Examples/test-suite/doxygen_basic_translate.i new file mode 100644 index 000000000..c961164d5 --- /dev/null +++ b/Examples/test-suite/doxygen_basic_translate.i @@ -0,0 +1,16 @@ +%module doxygen_basic_translate + +%inline %{ + +/** + * \brief Brief description. + * The comment text + * \author Some author + * \return Some number + * \sa function2 + */ +int function() +{ +} + +%} \ No newline at end of file diff --git a/Examples/test-suite/java/doxygen_basic_translate_runme.java b/Examples/test-suite/java/doxygen_basic_translate_runme.java new file mode 100644 index 000000000..7aee4221b --- /dev/null +++ b/Examples/test-suite/java/doxygen_basic_translate_runme.java @@ -0,0 +1,94 @@ + +import doxygen_basic_translate.*; +import com.sun.javadoc.*; +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.Iterator; + +public class doxygen_basic_translate_runme { + static { + try { + System.loadLibrary("doxygen_basic_translate"); + } 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); + } + } + + static HashMap parsedComments = new HashMap(); + static HashMap wantedComments = new HashMap(); + + public static boolean start(RootDoc root) { + + /* + This method is called by 'javadoc' and gets the whole parsed + java file, we get comments and store them + */ + + ClassDoc[] classes = root.classes(); + + for (int i = 0; i < classes.length; i++) { + + if (classes[i].getRawCommentText().length() > 0) + parsedComments.put(classes[i].name(), classes[i].getRawCommentText()); + + MethodDoc[] methods = classes[i].methods(); + FieldDoc[] fields = classes[i].fields(); + FieldDoc[] constants = classes[i].enumConstants(); + + for (int j = 0; j < constants.length; j++) { + FieldDoc f = constants[j]; + if (f.getRawCommentText().length() > 0) + parsedComments.put(f.name(), f.getRawCommentText()); + } + for (int j = 0; j < fields.length; j++) { + FieldDoc f = fields[j]; + if (f.getRawCommentText().length() > 0) + parsedComments.put(f.name(), f.getRawCommentText()); + } + for (int j = 0; j < methods.length; j++) { + MethodDoc m = methods[j]; + if (m.getRawCommentText().length() > 0) + parsedComments.put(m.name(), m.getRawCommentText()); + } + } + return true; + } + + public static void main(String argv[]) + { + /* + Here we are using internal javadoc tool, it accepts the name of the class as paramterer, + and calls the start() method of that class with parsed information. + */ + com.sun.tools.javadoc.Main.execute("doxygen_basic_translate runtime test", + "doxygen_basic_translate_runme", new String[]{"-quiet", "doxygen_basic_translate"}); + + wantedComments.put("function", " Brief description. \n The comment text \n" + + " @author\tSome author \n" + + " @return\tSome number \n" + + " @see\tfunction2 \n"); + + int errorCount=0; + Iterator< Entry > it = parsedComments.entrySet().iterator(); + + while (it.hasNext()) + { + Entry e = (Entry) it.next(); + + if (!e.getValue().equals(wantedComments.get(e.getKey()))) { + System.out.println("Documentation comments for " + e.getKey() + " does not match: "); + System.out.println("\texpected:"+wantedComments.get(e.getKey())); + System.out.println("\tgot:\t"+e.getValue()); + errorCount++; + } + } + + if (parsedComments.size() != wantedComments.size()) { + System.out.println("Found " + (wantedComments.size()-parsedComments.size()) + " missed comment(s)!"); + errorCount++; + } + + System.exit(errorCount); + } +} diff --git a/Source/DoxygenTranslator/src/JavaDocConverter.cpp b/Source/DoxygenTranslator/src/JavaDocConverter.cpp index 812a6c34d..0c332c3b9 100644 --- a/Source/DoxygenTranslator/src/JavaDocConverter.cpp +++ b/Source/DoxygenTranslator/src/JavaDocConverter.cpp @@ -14,9 +14,64 @@ #include #define APPROX_LINE_LENGTH 64 //characters per line allowed #define TAB_SIZE 8 //current tab size in spaces -int printSortedTree2 = 0; //TODO {@link} {@linkplain} {@docRoot}, and other useful doxy commands that are not a javadoc tag +// define static escape table, it is filled in JavaDocConverter's constructor +std::map JavaDocConverter::escapeTable; + +void JavaDocConverter::fillEscapeTable() { + if (escapeTable.size()) // fill only once + return; + + escapeTable["&"] = "&"; + escapeTable["\'"] = "&apos"; + escapeTable["\""] = """; + escapeTable["<"] = "<"; + escapeTable[">"] = ">"; +} + + +JavaDocConverter::JavaDocConverter() : debug(false) { + + fillEscapeTable(); + + // these commands insert HTML tags + tagHandlers["c"] = &handleTagC; + tagHandlers["b"] = &handleTagB; + // these commands insert just a single char, all of them need to be escaped + tagHandlers["$"] = &handleTagChar; + tagHandlers["@"] = &handleTagChar; + tagHandlers["\\"] = &handleTagChar; + tagHandlers["<"] = &handleTagChar; + tagHandlers[">"] = &handleTagChar; + tagHandlers["&"] = &handleTagChar; + tagHandlers["#"] = &handleTagChar; + tagHandlers["%"] = &handleTagChar; + tagHandlers["~"] = &handleTagChar; + tagHandlers["\""] = &handleTagChar; + tagHandlers["."] = &handleTagChar; + tagHandlers["::"] = &handleTagChar; + // these commands are stripped out + tagHandlers["brief"] = &handleTagStrip; + tagHandlers["details"] = &handleTagStrip; + tagHandlers["partofdescription"] = &handleTagStrip; + // these commands are kept as-is, they are supported by JavaDoc + tagHandlers["sa"] = &handleTagSeeAll; + tagHandlers["see"] = &handleTagSame; + tagHandlers["param"] = &handleTagSame; + tagHandlers["return"] = &handleTagSame; + tagHandlers["throws"] = &handleTagSame; + tagHandlers["throw"] = &handleTagThrow; + tagHandlers["author"] = &handleTagSame; + tagHandlers["since"] = &handleTagSame; + tagHandlers["version"] = &handleTagSame; + tagHandlers["exception"] = &handleTagSame; + tagHandlers["deprecated"] = &handleTagSame; + // this command just prints it's contents + // (it is internal command of swig's parser, contains plain text) + tagHandlers["plainstd::string"] = &handleTagData; +} + std::string JavaDocConverter::formatCommand(std::string unformattedLine, int indent) { std::string formattedLines = "\n * "; int lastPosition = 0; @@ -56,99 +111,58 @@ std::string JavaDocConverter::formatCommand(std::string unformattedLine, int ind return formattedLines; } -/* Contains the conversions for tags - * could probably be much more efficient... - */ -std::string JavaDocConverter::javaDocFormat(DoxygenEntity & doxygenEntity) { - if (doxygenEntity.typeOfEntity.compare("partofdescription") == 0) { - return doxygenEntity.data; - } - if (doxygenEntity.typeOfEntity.compare("plainstd::string") == 0) { - return doxygenEntity.data; - } else if (doxygenEntity.typeOfEntity.compare("b") == 0) { - return "" + doxygenEntity.data + ""; - } else if (doxygenEntity.typeOfEntity.compare("c") == 0) { - return "" + doxygenEntity.data + ""; - } else if (doxygenEntity.typeOfEntity.compare("@") == 0) { - return "@"; - } else if (doxygenEntity.typeOfEntity.compare("\\") == 0) { - return "\\"; - } else if (doxygenEntity.typeOfEntity.compare("<") == 0) { - return "<"; - } else if (doxygenEntity.typeOfEntity.compare(">") == 0) { - return ">"; - } else if (doxygenEntity.typeOfEntity.compare("&") == 0) { - return "&"; - } else if (doxygenEntity.typeOfEntity.compare("#") == 0) { - return "#"; - } else if (doxygenEntity.typeOfEntity.compare("%") == 0) { - return "%"; - } else if (doxygenEntity.typeOfEntity.compare("~") == 0) { - return "~"; - } - return ""; -} - - std::string JavaDocConverter::translateSubtree(DoxygenEntity & doxygenEntity) { - std::string returnedString; - if (doxygenEntity.isLeaf) { - return javaDocFormat(doxygenEntity) + " "; - } else { - returnedString += javaDocFormat(doxygenEntity); - std::list < DoxygenEntity >::iterator p = doxygenEntity.entityList.begin(); - - while (p != doxygenEntity.entityList.end()) { - returnedString += translateSubtree(*p); - p++; - } + std::string translatedComment; + + if (doxygenEntity.isLeaf) + return translatedComment; + + std::list < DoxygenEntity >::iterator p = doxygenEntity.entityList.begin(); + while (p != doxygenEntity.entityList.end()) { + translateEntity(*p, translatedComment); + translateSubtree(*p); + p++; } - return returnedString; + + return translatedComment; } - -std::string JavaDocConverter::translateEntity(DoxygenEntity & doxyEntity) { - if (doxyEntity.typeOfEntity.compare("partofdescription") == 0) { - return formatCommand(std::string(translateSubtree(doxyEntity)), 0); - } - - if ((doxyEntity.typeOfEntity.compare("brief") == 0) || (doxyEntity.typeOfEntity.compare("details") == 0)) { - return formatCommand(std::string(translateSubtree(doxyEntity)), 0) + "\n * "; - - } else if (doxyEntity.typeOfEntity.compare("plainstd::string") == 0 || - doxyEntity.typeOfEntity.compare("deprecated") == 0 || - doxyEntity.typeOfEntity.compare("brief") == 0) { - return formatCommand(doxyEntity.data, 0) + "\n * "; - - } else if (doxyEntity.typeOfEntity.compare("see") == 0) { - return formatCommand(std::string("@" + doxyEntity.typeOfEntity + "\t\t" + translateSubtree(doxyEntity)), 2); - - } else if (doxyEntity.typeOfEntity.compare("return") == 0 - || doxyEntity.typeOfEntity.compare("author") == 0 - || doxyEntity.typeOfEntity.compare("param") == 0 - || doxyEntity.typeOfEntity.compare("throw") == 0 - || doxyEntity.typeOfEntity.compare("throws") == 0 - || doxyEntity.typeOfEntity.compare("since") == 0 - || doxyEntity.typeOfEntity.compare("version") == 0 - || doxyEntity.typeOfEntity.compare("exception") == 0 - || doxyEntity.typeOfEntity.compare("deprecated") == 0) { - - // this 'if' is a hack - convert doxyEntity.typeOfEntity at the time of parsing - if (doxyEntity.typeOfEntity.compare("throw") == 0) { - doxyEntity.typeOfEntity = "throws"; - } - return formatCommand(std::string("@" + doxyEntity.typeOfEntity + "\t" + translateSubtree(doxyEntity)), 2); - - } else if (doxyEntity.typeOfEntity.compare("sa") == 0) { - return formatCommand(std::string("@see\t\t" + translateSubtree(doxyEntity)), 2); - - } else { - return formatCommand(javaDocFormat(doxyEntity), 0); - } - - return ""; +void JavaDocConverter::translateEntity(DoxygenEntity& tag, std::string& translatedComment) { + // check if we have needed handler and call it + if (tagHandlers.find(tag.typeOfEntity)!=tagHandlers.end()) + tagHandlers[tag.typeOfEntity](this, tag, translatedComment); } +void JavaDocConverter::handleTagC(JavaDocConverter* converter, DoxygenEntity& tag, std::string& translatedComment) { + translatedComment += "" + tag.data + ""; +} +void JavaDocConverter::handleTagB(JavaDocConverter* converter, DoxygenEntity& tag, std::string& translatedComment) { + translatedComment += "" + tag.data + ""; +} +void JavaDocConverter::handleTagThrow(JavaDocConverter* converter, DoxygenEntity& tag, std::string& translatedComment) { + tag.typeOfEntity = "throws"; + handleTagSame(converter, tag, translatedComment); +} +void JavaDocConverter::handleTagSeeAll(JavaDocConverter* converter, DoxygenEntity& tag, std::string& translatedComment) { + tag.typeOfEntity = "see"; + handleTagSame(converter, tag, translatedComment); +} +void JavaDocConverter::handleTagChar(JavaDocConverter* converter, DoxygenEntity& tag, std::string& translatedComment) { + // escape it if we can, else just print + if (escapeTable.find(tag.typeOfEntity)!=escapeTable.end()) + translatedComment += escapeTable[tag.typeOfEntity]; + else + translatedComment += tag.typeOfEntity; +} +void JavaDocConverter::handleTagSame(JavaDocConverter* converter, DoxygenEntity& tag, std::string& translatedComment) { + translatedComment += converter->formatCommand(std::string("@" + tag.typeOfEntity + "\t" + converter->translateSubtree(tag)), 2); +} +void JavaDocConverter::handleTagStrip(JavaDocConverter* converter, DoxygenEntity& tag, std::string& translatedComment) { + translatedComment += converter->formatCommand(converter->translateSubtree(tag), 0); +} +void JavaDocConverter::handleTagData(JavaDocConverter* converter, DoxygenEntity& tag, std::string& translatedComment) { + translatedComment += tag.data + " "; +} String *JavaDocConverter::makeDocumentation(Node *node) { @@ -158,7 +172,7 @@ String *JavaDocConverter::makeDocumentation(Node *node) { return NULL; } - std::list < DoxygenEntity > entityList = DoxygenParser().createTree(Char(documentation)); + std::list < DoxygenEntity > entityList = parser.createTree(Char(documentation)); // entityList.sort(CompareDoxygenEntities()); sorting currently not used, // see CompareDoxygenEntities::operator() in DoxygenEntity.cpp @@ -171,7 +185,7 @@ String *JavaDocConverter::makeDocumentation(Node *node) { std::string javaDocString = "/**"; for (std::list < DoxygenEntity >::iterator entityIterator = entityList.begin(); entityIterator != entityList.end();) { - javaDocString += translateEntity(*entityIterator); + translateEntity(*entityIterator, javaDocString); entityIterator++; } diff --git a/Source/DoxygenTranslator/src/JavaDocConverter.h b/Source/DoxygenTranslator/src/JavaDocConverter.h index 1d54e2514..408ec4bb2 100644 --- a/Source/DoxygenTranslator/src/JavaDocConverter.h +++ b/Source/DoxygenTranslator/src/JavaDocConverter.h @@ -15,24 +15,55 @@ #define JAVADOCCONVERTER_H_ #include "DoxygenTranslator.h" +#include /* * A class to translate doxygen comments into JavaDoc style comments. */ class JavaDocConverter : public DoxygenTranslator { public: - JavaDocConverter() : debug(false) { - } + JavaDocConverter(); String *makeDocumentation(Node *node); protected: std::string formatCommand(std::string unformattedLine, int indent); - std::string translateEntity(DoxygenEntity & doxyEntity); std::string javaDocFormat(DoxygenEntity & doxygenEntity); std::string translateSubtree(DoxygenEntity & doxygenEntity); + void translateEntity(DoxygenEntity &tag, std::string &translatedComment); + + /* + * Typedef for the function that handles one tag + */ + typedef void (*tagHandler)(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); + /* + * Here comes various tag handlers + */ + static void handleTagC(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); + static void handleTagB(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); + static void handleTagThrow(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); + static void handleTagSeeAll(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); + /* + * Print the name of tag to the output, used for escape-commands + */ + static void handleTagChar(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); + /* + * Do not translate and print as-is + */ + static void handleTagSame(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); + /* + * Print only the content and strip original tag + */ + static void handleTagStrip(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); + /* + * Print only data part of code + */ + static void handleTagData(JavaDocConverter *converter, DoxygenEntity &tag, std::string &translatedComment); private: bool debug; + std::map tagHandlers; + static std::map escapeTable; + void fillEscapeTable(); }; #endif