# HG changeset patch # User ksrini # Date 1447967656 28800 # Node ID e9fccc09cfc633138b1bcf85372c0e8c4a8052b8 # Parent 6d7a40b2a54b24acf4414be72785dc4125af922f 8130880: Create sampleapi regression test Reviewed-by: ksrini, vromero Contributed-by: sergei.pikalev@oracle.com diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/README.txt Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,59 @@ + + SampleAPI Generator for javadoc + +1. General description + + The primary goal is to provide one or more data sets to be used as input +to the javadoc tool, such that it can be used to generate representative samples +of all the different content on all the different types of pages that can be +generated by javadoc. + + The tool is implemented as generator based on xml descriptions of data sets. +The xml description of data set provides top level entities (class, interface, +enum, annotation) with all possible content. Desired output parameters (fields, +methods, inner/nested classes) are also described in xml as lists of modifiers, +types and annotations. The generator "multiply" the entities from the lists +providing the set of all possible combinations. + + After the api generation the tool connects the javadoc style comments to +the generated entities with full possible sets of supported tags. + +2. Tool structure + + Sources: + test/tools/javadoc/sampleapi/lib - generator sources + test/tools/javadoc/sampleapi/res/xml - sample data sets in xml + test/tools/javadoc/sampleapi/res/txt - sample texts for doc comments + +3. Public API + +3.1 Command line runner + + * test/tools/javadoc/sampleapi/lib/sampleapi/SampleApiDefaultRunner.java + + class sampleapi.SampleApiDefaultRunner + + Options: [-?|-h|--help] [-o:|--outdir:] + -?|-h|--help - print help + -o:|--outdir: - set to generate output + +3.2 Programmatic access + + * test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java + + class sampleapi.SampleApi + + public void generate(File dir) + public void generate(Path dir) + public void generate(String dir) + +3.3 How to run other xml data set description + + Put data set xml description into res/xml directory + + * test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java + + class sampleapi.generator.PackageGenerator + + public void processDataSet(String dsName) + public void generate(File outDir) diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/SampleApiTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/SampleApiTest.java Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8130880 + * @library lib + * @run main sampleapi.SampleApiDefaultRunner -o:out/src + * @run main SampleApiTest + */ + +import com.sun.tools.javadoc.*; +import java.nio.file.Paths; + +public class SampleApiTest { + + public static void main(String... args) { + + // html4 + Main.execute( + new String[] { + "-d", "out/doc.html4", + "-verbose", + "-private", + "-use", + "-splitindex", + "-linksource", + "-html4", + "-javafx", + "-windowtitle", "SampleAPI", + "-sourcepath", "out/src", + "sampleapi.simple", + "sampleapi.tiny", + "sampleapi.fx" + }); + + // html5 + Main.execute( + new String[] { + "-d", "out/doc.html5", + "-verbose", + "-private", + "-use", + "-splitindex", + "-linksource", + "-html5", + "-javafx", + "-windowtitle", "SampleAPI", + "-sourcepath", "out/src", + "sampleapi.simple", + "sampleapi.tiny", + "sampleapi.fx" + }); + } +} diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sampleapi; + +import java.io.File; +import java.nio.file.Path; + +import sampleapi.generator.PackageGenerator; + +public class SampleApi { + + PackageGenerator pkgGen = new PackageGenerator(); + + public void generate(File dir) throws Fault { + pkgGen.processDataSet("simple"); + pkgGen.generate(dir); + pkgGen.processDataSet("tiny"); + pkgGen.generate(dir); + pkgGen.processDataSet("fx"); + pkgGen.generate(dir); + } + + public void generate(Path dir) throws Fault { + generate(dir.toFile()); + } + + public void generate(String dir) throws Fault { + generate(new File(dir)); + } + + public static class Fault extends Exception { + public Fault(String msg) { + super(msg); + } + } +} diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApiDefaultRunner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApiDefaultRunner.java Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sampleapi; + +import java.io.File; + +import sampleapi.SampleApi.Fault; + +public class SampleApiDefaultRunner { + + public static final String MSG_DUP_OUTDIR = + "SampleApi: duplicated outdir detected: "; + public static final String MSG_USE_FIRST = + " will use first occurance: "; + public static final String MSG_INVAL_OUTDIR = + "SampleApi: outdir is not valid: "; + public static final String MSG_CANNOT_GEN = + "SampleApi: cannot generate output: "; + public static final String MSG_WRONG_OPTION = + "SampleApi: incorrect option: "; + public static final String MSG_USE_HELP = + " use -? for help"; + + public static void main(String... args) throws Exception { + if (args.length == 0) { + printHelp(); + System.exit(1); + } + + String outDirName = ""; + + boolean isOutDirSet = false; + boolean isHelpPrinted = false; + for (String arg : args) { + Option option = new Option(arg); + switch (option.getOptionName()) { + case "-?": + case "-h": + case "--help": + if (!isHelpPrinted) { + printHelp(); + isHelpPrinted = true; + } + break; + case "-o": + case "--outdir": + if (!isOutDirSet) { + outDirName = option.getOptionValue(); + isOutDirSet = true; + } else { + System.err.println(MSG_DUP_OUTDIR + option.getOptionValue()); + System.err.println(MSG_USE_FIRST + outDirName); + } + break; + default: + System.err.println(MSG_WRONG_OPTION + arg); + System.err.println(MSG_USE_HELP); + break; + } + + } + + if (!isOutDirSet) { + System.exit(1); + } + + if (outDirName.length() == 0) { + System.err.println(MSG_INVAL_OUTDIR + outDirName); + System.exit(1); + } + + File outDir = new File(outDirName); + outDir.mkdirs(); + SampleApi apiGen = new SampleApi(); + + try { + apiGen.generate(outDir); + } catch (Fault e) { + System.err.println(MSG_CANNOT_GEN + e.getMessage()); + e.printStackTrace(); + } + } + + private static void printHelp() { + System.out.println("SampleApi:"); + System.out.println(" options: [-?|-h|--help] [-o:|--outdir:]"); + System.out.println(" -?|-h|--help - print help"); + System.out.println(" -o:|--outdir: - set to generate output"); + } + + private static class Option { + + private String optionName; + private String optionValue; + + public Option(String arg) { + int delimPos = arg.indexOf(':'); + + if (delimPos == -1) { + optionName = arg; + optionValue = ""; + } else { + optionName = arg.substring(0, delimPos); + optionValue = arg.substring(delimPos + 1, arg.length()); + } + } + + public String getOptionName() { + return optionName; + } + + public String getOptionValue() { + return optionValue; + } + } +} diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sampleapi.generator; + +import java.io.File; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.util.Set; +import javax.lang.model.element.Modifier; + +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.util.List; + +class DocCommentGenerator { + + public enum Text { + BROWNFOX(BROWNFOX_TEXT), + NOWISTHETIME(NOWISTHETIME_TEXT), + THISPANGRAM(THISPANGRAM_TEXT), + LOREMIPSUM(LOREMIPSUM_TEXT), + LIEUROPANLINGUES(LIEUROPANLINGUES_TEXT), + CODE(CODE_TEXT); + + String commentText; + + Text(String text) { + commentText = text; + } + + @Override + public String toString() { + return commentText; + } + } + + public enum Tag { + AUTHOR("@author", "Cody J. Writer"), + PARAM("@param", ""), + RETURN("@return", Text.NOWISTHETIME.toString()), + SINCE("@since", "1.0"), + THROWS("@throws", "If problem detected"), + EXCEPTION("@exception", "If problem detected"), + SERIAL("@serial", ""), + SERIALDATA("@serialData", "The types and order of data could be here."), + SERIALFIELD("@serialField", "\n Serial field in special array"), + FX_PROPSETTER("@propertySetter", "Set the property"), + FX_PROPGETTER("@propertyGetter", "Get the property"), + FX_PROPDESC("@propertyDescription", ""), + FX_DEFVALUE("@defaultValue", ""), + FX_TREATASPRIVATE("@treatAsPrivate", ""); + + String tagName; + String tagValue; + + Tag(String tagName, String tagValue) { + this.tagName = tagName; + this.tagValue = tagValue; + } + + public String toString() { + return value("", ""); + } + + public String value(String value) { + return value(value, ""); + } + + public String value(String value, String extra) { + return tagName + + ((value.length() != 0) ? " " + value : "") + + ((tagValue.length() != 0) ? " " + tagValue : "") + + ((extra.length() != 0) ? " " + extra : ""); + } + } + + public enum InlineTag { + LITERAL("@literal", "Use < and > brackets instead of < and > escapes."), + CODE("@code", "(i) -> new Abc((i > 0) ? (i << 1) : 0)"), + LINK("@link", ""), + VALUE("@value", ""); + + String tagName; + String tagValue; + + InlineTag(String tagName, String tagValue) { + this.tagName = tagName; + this.tagValue = tagValue; + } + + public String toString() { + return value(""); + } + + public String value(String value) { + return "{" + tagName + + ((tagValue.length() != 0) ? " " + tagValue : "") + + ((value.length() != 0) ? " " + value : "") + + "}"; + } + } + + public static class LinkTag { + + static String[] links = new String[] { + "Boolean", + "Boolean#TRUE", + "Boolean#Boolean(boolean)", + "Boolean#Boolean(String s)", + "Boolean#compare(boolean, boolean)", + "Boolean#compareTo(Boolean b)", + "java.util.Vector", + "java.util.Vector#elementCount", + "java.util.Vector#Vector(int)", + "java.util.Vector#Vector(int initialCapacity, int capacityIncrement)", + "java.util.Vector#indexOf(Object)", + "java.util.Vector#indexOf(Object o, int index)", + "java.lang.annotation" }; + + static int index = 0; + + public static String nextSee() { + String next = "@see " + links[index]; + index = (index + 1) % links.length; + return next; + } + + public static String nextLink() { + String next = "Also check " + + (((index % 2) == 0) ? "{@link " : "{@linkplain ") + + links[index] + + "} for details.\n"; + index = (index + 1) % links.length; + return next; + } + } + + public static class VersionTag { + + static String[] versions = new String[] { + "1.5, 09/01/04", + "1.6, 12/11/06", + "1.7, 07/28/11", + "1.8, 04/19/14", + "1.9, 06/03/16" }; + + static int index = 0; + + public static String nextVersion() { + String next = "@version " + versions[index]; + index = (index + 1) % versions.length; + return next; + } + } + + // + // getters (build comments for entities) + // + + public String getPackageComment() { + return Text.LOREMIPSUM + + "\n

