OpenJDK / amber / amber
changeset 56965:f71ddaa59037 records-and-sealed
basic javadoc support for record pseudo-keyword
line wrap: on
line diff
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java Fri Aug 02 11:21:38 2019 -0700 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java Fri Aug 02 16:57:06 2019 -0700 @@ -236,22 +236,21 @@ * {@inheritDoc} */ @Override // defined by AbstractDoclet - protected void generateClassFiles(SortedSet<TypeElement> arr, ClassTree classtree) + protected void generateClassFiles(SortedSet<TypeElement> typeElems, ClassTree classTree) throws DocletException { - List<TypeElement> list = new ArrayList<>(arr); - for (TypeElement klass : list) { - if (utils.hasHiddenTag(klass) || - !(configuration.isGeneratedDoc(klass) && utils.isIncluded(klass))) { + for (TypeElement te : typeElems) { + if (utils.hasHiddenTag(te) || + !(configuration.isGeneratedDoc(te) && utils.isIncluded(te))) { continue; } - if (utils.isAnnotationType(klass)) { + if (utils.isAnnotationType(te)) { AbstractBuilder annotationTypeBuilder = configuration.getBuilderFactory() - .getAnnotationTypeBuilder(klass); + .getAnnotationTypeBuilder(te); annotationTypeBuilder.build(); } else { AbstractBuilder classBuilder = - configuration.getBuilderFactory().getClassBuilder(klass, classtree); + configuration.getBuilderFactory().getClassBuilder(te, classTree); classBuilder.build(); } }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java Fri Aug 02 11:21:38 2019 -0700 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java Fri Aug 02 16:57:06 2019 -0700 @@ -70,6 +70,11 @@ private final boolean isEnum; /** + * Keep track of whether or not this typeElement is an record. + */ + private final boolean isRecord; + + /** * The content tree for the class documentation. */ private Content contentTree; @@ -91,13 +96,20 @@ if (utils.isInterface(typeElement)) { isInterface = true; isEnum = false; + isRecord = false; } else if (utils.isEnum(typeElement)) { isInterface = false; isEnum = true; + isRecord = false; utils.setEnumDocumentation(typeElement); + } else if (utils.isRecord(typeElement)) { + isInterface = false; + isEnum = false; + isRecord = true; } else { isInterface = false; isEnum = false; + isRecord = false; } } @@ -133,6 +145,8 @@ key = "doclet.Interface"; } else if (isEnum) { key = "doclet.Enum"; + } else if (isRecord) { + key = "doclet.Record"; } else { key = "doclet.Class"; }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties Fri Aug 02 11:21:38 2019 -0700 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties Fri Aug 02 16:57:06 2019 -0700 @@ -137,6 +137,7 @@ doclet.interfaces=interfaces doclet.class=class doclet.classes=classes +doclet.Record=Record doclet.Error=Error doclet.error=error doclet.errors=errors
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java Fri Aug 02 11:21:38 2019 -0700 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java Fri Aug 02 16:57:06 2019 -0700 @@ -521,6 +521,7 @@ case INTERFACE: case CLASS: case ENUM: + case RECORD: return blockTagletsBySite.get(Site.TYPE); case MODULE: return blockTagletsBySite.get(Site.MODULE);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java Fri Aug 02 11:21:38 2019 -0700 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java Fri Aug 02 16:57:06 2019 -0700 @@ -427,6 +427,10 @@ return typeUtils.isSubtype(e.asType(), getExternalizableType()); } + public boolean isRecord(TypeElement e) { + return e.getKind() == ElementKind.RECORD; + } + public SortedSet<VariableElement> serializableFields(TypeElement aclass) { return configuration.workArounds.getSerializableFields(this, aclass); } @@ -440,11 +444,11 @@ } public String modifiersToString(Element e, boolean trailingSpace) { - SortedSet<Modifier> set = new TreeSet<>(e.getModifiers()); - set.remove(NATIVE); - set.remove(STRICTFP); - set.remove(SYNCHRONIZED); - set.remove(SEALED); + SortedSet<Modifier> modifiers = new TreeSet<>(e.getModifiers()); + modifiers.remove(NATIVE); + modifiers.remove(STRICTFP); + modifiers.remove(SYNCHRONIZED); + modifiers.remove(SEALED); return new ElementKindVisitor9<String, SortedSet<Modifier>>() { final StringBuilder sb = new StringBuilder(); @@ -503,29 +507,35 @@ } @Override - public String visitTypeAsInterface(TypeElement e, SortedSet<Modifier> p) { - addVisibilityModifier(p); - addStatic(p); + public String visitTypeAsInterface(TypeElement e, SortedSet<Modifier> mods) { + addVisibilityModifier(mods); + addStatic(mods); addSealed(e); return finalString("interface"); } @Override - public String visitTypeAsEnum(TypeElement e, SortedSet<Modifier> p) { - addVisibilityModifier(p); - addStatic(p); + public String visitTypeAsEnum(TypeElement e, SortedSet<Modifier> mods) { + addVisibilityModifier(mods); + addStatic(mods); return finalString("enum"); } @Override - public String visitTypeAsAnnotationType(TypeElement e, SortedSet<Modifier> p) { - addVisibilityModifier(p); - addStatic(p); + public String visitTypeAsAnnotationType(TypeElement e, SortedSet<Modifier> mods) { + addVisibilityModifier(mods); + addStatic(mods); return finalString("@interface"); } @Override - public String visitTypeAsClass(TypeElement e, SortedSet<Modifier> p) { + public String visitTypeAsRecord(TypeElement e, SortedSet<Modifier> mods) { + mods.remove(FINAL); // suppress the implicit `final` + return visitTypeAsClass(e, mods); + } + + @Override + public String visitTypeAsClass(TypeElement e, SortedSet<Modifier> mods) { Set<Modifier> beforeSealed = EnumSet.noneOf(Modifier.class); Set<Modifier> afterSealed = EnumSet.noneOf(Modifier.class); Set<Modifier> set = beforeSealed; @@ -533,23 +543,24 @@ if (m == SEALED) { set = afterSealed; } - if (p.contains(m)) { + if (mods.contains(m)) { set.add(m); } } addModifiers(beforeSealed); addSealed(e); addModifiers(afterSealed); - return finalString("class"); + String keyword = e.getKind() == ElementKind.RECORD ? "record" : "class"; + return finalString(keyword); } @Override - protected String defaultAction(Element e, SortedSet<Modifier> p) { - addModifiers(p); + protected String defaultAction(Element e, SortedSet<Modifier> mods) { + addModifiers(mods); return sb.toString().trim(); } - }.visit(e, set); + }.visit(e, modifiers); } public boolean isFunctionalInterface(AnnotationMirror amirror) { @@ -1800,7 +1811,7 @@ result = compareStrings(getFullyQualifiedName(o1), getFullyQualifiedName(o2)); if (result != 0) return result; - return compareElementTypeKinds(o1, o2); + return compareElementKinds(o1, o2); } }; } @@ -1849,7 +1860,7 @@ return result; } // if names are the same, compare element kinds - result = compareElementTypeKinds(e1, e2); + result = compareElementKinds(e1, e2); if (result != 0) { return result; } @@ -2025,7 +2036,7 @@ if (result != 0) { return result; } - return compareElementTypeKinds(e1, e2); + return compareElementKinds(e1, e2); } }; } @@ -2037,6 +2048,8 @@ * for creating specific comparators for an use-case. */ private abstract class ElementComparator implements Comparator<Element> { + public ElementComparator() { } + /** * compares two parameter arrays by first comparing the length of the arrays, and * then each Type of the parameter in the array. @@ -2045,21 +2058,6 @@ * @return a negative integer, zero, or a positive integer as the first * argument is less than, equal to, or greater than the second. */ - final EnumMap<ElementKind, Integer> elementKindOrder; - public ElementComparator() { - elementKindOrder = new EnumMap<>(ElementKind.class); - elementKindOrder.put(ElementKind.MODULE, 0); - elementKindOrder.put(ElementKind.PACKAGE, 1); - elementKindOrder.put(ElementKind.CLASS, 2); - elementKindOrder.put(ElementKind.ENUM, 3); - elementKindOrder.put(ElementKind.ENUM_CONSTANT, 4); - elementKindOrder.put(ElementKind.INTERFACE, 5); - elementKindOrder.put(ElementKind.ANNOTATION_TYPE, 6); - elementKindOrder.put(ElementKind.FIELD, 7); - elementKindOrder.put(ElementKind.CONSTRUCTOR, 8); - elementKindOrder.put(ElementKind.METHOD, 9); - } - protected int compareParameters(boolean caseSensitive, List<? extends VariableElement> params1, List<? extends VariableElement> params2) { @@ -2122,10 +2120,28 @@ String thatElement = getFullyQualifiedName(e2); return compareStrings(thisElement, thatElement); } - protected int compareElementTypeKinds(Element e1, Element e2) { - return Integer.compare(elementKindOrder.get(e1.getKind()), - elementKindOrder.get(e2.getKind())); + + protected int compareElementKinds(Element e1, Element e2) { + return Integer.compare(getKindIndex(e1), getKindIndex(e2)); } + + private int getKindIndex(Element e) { + switch (e.getKind()) { + case MODULE: return 0; + case PACKAGE: return 1; + case CLASS: return 2; + case ENUM: return 3; + case ENUM_CONSTANT: return 4; + case RECORD: return 5; + case INTERFACE: return 6; + case ANNOTATION_TYPE: return 7; + case FIELD: return 8; + case CONSTRUCTOR: return 9; + case METHOD: return 10; + default: throw new IllegalArgumentException(e.getKind().toString()); + } + } + boolean hasParameters(Element e) { return new SimpleElementVisitor9<Boolean, Void>() { @Override @@ -2227,6 +2243,7 @@ out.addAll(getClasses(pkg)); out.addAll(getEnums(pkg)); out.addAll(getAnnotationTypes(pkg)); + out.addAll(getRecords(pkg)); return out; } @@ -2257,6 +2274,14 @@ return convertToTypeElement(getItems(e, false, ANNOTATION_TYPE)); } + public List<TypeElement> getRecords(Element e) { + return convertToTypeElement(getItems(e, true, RECORD)); + } + + public List<TypeElement> getRecordsUnfiltered(Element e) { + return convertToTypeElement(getItems(e, false, RECORD)); + } + public List<VariableElement> getFields(Element e) { return convertToVariableElement(getItems(e, true, FIELD)); } @@ -2431,6 +2456,7 @@ clist.addAll(getInterfaces(e)); clist.addAll(getAnnotationTypes(e)); clist.addAll(getEnums(e)); + clist.addAll(getRecords(e)); oset = new TreeSet<>(makeGeneralPurposeComparator()); oset.addAll(clist); cachedClasses.put(e, oset);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java Fri Aug 02 11:21:38 2019 -0700 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java Fri Aug 02 16:57:06 2019 -0700 @@ -1200,7 +1200,7 @@ ElementKind.PACKAGE, ElementKind.MODULE); - // all possible accesss levels allowed for each element + // all possible access levels allowed for each element private final EnumMap<ElementKind, EnumSet<AccessKind>> filterMap = new EnumMap<>(ElementKind.class); @@ -1285,7 +1285,7 @@ switch (kind) { case CLASS: case METHOD: case MODULE: case PACKAGE: return kind; - case ANNOTATION_TYPE: case ENUM: case INTERFACE: + case RECORD: case ANNOTATION_TYPE: case ENUM: case INTERFACE: return ElementKind.CLASS; case CONSTRUCTOR: case ENUM_CONSTANT: case EXCEPTION_PARAMETER: case FIELD: case INSTANCE_INIT: case LOCAL_VARIABLE: case PARAMETER:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java Fri Aug 02 16:57:06 2019 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019, 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 8225055 + * @summary Record types + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestRecordTypes + */ + + +import java.io.IOException; +import java.nio.file.Path; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +public class TestRecordTypes extends JavadocTester { + + public static void main(String... args) throws Exception { + TestRecordTypes tester = new TestRecordTypes(); + tester.runTests(m -> new Object[] { Path.of(m.getName()) }); + } + + private final ToolBox tb = new ToolBox(); + + @Test + public void testRecordKeywordUnnamedPackage(Path base) throws IOException { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "public record A(int a) { }"); + + javadoc("-d", base.resolve("out").toString(), + "-sourcepath", src.toString(), + src.resolve("A.java").toString()); + checkExit(Exit.OK); + + checkOutput("A.html", true, + "<h1 title=\"Record A\" class=\"title\">Record A</h1>", + "public record <span class=\"typeNameLabel\">A</span>", + "<code><span class=\"memberNameLink\"><a href=\"#%3Cinit%3E(int)\">A</a></span>​(int a)</code>"); + } + + @Test + public void testRecordKeywordNamedPackage(Path base) throws IOException { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "package p; public record A(int a) { }"); + + javadoc("-d", base.resolve("out").toString(), + "-sourcepath", src.toString(), + "p"); + checkExit(Exit.OK); + + checkOutput("p/A.html", true, + "<h1 title=\"Record A\" class=\"title\">Record A</h1>", + "public record <span class=\"typeNameLabel\">A</span>", + "<code><span class=\"memberNameLink\"><a href=\"#%3Cinit%3E(int)\">A</a></span>​(int a)</code>"); + } + +}
--- a/test/langtools/tools/lib/toolbox/ToolBox.java Fri Aug 02 11:21:38 2019 -0700 +++ b/test/langtools/tools/lib/toolbox/ToolBox.java Fri Aug 02 16:57:06 2019 -0700 @@ -650,7 +650,7 @@ private static Pattern packagePattern = Pattern.compile("package\\s+(((?:\\w+\\.)*)(?:\\w+))"); private static Pattern classPattern = - Pattern.compile("(?:public\\s+)?(?:class|enum|interface)\\s+(\\w+)"); + Pattern.compile("(?:public\\s+)?(?:class|enum|interface|record)\\s+(\\w+)"); /** * Extracts the Java file name from the class declaration.