" + Text.LIEUROPANLINGUES + + "\n" + Text.CODE + + "\n" + LinkTag.nextLink() + + "\n" + LinkTag.nextSee() + + "\n" + Tag.SINCE; + } + + String[] serialVals = new String[] { "include", "exclude" }; + // static index to roll over "include/exclude" + static int serialValIdx = 0; + + public String getBaseComment(JCClassDecl baseDecl, boolean toplevel) { + String buildComment = Text.LIEUROPANLINGUES + "\n"; + + buildComment += "

It is possible to see inlined code:\n" + + InlineTag.CODE + + " is the example.\n\n"; + + buildComment += "

Literal use example.\n" + + InlineTag.LITERAL + "\n\n"; + + buildComment += "

" + Text.THISPANGRAM + "\n"; // make comment longer + + buildComment += "

" + LinkTag.nextLink() + "\n"; + + if (toplevel) + buildComment += "\n" + VersionTag.nextVersion() + "\n"; + + // @param for type params + List params = baseDecl.getTypeParameters(); + int paramIndex = 0; + for (JCTypeParameter paramDecl : params) { + buildComment += Tag.PARAM.value( + "<" + paramDecl.getName().toString() + ">", + "the type of value set #" + paramIndex++) + + "\n"; + } + + buildComment += "\n" + LinkTag.nextSee(); + + buildComment += "\n"; + + if (toplevel) + buildComment += Tag.AUTHOR + "\n"; + + buildComment += Tag.SINCE + "\n"; + + // for serial; currently no need to dig too deep + if (isSerializable(baseDecl) || isErrorOrException(baseDecl)) { + buildComment += "\n" + Tag.SERIAL.value(serialVals[serialValIdx]); + serialValIdx = (serialValIdx + 1) % 2; + } + + return buildComment; + } + + public String getConstComment() { + String buildComment = Text.NOWISTHETIME + " " + Text.BROWNFOX + "\n"; + + buildComment += LinkTag.nextLink() + "\n"; + buildComment += LinkTag.nextSee() + "\n"; + buildComment += Tag.SINCE + "\n"; + + return buildComment; + } + + public String getFieldComment(JCClassDecl baseDecl, + JCVariableDecl varDecl, + boolean isFxStyle) { + String buildComment = Text.BROWNFOX + "

" + Text.NOWISTHETIME + "\n"; + + Set mods = varDecl.getModifiers().getFlags(); + String varName = varDecl.getName().toString(); + + if (mods.contains(Modifier.STATIC) && mods.contains(Modifier.FINAL)) { + JCExpression init = varDecl.getInitializer(); + if (init != null + && !"null".equals(init.toString()) + && !"serialPersistentFields".equals(varName)) + buildComment += "

The value of this constant is " + + InlineTag.VALUE + + ".\n"; + } + + buildComment += "

" + LinkTag.nextLink() + "\n"; + + if (isSerializable(baseDecl)) { + if (isErrorOrException(baseDecl)) { + buildComment += Tag.SERIAL + "\n"; + } else if ("serialPersistentFields".equals(varName)) { + JCNewArray sfList = (JCNewArray)varDecl.getInitializer(); + for (JCExpression sf : sfList.getInitializers()) { + List args = ((JCNewClass)sf).getArguments(); + String sfName = ((JCLiteral)args.get(0)).getValue().toString(); + String sfClass = ((JCIdent)args.get(1)).getName().toString(); + String sfType = sfClass.substring(0, sfClass.indexOf(".class")); + + buildComment += Tag.SERIALFIELD.value(sfName + " " + sfType) + + "\n"; + } + } else { + buildComment += Tag.SERIAL.value("Very important value.") + "\n"; + } + } + + if (isFxStyle) { + // set default value + String varType = varDecl.getType().toString(); + buildComment += Tag.FX_DEFVALUE.value(defValue(varType)) + "\n"; + } + + buildComment += LinkTag.nextSee() + "\n"; + + return buildComment; + } + + public String getMethodComment(JCClassDecl baseDecl, + JCMethodDecl methodDecl, + boolean isFxStyle) { + String buildComment = Text.BROWNFOX + "\n

" + Text.THISPANGRAM + "\n"; + + buildComment += "

" + LinkTag.nextLink() + "\n"; + + buildComment += "

Literal use example.\n" + + InlineTag.LITERAL + "\n\n"; + + // @param for type params + List tparams = methodDecl.getTypeParameters(); + int tparamIndex = 0; + for (JCTypeParameter paramDecl : tparams) { + String paramDeclString = paramDecl.getName().toString(); + // simplify it (could contain 'extend'/'super' clauses + int spacePos = paramDeclString.indexOf(' '); + if (spacePos != -1) + paramDeclString = paramDeclString.substring(0, spacePos); + buildComment += Tag.PARAM.value( + "<" + paramDeclString + ">", + "the type of value set #" + tparamIndex++) + + "\n"; + } + + // @param + List params = methodDecl.getParameters(); + int paramIndex = 0; + for (JCVariableDecl paramDecl : params) { + buildComment += Tag.PARAM.value( + paramDecl.getName().toString(), + "an income parameter #" + paramIndex++) + + "\n"; + } + + // @return + JCTree retType = methodDecl.getReturnType(); // null for constructors + if (retType != null && !"void".equals(retType.toString())) + buildComment += Tag.RETURN + "\n"; + + // @throws/@exception + Tag t = isDerived(baseDecl) ? Tag.EXCEPTION : Tag.THROWS; + List throwTypes = methodDecl.getThrows(); + for (JCExpression throwsExp : throwTypes) { + buildComment += t.value(throwsExp.toString()) + "\n"; + } + + if (isSerializable(baseDecl)) { + switch (methodDecl.getName().toString()) { + case "writeObject": + case "readObject": + case "writeExternal": + case "readExternal": + case "writeReplace": + case "readResolve": + buildComment += Tag.SERIALDATA + "\n"; + break; + default: + } + } + + if (isFxStyle) { + // @propertySetter/Getter + Description + if ("void".equals(retType.toString())) { + buildComment += Tag.FX_PROPSETTER + "\n"; + } else { + buildComment += Tag.FX_PROPGETTER + "\n"; + buildComment += Tag.FX_DEFVALUE.value(defValue(retType.toString())) + + "\n"; + } + buildComment += Tag.FX_PROPDESC.value(Text.BROWNFOX.toString()) + "\n"; + + // @treatAsPrivate + if (methodDecl.getModifiers().getFlags().contains(Modifier.PUBLIC)) + buildComment += Tag.FX_TREATASPRIVATE + "\n"; + } + + // @see + buildComment += LinkTag.nextSee() + "\n"; + + // @since + buildComment += Tag.SINCE + "\n"; + + return buildComment; + } + + // + // util methods + // + + private boolean isErrorOrException(JCClassDecl baseDecl) { + JCExpression ext = baseDecl.getExtendsClause(); + if (ext != null) { + String extClassName = ext.toString(); + if (extClassName.contains("Error") || extClassName.contains("Exception")) + return true; + } + return false; + } + + private boolean isSerializable(JCClassDecl baseDecl) { + List impls = baseDecl.getImplementsClause(); + for (JCExpression impl : impls) { + if (impl.toString().contains("Serializable")) + return true; + } + return false; + } + + private boolean isDerived(JCClassDecl baseDecl) { + return (baseDecl.getExtendsClause() == null) ? false : true; + } + + private String defValue(String type) { + switch (type) { + case "boolean": + return "true"; + case "byte": case "char": case "int": case "long": + case "Integer": case "Long": + return "1"; + case "float": case "double": case "Float": case "Double": + return "1.0"; + case "String": + return "string"; + default: + return "null"; + } + } + + private static final String BROWNFOX_TEXT = + "The quick brown fox jumps over the lazy dog.\n"; + private static final String NOWISTHETIME_TEXT = + "Now is the time for all good men to come to the aid of the party.\n"; + private static final String THISPANGRAM_TEXT = + "This pangram contains four a's, one b, two c's, one d, thirty e's,\n" + + "six f's, five g's, seven h's, eleven i's, one j, one k, two l's,\n" + + "two m's, eighteen n's, fifteen o's, two p's, one q, five r's,\n" + + "twenty-seven s's, eighteen t's, two u's, seven v's, eight w's,\n" + + "two x's, three y's, & one z."; + private static final String LOREMIPSUM_TEXT = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n" + + "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut\n" + + "enim ad minim veniam, quis nostrud exercitation ullamco laboris\n" + + "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor\n" + + "in reprehenderit in voluptate velit esse cillum dolore eu fugiat\n" + + "nulla pariatur. Excepteur sint occaecat cupidatat non proident,\n" + + "sunt in culpa qui officia deserunt mollit anim id est laborum.\n"; + private static final String LIEUROPANLINGUES_TEXT = + "Li Europan lingues es membres del sam familie. Lor separat existentie\n" + + "es un myth. Por scientie, musica, sport etc, litot Europa usa li sam\n" + + "vocabular. Li lingues differe solmen in li grammatica, li pronunciation\n" + + "e li plu commun vocabules. Omnicos directe al desirabilite de un nov\n" + + "lingua franca: On refusa continuar payar custosi traductores.\n" + + "\n" + + "

At solmen va esser necessi far uniform grammatica, pronunciation\n" + + "e plu commun paroles. Ma quande lingues coalesce, li grammatica del\n" + + "resultant lingue es plu simplic e regulari quam ti del coalescent\n" + + "lingues. Li nov lingua franca va esser plu simplic e regulari quam\n" + + "li existent Europan lingues. It va esser tam simplic quam Occidental\n" + + "in fact, it va esser Occidental. A un Angleso it va semblar un simplificat\n" + + "Angles, quam un skeptic Cambridge amico dit me que Occidental es.\n"; + private static final String CODE_TEXT = + "

\n" +
+        "public void checkLanguage(Language lang) throws Exception {\n" +
+        "    if (lang.getName().equals(\"Java\")) {\n" +
+        "        System.out.println(\"Warning! Hot!\");\n" +
+        "    else {\n" +
+        "        throw new LooserException();\n" +
+        "    }\n" +
+        "}\n" +
+        "
\n"; +} diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/Documentifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/Documentifier.java Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sampleapi.generator; + +import java.util.ArrayList; +import java.util.Set; +import javax.lang.model.element.Modifier; + +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.DocCommentTable; +import com.sun.tools.javac.parser.ScannerFactory; +import com.sun.tools.javac.parser.Scanner; +import com.sun.tools.javac.parser.Tokens.Token; +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; +import com.sun.source.tree.Tree.Kind; + +import sampleapi.util.*; + +class Documentifier { + + static Documentifier instance; + + final DocCommentGenerator docGen; + final ScannerFactory scanners; + + private Documentifier(Context context) { + docGen = new DocCommentGenerator(); + scanners = ScannerFactory.instance(context); + } + + public static Documentifier instance(Context context) { + if (instance == null) + instance = new Documentifier(context); + return instance; + } + + private DocCommentTable curDocComments; + + public void documentify(JCCompilationUnit topLevel, boolean isFxStyle) { + JCClassDecl base = (JCClassDecl)topLevel.getTypeDecls().get(0); + curDocComments = new PoorDocCommentTable(); + documentifyBase(base, true, isFxStyle); + topLevel.docComments = curDocComments; + } + + private void documentifyBase(JCClassDecl base, boolean isTopLevel, boolean isFxStyle) { + // add doc comment to class itself + Comment comm = comment(docGen.getBaseComment(base, isTopLevel)); + curDocComments.putComment(base, comm); + + // add doc comments to members + for (JCTree member : base.getMembers()) { + switch (member.getTag()) { + case VARDEF: + documentifyField(base, (JCVariableDecl)member, isFxStyle); + break; + case METHODDEF: + documentifyMethod(base, (JCMethodDecl)member, isFxStyle); + break; + case CLASSDEF: + documentifyBase((JCClassDecl)member, false, isFxStyle); + break; + } + } + } + + private void documentifyField(JCClassDecl base, JCVariableDecl field, boolean isFxStyle) { + Kind baseKind = base.getKind(); + Set fieldMods = field.getModifiers().getFlags(); + String doc = (baseKind == Kind.ENUM + && fieldMods.contains(Modifier.PUBLIC) + && fieldMods.contains(Modifier.STATIC) + && fieldMods.contains(Modifier.FINAL)) ? + docGen.getConstComment() : + docGen.getFieldComment(base, field, isFxStyle); + Comment comm = comment(doc); + curDocComments.putComment(field, comm); + } + + private void documentifyMethod(JCClassDecl base, JCMethodDecl method, boolean isFxStyle) { + Comment comm = comment(docGen.getMethodComment(base, method, isFxStyle)); + curDocComments.putComment(method, comm); + } + + private Comment comment(String docString) { + StringBuilder docComment = new StringBuilder() + .append("/**") + .append(docString) + .append("*/"); + Scanner scanner = scanners.newScanner(docComment, true); + scanner.nextToken(); + Token token = scanner.token(); + return token.comment(CommentStyle.JAVADOC); + } + + // provide package comment data ONLY + public DocCommentGenerator getDocGenerator() { + return docGen; + } +} diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,832 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sampleapi.generator; + +import java.io.File; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Hashtable; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; +import org.xml.sax.SAXException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.TypeTag; +import com.sun.tools.javac.code.TypeMetadata; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symtab; + +import sampleapi.util.*; +import sampleapi.SampleApi.Fault; + +public class PackageGenerator { + + String packageName; + String packageDirName; + + ArrayList topLevels; + Hashtable nameIndex; + Hashtable idBases; + Hashtable idAnnos; + + TreeMaker make; + Names names; + Symtab syms; + DocumentBuilderFactory factory; + Documentifier documentifier; + boolean fx = false; + + public PackageGenerator() { + JavacTool jt = JavacTool.create(); + JavacTask task = jt.getTask(null, null, null, null, null, null); + Context ctx = ((JavacTaskImpl)task).getContext(); + + make = TreeMaker.instance(ctx); + names = Names.instance(ctx); + syms = Symtab.instance(ctx); + factory = DocumentBuilderFactory.newInstance(); + + documentifier = Documentifier.instance(ctx); + } + + String dataSetName; + + public void processDataSet(String dsName) throws Fault { + dataSetName = dsName; + topLevels = new ArrayList<>(); + nameIndex = new Hashtable<>(); + idBases = new Hashtable<>(); + idAnnos = new Hashtable<>(); + + String dsPath = "res/xml/" + dsName + ".xml"; + + try { + InputStream is = getClass().getResourceAsStream("/" + dsPath); + if (is == null) + is = new FileInputStream(dsPath); + + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(is); + + Element rootElement = document.getDocumentElement(); + packageName = rootElement.getAttribute("package"); + fx = "fx".equals(rootElement.getAttribute("style")); + packageDirName = packageName.replace('.', '/'); + + // process nodes (toplevels) + NodeList nodeList = rootElement.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + + if (!(node instanceof Element)) + continue; + processTopLevel((Element)node); + } + } catch (ParserConfigurationException | SAXException | IOException e) { + throw new Fault("Error parsing dataset " + dsName); + } + + fx = false; + } + + public void generate(File outDir) throws Fault { + if (dataSetName == null) + throw new Fault("No Data Set processed"); + + try { + File pkgDir = new File(outDir, packageDirName); + pkgDir.mkdirs(); + + for (JCCompilationUnit decl : topLevels) { + JCClassDecl classDecl = (JCClassDecl)decl.getTypeDecls().get(0); + File outFile = new File(pkgDir, + classDecl.getSimpleName().toString() + ".java"); + FileWriter writer = new FileWriter(outFile); + writer.write(decl.toString()); + writer.flush(); + writer.close(); + } + + // package-info + File outFile = new File(pkgDir, "package-info.java"); + FileWriter writer = new FileWriter(outFile); + writer.write("/**\n"); + writer.write(documentifier.getDocGenerator().getPackageComment()); + writer.write("*/\n"); + writer.write("package " + packageName + ";"); + writer.flush(); + writer.close(); + } catch (IOException e) { + throw new Fault("Error writing output"); + } + } + + // levels' processing methods + + void processTopLevel(Element tlTag) { + String kind = tlTag.getTagName(); + + if (kind.equals("annodecl")) { + // decls stored separately, does not affect bases + String declId = tlTag.getAttribute("id"); + if (!declId.startsWith("@")) + declId = "@" + declId; + idAnnos.put(declId, processAnnoDecl(tlTag)); + return; + } + + ListBuffer[] bases = processBases(tlTag, null); + + for (JCTree base : bases[0]) { // [0] - bases namely + JCPackageDecl pkg = make.PackageDecl( + List.nil(), + make.QualIdent( + new Symbol.PackageSymbol( + names.fromString(packageName), + null))); + ListBuffer topLevelParts = new ListBuffer<>(); + topLevelParts.append(pkg); + topLevelParts.appendList(bases[1]); // [1] imports + topLevelParts.append(base); + + JCCompilationUnit topLevel = make.TopLevel(topLevelParts.toList()); + documentifier.documentify(topLevel, fx); + topLevels.add(topLevel); + } + } + + ListBuffer[] processBases(Element baseTag, Hashtable scope) { + String kind = baseTag.getTagName(); + String baseName = baseTag.getAttribute("basename"); + String typeParam = baseTag.getAttribute("tparam"); + String baseId = baseTag.getAttribute("id"); + + long kindFlag = 0; + switch (kind) { + case "class": + // no flags for class + break; + case "interface": + kindFlag |= Flags.INTERFACE; + break; + case "enum": + kindFlag |= Flags.ENUM; + break; + case "annotation": + kindFlag |= Flags.ANNOTATION | Flags.INTERFACE; + break; + } + + // go through other nodes; add modifiers to multiplier + NodeList nodes = baseTag.getChildNodes(); + ListBuffer bases = new ListBuffer<>(); + ListBuffer members = new ListBuffer<>(); + ListBuffer imports = new ListBuffer<>(); + JCExpression extType = null; + ListBuffer implTypes = new ListBuffer<>(); + SimpleMultiplier multiply = new SimpleMultiplier(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if (!(node instanceof Element)) + continue; + + switch (((Element)node).getTagName()) { + case "modifier": + multiply.addAxis(((Element)node).getTextContent()); + break; + case "anno": + multiply.addAxis(((Element)node).getTextContent()); + break; + case "member": + // process members here + members.appendList(processMembers((Element)node, baseName, kind)); + break; + case "extend": + String classId = ((Element)node).getAttribute("id"); // this pkg + String classRef = ((Element)node).getAttribute("ref"); // external + if (classId.length() !=0 && + idBases.containsKey(classId)) { + // if have base, take methods from base members + JCClassDecl baseDecl = idBases.get(classId); + extType = make.Type( + getTypeByName( + baseDecl.getSimpleName().toString())); + members.appendList(processMethods(baseDecl.getMembers(), false)); + } else if (classRef.length() !=0) { + extType = make.Type(getTypeByName(classRef)); + } + break; + case "implement": + String interfaceId = ((Element)node).getAttribute("id"); + String interfaceRef = ((Element)node).getAttribute("ref"); + if (interfaceId.length() != 0 && + idBases.containsKey(interfaceId)) { + JCClassDecl baseDecl = idBases.get(interfaceId); + implTypes.add( + make.Type( + getTypeByName( + baseDecl.getSimpleName().toString()))); + members.appendList(processMethods(baseDecl.getMembers(), true)); + } else if (interfaceRef.length() != 0) { + implTypes.add(make.Type(getTypeByName(interfaceRef))); + } + break; + case "import": + imports.append( + make.Import( + make.Ident(names.fromString(((Element)node).getTextContent())), + false)); + } + } + + // process modifiers through multiplier + multiply.initIterator(); + while (multiply.hasNext()) { + ArrayList tuple = multiply.getNext(); + + long declFlags = kindFlag; + ListBuffer annos = new ListBuffer<>(); + for (String modifier : tuple) { + if (modifier.startsWith("@") && idAnnos.containsKey(modifier)) + annos.add(idAnnos.get(modifier)); // it's anno + else + declFlags |= getFlagByName(modifier); // it's modifier + } + + String declName = (scope == null) + ? getUniqName(baseName) + : baseName + getUniqIndex(scope, baseName); + JCClassDecl baseDecl = make.ClassDef( + make.Modifiers(declFlags, annos.toList()), + names.fromString(declName), + processTypeParams(typeParam), // type params + extType, // ext + implTypes.toList(), // impl + members.toList()); // members + + // fix constructors names + fixConstructorNames(baseDecl); + + bases.append(baseDecl); + + // for non-empty ids store first base occurence from multiplied sequence + if (baseId.length() != 0) { + idBases.put(baseId, baseDecl); + baseId = ""; + } + } + + return new ListBuffer[] { bases, imports }; + } + + List processTypeParams(String typeParams) { + + if (typeParams == null || typeParams.length() == 0) + return List.nil(); // empty + + String[] typeVarsArr = typeParams.split(","); + ListBuffer typeParamsDecls = new ListBuffer<>(); + + for (String typeVar : typeVarsArr) { + typeParamsDecls.add( + make.TypeParameter(names.fromString(typeVar), + List.nil())); + } + + return typeParamsDecls.toList(); + } + + ListBuffer processMembers(Element memberTag, String name, String kind) { + ListBuffer members = new ListBuffer<>(); + NodeList nodes = memberTag.getChildNodes(); + Hashtable scope = new Hashtable<>(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if (!(node instanceof Element)) + continue; + + switch (((Element)node).getTagName()) { + case "field": + members.appendList(processFields((Element)node, scope)); + break; + case "serialfield": + members.append(processSerialFields((Element)node)); + break; + case "constant": + members.appendList(processConstants((Element)node, scope)); + break; + case "constructor": + members.appendList(processMethods((Element)node, scope, true, true)); + break; + case "method": + boolean needBody = kind.equals("class") || kind.equals("enum"); + members.appendList(processMethods((Element)node, scope, needBody, false)); + break; + case "class": + case "interface": + case "enum": + case "annotation": + members.appendList(processBases((Element)node, scope)[0]); + break; + } + } + + return members; + } + + ListBuffer processFields(Element fieldsNode, Hashtable scope) { + String kind = fieldsNode.getTagName(); + String baseName = fieldsNode.getAttribute("basename"); + + ListBuffer fields = new ListBuffer<>(); + NodeList nodes = fieldsNode.getChildNodes(); + SimpleMultiplier multiply = new SimpleMultiplier(); // for modifiers + String[] types = new String[] {}; + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if (!(node instanceof Element)) + continue; + + // parse type and modifiers + switch (((Element)node).getTagName()) { + case "modifier": + multiply.addAxis(((Element)node).getTextContent()); + break; + case "anno": + multiply.addAxis(((Element)node).getTextContent()); + case "type": + types = ((Element)node).getTextContent().split("\\|"); + break; + } + } + + // process through modifiers and types + multiply.initIterator(); + while (multiply.hasNext()) { + ArrayList tuple = multiply.getNext(); + + long declFlags = 0; + ListBuffer annos = new ListBuffer<>(); + for (String modifier : tuple) { + if (modifier.startsWith("@") && idAnnos.containsKey(modifier)) + annos.add(idAnnos.get(modifier)); // it's anno + else + declFlags |= getFlagByName(modifier); // it's modifier + } + + + for (String type : types) { + String declName = baseName + getUniqIndex(scope, baseName); + + Type initType = getTypeByName(type); + JCExpression initExpr = null; + if ((declFlags & Flags.STATIC) != 0) // static to be initialized + initExpr = make.Literal(initType.isPrimitive() ? + initType.getTag() : + TypeTag.BOT, + "String".equals(type) + ? new String("blah-blah-blah") + : new Integer(0)); + + JCVariableDecl fieldDecl = make.VarDef( + make.Modifiers(declFlags, annos.toList()), + names.fromString(declName), + make.Type(getTypeByName(type)), + initExpr); + + fields.append(fieldDecl); + } + } + + return fields; + } + + JCTree processSerialFields(Element sfNode) { + String baseName = sfNode.getAttribute("basename"); + String[] fieldTypes = sfNode.getTextContent().split(","); + + ListBuffer serialFields = new ListBuffer<>(); + Hashtable scope = new Hashtable<>(); + + for (String fType : fieldTypes) { + String fieldName = baseName + getUniqIndex(scope, baseName); + serialFields.add( + make.NewClass( + null, + null, + make.Type(getTypeByName("ObjectStreamField")), + List.from( + new JCTree.JCExpression[] { + make.Literal(fieldName), + make.Ident(names.fromString(fType + ".class")) + }), + null)); + } + + JCTree sfDecl = make.VarDef( + make.Modifiers( + Flags.PRIVATE | Flags.STATIC | Flags.FINAL), + names.fromString("serialPersistentFields"), + make.TypeArray( + make.Type(getTypeByName("ObjectStreamField"))), + make.NewArray( + null, + List.nil(), + serialFields.toList())); + + return sfDecl; + } + + ListBuffer processConstants(Element constNode, Hashtable scope) { + String baseName = constNode.getAttribute("basename"); + int count = 1; + try { + count = Integer.parseInt(constNode.getAttribute("count")); + } catch (Exception e) {} // nothing to do, will use count = 1 + + long declFlags = Flags.PUBLIC | Flags.STATIC | Flags.FINAL | Flags.ENUM; + ListBuffer fields = new ListBuffer<>(); + + for (int i = 0; i < count; i++) { + String declName = baseName + + ((count == 1) ? "" : getUniqIndex(scope, baseName)); + + JCVariableDecl constDecl = make.VarDef( + make.Modifiers(declFlags), + names.fromString(declName), + null, // no need for type in enum decl + null); // no init + + fields.append(constDecl); + } + return fields; + } + + ListBuffer processMethods(Element methodsNode, Hashtable scope, boolean needBody, boolean isConstructor) { + String kind = methodsNode.getTagName(); + String baseName = methodsNode.getAttribute("basename"); + String name = methodsNode.getAttribute("name"); + String methodTypeParam = methodsNode.getAttribute("tparam"); + + ListBuffer methods = new ListBuffer<>(); + NodeList nodes = methodsNode.getChildNodes(); + SimpleMultiplier multiply = new SimpleMultiplier(); // for modifiers + String[] types = new String[0]; + String[] params = new String[] { "none" }; // default - no params + ListBuffer throwTypes = new ListBuffer<>(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if (!(node instanceof Element)) + continue; + + // parse type and modifiers + switch (((Element)node).getTagName()) { + case "modifier": + multiply.addAxis(((Element)node).getTextContent()); + break; + case "anno": + multiply.addAxis(((Element)node).getTextContent()); + break; + case "type": + types = ((Element)node).getTextContent().split("\\|"); + break; + case "param": + params = ((Element)node).getTextContent().split("\\|"); + break; + case "throw": + throwTypes.add( + getTypeByName(((Element)node).getTextContent())); + break; + + } + } + + // constructor? + if (isConstructor) { + baseName = "constructor"; + types = new String[] { "" }; + } + + // direct name not indexed + boolean isDirectName = false; + if (name.length() > 0) { + baseName = name; + isDirectName = true; + } + + // process through modifiers and types + multiply.initIterator(); + while (multiply.hasNext()) { + ArrayList tuple = multiply.getNext(); + + long declFlags = 0; + ListBuffer annos = new ListBuffer<>(); + for (String modifier : tuple) { + if (modifier.startsWith("@") && idAnnos.containsKey(modifier)) + annos.add(idAnnos.get(modifier)); // it's anno + else + declFlags |= getFlagByName(modifier); // it's modifier + } + + for (String type : types) { + String declName = baseName + + ((isConstructor || isDirectName) + ? "" : getUniqIndex(scope, baseName)); + + JCBlock body = null; + if (needBody && (declFlags & Flags.ABSTRACT) == 0) { // create body + List bodyStatements = List.nil(); + if (!type.equals("") && !type.equals("void")) { // create return statement + Type retType = getTypeByName(type); + bodyStatements = List.of( + make.Return( + make.Literal( + retType.isPrimitive() ? + retType.getTag() : + TypeTag.BOT, + new Integer(0)))); + } + body = make.Block(0, bodyStatements); + } + + // same method by different params (if they exist) + for (String param : params) { + + JCMethodDecl methodDecl = + make.MethodDef( + make.Modifiers(declFlags, annos.toList()), + names.fromString(declName), + isConstructor ? null : make.Type(getTypeByName(type)), + processTypeParams(methodTypeParam), // type params + null, // no receiver + processParams(param), // formal params + make.Types(throwTypes.toList()), // throws + body, + null); // no default value YET + + methods.append(methodDecl); + } + } + } + + return methods; + } + + JCAnnotation processAnnoDecl(Element annoDeclNode) { + String annoId = annoDeclNode.getAttribute("id"); + + ListBuffer args = new ListBuffer<>(); + String className = ""; + + NodeList nodes = annoDeclNode.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if (!(node instanceof Element)) + continue; + + switch (((Element)node).getTagName()) { + case "class": + className = ((Element)node).getTextContent(); + break; + case "arg": + String argName = ((Element)node).getAttribute("name"); + String argValue = ((Element)node).getAttribute("value"); + + JCExpression arg; + if (argName.length() == 0) + arg = make.Ident(names.fromString(argValue)); + else + arg = make.Assign( + make.Ident(names.fromString(argName)), + make.Ident(names.fromString(argValue))); + + args.add(arg); + break; + } + } + + return make.Annotation( + make.Ident(names.fromString(className)), + args.toList()); + } + + ListBuffer processMethods(List tree, boolean needBody) { + // for "extends" clause; returns methods only + ListBuffer methods = new ListBuffer<>(); + for (JCTree memberDecl : tree) { + if (memberDecl instanceof JCMethodDecl) { + JCMethodDecl methodDecl = (JCMethodDecl)memberDecl; + JCTree retTypeTree = methodDecl.getReturnType(); + + // skip constructors + if (retTypeTree == null) + continue; + + if (needBody) { + // here we need to 'implement' interface declared methods + Type retType = retTypeTree.type; + + List bodyStatements = List.nil(); + if (retType.getTag() != TypeTag.VOID) + bodyStatements = List.of( + make.Return( + make.Literal( + retType.isPrimitive() ? + retType.getTag() : + TypeTag.BOT, + new Integer(0)))); + + JCBlock body = make.Block(0, bodyStatements); + + methodDecl = make.MethodDef( + methodDecl.getModifiers(), + methodDecl.getName(), + (JCExpression)methodDecl.getReturnType(), + methodDecl.getTypeParameters(), + methodDecl.getReceiverParameter(), + methodDecl.getParameters(), + methodDecl.getThrows(), + body, + (JCExpression)methodDecl.getDefaultValue()); + } + + methods.add(methodDecl); + } + } + return methods; + } + + void fixConstructorNames(JCClassDecl baseDecl) { + ListBuffer newMembers = new ListBuffer<>(); + List members = baseDecl.getMembers(); + Name name = baseDecl.getSimpleName(); + + for (JCTree memberDecl : members) { + JCTree newDecl = memberDecl; + + if (memberDecl instanceof JCMethodDecl) { + JCMethodDecl methodDecl = (JCMethodDecl)memberDecl; + JCTree retTypeTree = methodDecl.getReturnType(); + + if (retTypeTree == null) + newDecl = make.MethodDef( + methodDecl.getModifiers(), + name, + (JCExpression)methodDecl.getReturnType(), + methodDecl.getTypeParameters(), + methodDecl.getReceiverParameter(), + methodDecl.getParameters(), + methodDecl.getThrows(), + methodDecl.getBody(), + (JCExpression)methodDecl.getDefaultValue()); + } + + newMembers.add(newDecl); + } + + baseDecl.defs = newMembers.toList(); + } + + List processParams(String paramTypes) { + + if ("none".equals(paramTypes)) + return List.nil(); // empty + + String[] typesArr = paramTypes.split(",(?!(\\w+,)*\\w+>)"); + ListBuffer paramsDecls = new ListBuffer<>(); + + int i = 0; + for (String typeName : typesArr) { + String paramName = "param" + + (typesArr.length == 1 ? "" : String.valueOf(i)); + paramsDecls.add( + make.VarDef(make.Modifiers(0), + names.fromString(paramName), + make.Type(getTypeByName(typeName)), + null)); + i++; + } + + return paramsDecls.toList(); + } + + // + // util methods + // + + String getUniqName(String name) { + if (!nameIndex.containsKey(name)) + nameIndex.put(name, new Integer(0)); + Integer index = nameIndex.get(name); + String uniqName = name + index; + nameIndex.put(name, index + 1); + return uniqName; + } + + int getUniqIndex(Hashtable scope, String name) { + if (!scope.containsKey(name)) + scope.put(name, new Integer(0)); + Integer index = scope.get(name); + scope.put(name, index + 1); + return index; + } + + long getFlagByName(String modifierName) { + switch (modifierName) { + case "public": + return Flags.PUBLIC; + case "private": + return Flags.PRIVATE; + case "protected": + return Flags.PROTECTED; + case "static": + return Flags.STATIC; + case "final": + return Flags.FINAL; + case "abstract": + return Flags.ABSTRACT; + case "strictfp": + return Flags.STRICTFP; + default: + return 0; + } + } + + Type getTypeByName(String typeName) { + //check for primitive types + switch (typeName) { + case "void": + return syms.voidType; + case "boolean": + return syms.booleanType; + case "byte": + return syms.byteType; + case "char": + return syms.charType; + case "double": + return syms.doubleType; + case "float": + return syms.floatType; + case "int": + return syms.intType; + case "long": + return syms.longType; + default: + return getTypeByName(typeName, List.nil()); + } + } + + Type getTypeByName(String typeName, List tparams) { + return new Type.ClassType( + Type.noType, + tparams, + new Symbol.ClassSymbol(0, names.fromString(typeName), null)); + } +} diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/lib/sampleapi/util/PoorDocCommentTable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/util/PoorDocCommentTable.java Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sampleapi.util; + +import java.util.HashMap; + +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.tree.DCTree.DCDocComment; +import com.sun.tools.javac.tree.DocCommentTable; +import com.sun.tools.javac.tree.JCTree; + +/* + * This class is replica of LazyDocCommentTable from com.sun.tools.javac.parser + * package. It's created due to restrictions of LazyDocCommentTable (cannot be + * used outside the package) and implements minimal functionality necessary + * for doc comment generation purposes. + */ +public class PoorDocCommentTable implements DocCommentTable { + + HashMap table; + + public PoorDocCommentTable() { + table = new HashMap<>(); + } + + public boolean hasComment(JCTree tree) { + return table.containsKey(tree); + } + + public Comment getComment(JCTree tree) { + return table.get(tree); + } + + public String getCommentText(JCTree tree) { + Comment c = getComment(tree); + return (c == null) ? null : c.getText(); + } + + public DCDocComment getCommentTree(JCTree tree) { + return null; // no need for generator purposes, Pretty does not call it + } + + public void putComment(JCTree tree, Comment c) { + table.put(tree, c); + } +} diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/lib/sampleapi/util/SimpleMultiplier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/util/SimpleMultiplier.java Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sampleapi.util; + +import java.util.StringTokenizer; +import java.util.ArrayList; + +/* + * The class implements unknown number of nested loops. The number of modifiers + * in class/interface definitions could be any size. Annotations are also multiplied + * by this class. + * That is, dataset xml can provide any number of modifier sets, and generator should + * iterate through all possible modifiers, annotations and types combinations. + * + * For example, class definition xml provides 3 modifiers sets: + * + * "public,private" + * "static" + * "final,abstract" + * + * and one types set "void,int" + * + * the class will generate the sequence like: + * "public static final void" + * "public static final int" + * "public static abstract void" + * "public static abstract int" + * "private static final void" + * "private static final int" + * "private static abstract void" + * "private static abstract int". + * + * This sequence could be processed by just one loop instead of four. + * + * In other places where the number of possible positions are known, + * the generator uses nested loops instead. + */ +public class SimpleMultiplier { + + ArrayList> valueSpace = new ArrayList<>(); + + int size = 0; + int index = 0; + + public void addAxis(String values) { + ArrayList valueAxis = new ArrayList<>(); + StringTokenizer valuesTokens = new StringTokenizer(values, "|"); + while (valuesTokens.hasMoreTokens()) + valueAxis.add(valuesTokens.nextToken()); + valueSpace.add(valueAxis); + } + + public void initIterator() { + if (!valueSpace.isEmpty()) { + size = 1; + for (int i = 0; i < valueSpace.size(); i++) + size *= valueSpace.get(i).size(); + } + index = 0; + } + + public boolean hasNext() { + return index < size; + } + + public ArrayList getNext() { + ArrayList next = new ArrayList<>(); + int positionIndex = index; + + // last added changing faster + for (int i = valueSpace.size() - 1; i >= 0; i--) { + ArrayList valueAxis = valueSpace.get(i); + int axisSize = valueAxis.size(); + next.add(valueAxis.get(positionIndex % axisSize)); + positionIndex /= axisSize; + } + index += 1; + + return next; + } +} diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/res/xml/fx.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/res/xml/fx.xml Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,45 @@ + + + + + + public + + + public + int|boolean + + + public|protected|private + int|String + void + + + public|protected|private + int|int|String + + + + + diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/res/xml/simple.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/res/xml/simple.xml Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,529 @@ + + + + + + public + none|abstract + + + none|public + none|static + none|final + boolean|int|String + + + protected|private + String + + + public + none|int|int,boolean|int,String + + + public + String + NullPointerException + SampleException0 + + + public + void + int + + + public + int|boolean|String + + + public + void|int + none|int|Object,int + NullPointerException + ArithmeticException + + + + + + public + + + + public + int|boolean + + + public + none|int|int,boolean|int,String + + + public + int|boolean + + + + + + java.io.Serializable + public + + + + private|none|public + boolean|int|String + + + + + + java.io.Serializable + java.io.ObjectStreamField + public + + + String,Long,Boolean + + public + String|long|boolean + + + + + + java.io.Serializable + java.io.ObjectOutputStream + java.io.ObjectOutput + java.io.IOException + java.io.ObjectStreamException + public + + + + private + ObjectOutputStream + void + IOException + + + public + ObjectOutput + void + IOException + + + protected + none + Object + ObjectStreamException + + + public + Object + void + IOException + + + + + + java.io.Serializable + java.io.ObjectInputStream + java.io.ObjectInput + java.io.IOException + java.io.ObjectStreamException + public + + + + private + ObjectInputStream + void + IOException + ClassNotFoundException + + + public + ObjectInput + void + IOException + + + protected + none + Object + ObjectStreamException + + + public + Object + void + IOException + + + + + + public + + + public + + + public + int + + + + + public + static + + + public + static + + + public + void + + + + + + + + + public + + + + private + boolean|int|String + + + public + String + + + public + int|String + + + + + + public + + + + private + boolean|int|String + + + public + String + + + public + int|String + + + + + + public|none + + + public + void|int|Object + + + + + + public + + + + public + int|boolean + + + public + int|boolean + + + + + + java.util.List + public + + + public + void + T + + + public + T + int + + + public + List<T> + + + + + + java.util.Set + java.util.List + java.util.Map + public + + + public + void + K,V + + + public + void + Map<K,V> + + + public + V + K + + + public + Set<V>|List<V> + + + public + Set<K>|List<K> + + + + + + java.util.Set + java.util.List + java.util.Map + public + + + public + Set<M>|List<M> + Map<N,O> + + + public + Set<N>|List<N> + Map<M,O> + + + public + Set<O>|List<O> + Map<M,N> + + + + + + java.util.Set + java.util.List + java.util.Map + java.util.function.Supplier + public + + + public + static + Set<? extends E>|List<? extends E> + + + public|private + static + Map<V,K> + + + public + static + void + E + + + public|private + static + X + Supplier<? extends X> + X + + + + + + public + + + + + + + public + + + + + private + int|String + + + public + void|String + + + + + + Documented + + + + Retention + + + + + Retention + + + + + Retention + + + + + Target + + + + + Target + + + + + Target + + + + + java.lang.annotation.Documented + @documented + public + + + public + boolean|String + + + + + + java.lang.annotation.Retention + java.lang.annotation.RetentionPolicy + @reten-source|@reten-class|@reten-runtime + public + + + public + int + + + + + + java.lang.annotation.Retention + java.lang.annotation.RetentionPolicy + java.lang.annotation.Target + java.lang.annotation.ElementType + public + + + @reten-source|@reten-class|@reten-runtime + @target-method|@target-field|@target-type + public + static + + + public + String + + + + + + + + Deprecated + + + + SafeVarargs + + + + SuppressWarnings + + + + + public + + + @deprecated + public + void + + + @safevarargs + public + void|int + String... + + + @suppresswarnings + public + void + int|Object + + + + diff -r 6d7a40b2a54b -r e9fccc09cfc6 langtools/test/tools/javadoc/sampleapi/res/xml/tiny.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/sampleapi/res/xml/tiny.xml Thu Nov 19 13:14:16 2015 -0800 @@ -0,0 +1,71 @@ + + + + + + public + none|abstract + + + public + int + + + public + int + + + + + + public + + + public + void + int + + + + + + public + + + + + + + + + public + + + public + boolean + + + + +