8225054: Compiler implementation for records

8225052: javax.lang.model support for records
8225053: Preview APIs support for records
8225055: Javadoc for records
8226314: com.sun.source support for records
8227113: Specification for java.lang.Record
8233526: JVM support for records

Implement records in the compiler and the JVM, including serialization, reflection and APIs support

Co-authored-by: Brian Goetz <brian.goetz@oracle.com>
Co-authored-by: Maurizio Cimadamore <maurizio.cimadamore@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Joe Darcy <joe.darcy@oracle.com>
Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com>
Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Reviewed-by: mcimadamore, briangoetz, alanb, darcy, chegar, jrose, jlahoda, coleenp, dholmes, lfoltan, mchung, sadayapalam, hannesw, sspitsyn
This commit is contained in:
Vicente Romero 2019-12-04 15:57:39 -05:00
parent 0a375cfa2d
commit 827e5e3226
351 changed files with 24958 additions and 6395 deletions

View file

@ -38,7 +38,7 @@ import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
@ -178,9 +178,10 @@ public class AbstractIndexWriter extends HtmlDocletWriter {
contentTree.add(heading);
}
@SuppressWarnings("preview")
protected void addDescription(Content dl, Element element) {
SearchIndexItem si = new SearchIndexItem();
new SimpleElementVisitor9<Void, Void>() {
new SimpleElementVisitor14<Void, Void>() {
@Override
public Void visitModule(ModuleElement e, Void p) {

View file

@ -35,6 +35,7 @@ import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.RecordComponentElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleElementVisitor8;
@ -210,7 +211,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
/**
* {@inheritDoc}
*/
@Override
@Override @SuppressWarnings("preview")
public void addClassSignature(String modifiers, Content classInfoTree) {
Content hr = new HtmlTree(HtmlTag.HR);
classInfoTree.add(hr);
@ -231,6 +232,9 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
span.add(parameterLinks);
pre.add(span);
}
if (utils.isRecord(typeElement)) {
pre.add(getRecordComponents(typeElement));
}
if (!utils.isInterface(typeElement)) {
TypeMirror superclass = utils.getFirstVisibleSuperClass(typeElement);
if (superclass != null) {
@ -266,6 +270,26 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
classInfoTree.add(pre);
}
@SuppressWarnings("preview")
private Content getRecordComponents(TypeElement typeElem) {
Content content = new ContentBuilder();
content.add("(");
String sep = "";
for (RecordComponentElement e : typeElement.getRecordComponents()) {
content.add(sep);
getAnnotations(e.getAnnotationMirrors(), false).stream()
.forEach(a -> { content.add(a); content.add(" "); });
Content link = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.RECORD_COMPONENT,
e.asType()));
content.add(link);
content.add(Entity.NO_BREAK_SPACE);
content.add(e.getSimpleName());
sep = ", ";
}
content.add(")");
return content;
}
/**
* {@inheritDoc}
*/
@ -294,9 +318,9 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
* Get the class hierarchy tree for the given class.
*
* @param type the class to print the hierarchy for
* @return a content tree for class inheritence
* @return a content tree for class inheritance
*/
private Content getClassInheritenceTree(TypeMirror type) {
private Content getClassInheritanceTree(TypeMirror type) {
TypeMirror sup;
HtmlTree classTree = null;
do {
@ -347,19 +371,20 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
if (!utils.isClass(typeElement)) {
return;
}
classContentTree.add(getClassInheritenceTree(typeElement.asType()));
classContentTree.add(getClassInheritanceTree(typeElement.asType()));
}
/**
* {@inheritDoc}
*/
@Override
public void addTypeParamInfo(Content classInfoTree) {
if (!utils.getTypeParamTrees(typeElement).isEmpty()) {
Content typeParam = (new ParamTaglet()).getTagletOutput(typeElement,
public void addParamInfo(Content classInfoTree) {
if (utils.hasBlockTag(typeElement, DocTree.Kind.PARAM)) {
Content paramInfo = (new ParamTaglet()).getTagletOutput(typeElement,
getTagletWriterInstance(false));
Content dl = HtmlTree.DL(typeParam);
classInfoTree.add(dl);
if (!paramInfo.isEmpty()) {
classInfoTree.add(HtmlTree.DL(paramInfo));
}
}
}

View file

@ -155,6 +155,7 @@ public class Contents {
public final Content propertyLabel;
public final Content propertyDetailsLabel;
public final Content propertySummaryLabel;
public final Content record;
public final Content seeLabel;
public final Content serializedForm;
public final Content servicesLabel;
@ -282,6 +283,7 @@ public class Contents {
propertyLabel = getContent("doclet.Property");
propertyDetailsLabel = getContent("doclet.Property_Detail");
propertySummaryLabel = getContent("doclet.Property_Summary");
record = getContent("doclet.Record");
seeLabel = getContent("doclet.See");
serializedForm = getContent("doclet.Serialized_Form");
servicesLabel = getContent("doclet.Services");

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -236,22 +236,21 @@ public class HtmlDoclet extends AbstractDoclet {
* {@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();
}
}

View file

@ -51,7 +51,7 @@ import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleAnnotationValueVisitor9;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import javax.lang.model.util.SimpleTypeVisitor9;
import com.sun.source.doctree.AttributeTree;
@ -1510,7 +1510,8 @@ public class HtmlDocletWriter {
@Override
public Boolean visitLink(LinkTree node, Content c) {
// we need to pass the DocTreeImpl here, so ignore node
result.add(seeTagToContent(element, tag));
Content content = seeTagToContent(element, tag);
result.add(content);
return false;
}
@ -1658,13 +1659,14 @@ public class HtmlDocletWriter {
*
* @return the text, with all the relative links redirected to work.
*/
@SuppressWarnings("preview")
private String redirectRelativeLinks(Element element, TextTree tt) {
String text = tt.getBody();
if (element == null || utils.isOverviewElement(element) || shouldNotRedirectRelativeLinks()) {
return text;
}
DocPath redirectPathFromRoot = new SimpleElementVisitor9<DocPath, Void>() {
DocPath redirectPathFromRoot = new SimpleElementVisitor14<DocPath, Void>() {
@Override
public DocPath visitType(TypeElement e, Void p) {
return docPaths.forPackage(utils.containingPackage(e));
@ -1747,22 +1749,22 @@ public class HtmlDocletWriter {
}
/**
* Add the annotatation types for the given element and parameter.
* Add the annotation types for the given element and parameter.
*
* @param param the parameter to write annotations for.
* @param tree the content tree to which the annotation types will be added
*/
public boolean addAnnotationInfo(VariableElement param, Content tree) {
Content annotaionInfo = getAnnotationInfo(param.getAnnotationMirrors(), false);
if (annotaionInfo.isEmpty()) {
Content annotationInfo = getAnnotationInfo(param.getAnnotationMirrors(), false);
if (annotationInfo.isEmpty()) {
return false;
}
tree.add(annotaionInfo);
tree.add(annotationInfo);
return true;
}
/**
* Adds the annotatation types for the given Element.
* Adds the annotation types for the given Element.
*
* @param descList a list of annotation mirrors.
* @param htmltree the documentation tree to which the annotation info will be

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -215,7 +215,12 @@ public class LinkInfoImpl extends LinkInfo {
/**
* A receiver type
*/
RECEIVER_TYPE
RECEIVER_TYPE,
/**
* A record component within a class signature
*/
RECORD_COMPONENT
}
public final HtmlConfiguration configuration;

View file

@ -208,6 +208,15 @@ public class PackageWriterImpl extends HtmlDocletWriter
addClassesSummary(enums, resources.enumSummary, tableHeader, summaryContentTree);
}
/**
* {@inheritDoc}
*/
@Override
public void addRecordSummary(SortedSet<TypeElement> records, Content summaryContentTree) {
TableHeader tableHeader= new TableHeader(contents.record, contents.descriptionLabel);
addClassesSummary(records, resources.recordSummary, tableHeader, summaryContentTree);
}
/**
* {@inheritDoc}
*/

View file

@ -28,13 +28,15 @@ package jdk.javadoc.internal.doclets.formats.html;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.IndexTree;
import com.sun.source.doctree.ParamTree;
import com.sun.source.doctree.SystemPropertyTree;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
@ -190,15 +192,19 @@ public class TagletWriterImpl extends TagletWriter {
/**
* {@inheritDoc}
*/
@SuppressWarnings("preview")
public Content paramTagOutput(Element element, DocTree paramTag, String paramName) {
ContentBuilder body = new ContentBuilder();
CommentHelper ch = utils.getCommentHelper(element);
body.add(HtmlTree.CODE(new RawHtml(paramName)));
// define id attributes for state components so that generated descriptions may refer to them
boolean defineID = (element.getKind() == ElementKind.RECORD)
&& (paramTag instanceof ParamTree) && !((ParamTree) paramTag).isTypeParameter();
Content nameTree = new StringContent(paramName);
body.add(HtmlTree.CODE(defineID ? HtmlTree.A_ID("param-" + paramName, nameTree) : nameTree));
body.add(" - ");
List<? extends DocTree> description = ch.getDescription(configuration, paramTag);
body.add(htmlWriter.commentTagsToContent(paramTag, element, description, false, inSummary));
HtmlTree result = HtmlTree.DD(body);
return result;
return HtmlTree.DD(body);
}
/**
@ -409,6 +415,7 @@ public class TagletWriterImpl extends TagletWriter {
return configuration;
}
@SuppressWarnings("preview")
private Content createAnchorAndSearchIndex(Element element, String tagText, String desc){
Content result = null;
if (isFirstSentence && inSummary) {
@ -427,7 +434,7 @@ public class TagletWriterImpl extends TagletWriter {
si.setDescription(desc);
si.setUrl(htmlWriter.path.getPath() + "#" + anchorName);
DocPaths docPaths = configuration.docPaths;
new SimpleElementVisitor9<Void, Void>() {
new SimpleElementVisitor14<Void, Void>() {
@Override
public Void visitVariable(VariableElement e, Void p) {
TypeElement te = utils.getEnclosingTypeElement(e);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -26,13 +26,14 @@
package jdk.javadoc.internal.doclets.toolkit;
import java.io.*;
import java.lang.ref.*;
import java.util.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
@ -1222,6 +1223,7 @@ public abstract class BaseConfiguration {
* Splits the elements in a collection to its individual
* collection.
*/
@SuppressWarnings("preview")
static private class Splitter {
final Set<ModuleElement> mset = new LinkedHashSet<>();
@ -1235,7 +1237,7 @@ public abstract class BaseConfiguration {
: docEnv.getSpecifiedElements();
for (Element e : inset) {
new SimpleElementVisitor9<Void, Void>() {
new SimpleElementVisitor14<Void, Void>() {
@Override
@DefinedBy(Api.LANGUAGE_MODEL)
public Void visitModule(ModuleElement e, Void p) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -73,11 +73,11 @@ public interface ClassWriter {
public Content getClassInfoTreeHeader();
/**
* Add the type parameter information.
* Add the type parameter and state component information.
*
* @param classInfoTree content tree to which the documentation will be added
*/
public void addTypeParamInfo(Content classInfoTree);
public void addParamInfo(Content classInfoTree);
/**
* Add all super interfaces if this is an interface.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -38,20 +38,26 @@ import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.RecordComponentElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import com.sun.source.doctree.AttributeTree;
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.IdentifierTree;
import com.sun.source.doctree.ParamTree;
import com.sun.source.doctree.ReferenceTree;
import com.sun.source.doctree.TextTree;
import com.sun.source.util.DocTreeFactory;
@ -65,6 +71,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils;
public class CommentUtils {
final BaseConfiguration configuration;
final Utils utils;
final Resources resources;
final DocTreeFactory treeFactory;
final HashMap<Element, DocCommentDuo> dcTreesMap = new HashMap<>();
@ -73,6 +80,7 @@ public class CommentUtils {
protected CommentUtils(BaseConfiguration configuration) {
this.configuration = configuration;
utils = configuration.utils;
resources = configuration.getResources();
trees = configuration.docEnv.getDocTrees();
treeFactory = trees.getDocTreeFactory();
@ -107,17 +115,17 @@ public class CommentUtils {
return treeFactory.newSeeTree(list);
}
public DocTree makeTextTree(String content) {
TextTree text = treeFactory.newTextTree(content);
return (DocTree) text;
public TextTree makeTextTree(String content) {
return treeFactory.newTextTree(content);
}
public void setEnumValuesTree(Element e) {
Utils utils = configuration.utils;
String klassName = utils.getSimpleName(utils.getEnclosingTypeElement(e));
public TextTree makeTextTreeForResource(String key) {
return treeFactory.newTextTree(resources.getText(key));
}
public void setEnumValuesTree(ExecutableElement ee) {
List<DocTree> fullBody = new ArrayList<>();
fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.fullbody", klassName)));
fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.fullbody")));
List<DocTree> descriptions = new ArrayList<>();
descriptions.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.return")));
@ -125,11 +133,10 @@ public class CommentUtils {
List<DocTree> tags = new ArrayList<>();
tags.add(treeFactory.newReturnTree(descriptions));
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
dcTreesMap.put(e, new DocCommentDuo(null, docTree));
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
}
public void setEnumValueOfTree(Element e) {
public void setEnumValueOfTree(ExecutableElement ee) {
List<DocTree> fullBody = new ArrayList<>();
fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.fullbody")));
@ -137,7 +144,6 @@ public class CommentUtils {
List<DocTree> paramDescs = new ArrayList<>();
paramDescs.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.param_name")));
ExecutableElement ee = (ExecutableElement) e;
java.util.List<? extends VariableElement> parameters = ee.getParameters();
VariableElement param = parameters.get(0);
IdentifierTree id = treeFactory.newIdentifierTree(elementUtils.getName(param.getSimpleName().toString()));
@ -161,7 +167,231 @@ public class CommentUtils {
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
dcTreesMap.put(e, new DocCommentDuo(null, docTree));
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
}
/**
* Generates the description for the canonical constructor for a record.
* @param ee the constructor
*/
public void setRecordConstructorTree(ExecutableElement ee) {
TypeElement te = utils.getEnclosingTypeElement(ee);
List<DocTree> fullBody =
makeDescriptionWithName("doclet.record_constructor_doc.fullbody", te.getSimpleName());
List<DocTree> tags = new ArrayList<>();
java.util.List<? extends VariableElement> parameters = ee.getParameters();
for (VariableElement param : ee.getParameters()) {
Name name = param.getSimpleName();
IdentifierTree id = treeFactory.newIdentifierTree(name);
tags.add(treeFactory.newParamTree(false, id,
makeDescriptionWithComponent("doclet.record_constructor_doc.param_name", te, name)));
}
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
}
/**
* Generates the description for the standard {@code equals} method for a record.
* @param ee the {@code equals} method
*/
@SuppressWarnings("preview")
public void setRecordEqualsTree(ExecutableElement ee) {
List<DocTree> fullBody = new ArrayList<>();
add(fullBody, "doclet.record_equals_doc.fullbody.head");
fullBody.add(treeFactory.newTextTree(" "));
List<? extends RecordComponentElement> comps = ((TypeElement) ee.getEnclosingElement()).getRecordComponents();
boolean hasPrimitiveComponents =
comps.stream().anyMatch(e -> e.asType().getKind().isPrimitive());
boolean hasReferenceComponents =
comps.stream().anyMatch(e -> !e.asType().getKind().isPrimitive());
if (hasPrimitiveComponents && hasReferenceComponents) {
add(fullBody, "doclet.record_equals_doc.fullbody.tail.both");
} else if (hasPrimitiveComponents) {
add(fullBody, "doclet.record_equals_doc.fullbody.tail.primitive");
} else if (hasReferenceComponents) {
add(fullBody, "doclet.record_equals_doc.fullbody.tail.reference");
}
Name paramName = ee.getParameters().get(0).getSimpleName();
IdentifierTree id = treeFactory.newIdentifierTree(paramName);
List<DocTree> paramDesc =
makeDescriptionWithName("doclet.record_equals_doc.param_name", paramName);
DocTree paramTree = treeFactory.newParamTree(false, id, paramDesc);
DocTree returnTree = treeFactory.newReturnTree(
makeDescriptionWithName("doclet.record_equals_doc.return", paramName));
TreePath treePath = utils.getTreePath(ee.getEnclosingElement());
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(paramTree, returnTree));
dcTreesMap.put(ee, new DocCommentDuo(treePath, docTree));
}
private void add(List<DocTree> contents, String resourceKey) {
// Special case to allow '{@link ...}' to appear in the string.
// A less general case would be to detect literal use of Object.equals
// A more general case would be to allow access to DocCommentParser somehow
String body = resources.getText(resourceKey);
Pattern p = Pattern.compile("\\{@link (\\S*)(.*)}");
Matcher m = p.matcher(body);
int start = 0;
while (m.find(start)) {
if (m.start() > start) {
contents.add(treeFactory.newTextTree(body.substring(start, m.start())));
}
ReferenceTree refTree = treeFactory.newReferenceTree(m.group(1));
List<DocTree> descr = List.of(treeFactory.newTextTree(m.group(2).trim())) ;
contents.add(treeFactory.newLinkTree(refTree, descr));
start = m.end();
}
if (start < body.length()) {
contents.add(treeFactory.newTextTree(body.substring(start)));
}
}
/**
* Generates the description for the standard {@code hashCode} method for a record.
* @param ee the {@code hashCode} method
*/
public void setRecordHashCodeTree(ExecutableElement ee) {
List<DocTree> fullBody = List.of(makeTextTreeForResource("doclet.record_hashCode_doc.fullbody"));
DocTree returnTree = treeFactory.newReturnTree(
List.of(makeTextTreeForResource("doclet.record_hashCode_doc.return")));
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
}
/**
* Generates the description for the standard {@code toString} method for a record.
* @param ee the {@code toString} method
*/
public void setRecordToStringTree(ExecutableElement ee) {
List<DocTree> fullBody = List.of(
treeFactory.newTextTree(resources.getText("doclet.record_toString_doc.fullbody")));
DocTree returnTree = treeFactory.newReturnTree(List.of(
treeFactory.newTextTree(resources.getText("doclet.record_toString_doc.return"))));
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
}
/**
* Generates the description for the accessor method for a state component of a record.
* @param ee the accessor method
*/
public void setRecordAccessorTree(ExecutableElement ee) {
TypeElement te = utils.getEnclosingTypeElement(ee);
List<DocTree> fullBody =
makeDescriptionWithComponent("doclet.record_accessor_doc.fullbody", te, ee.getSimpleName());
DocTree returnTree = treeFactory.newReturnTree(
makeDescriptionWithComponent("doclet.record_accessor_doc.return", te, ee.getSimpleName()));
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
}
/**
* Generates the description for the field for a state component of a record.
* @param ve the field
*/
public void setRecordFieldTree(VariableElement ve) {
TypeElement te = utils.getEnclosingTypeElement(ve);
List<DocTree> fullBody =
makeDescriptionWithComponent("doclet.record_field_doc.fullbody", te, ve.getSimpleName());
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of());
dcTreesMap.put(ve, new DocCommentDuo(null, docTree));
}
/**
* Creates a description that contains a reference to a state component of a record.
* The description is looked up as a resource, and should contain {@code {0}} where the
* reference to the component is to be inserted. The reference will be a link if the
* doc comment for the record has a {@code @param} tag for the component.
* @param key the resource key for the description
* @param elem the record element
* @param component the name of the component
* @return the description
*/
private List<DocTree> makeDescriptionWithComponent(String key, TypeElement elem, Name component) {
List<DocTree> result = new ArrayList<>();
String text = resources.getText(key);
int index = text.indexOf("{0}");
result.add(treeFactory.newTextTree(text.substring(0, index)));
Name A = elementUtils.getName("a");
Name CODE = elementUtils.getName("code");
Name HREF = elementUtils.getName("href");
List<DocTree> code = List.of(
treeFactory.newStartElementTree(CODE, List.of(), false),
treeFactory.newTextTree(component.toString()),
treeFactory.newEndElementTree(CODE));
if (hasParamForComponent(elem, component)) {
DocTree href = treeFactory.newAttributeTree(HREF,
AttributeTree.ValueKind.DOUBLE,
List.of(treeFactory.newTextTree("#param-" + component)));
result.add(treeFactory.newStartElementTree(A, List.of(href), false));
result.addAll(code);
result.add(treeFactory.newEndElementTree(A));
} else {
result.addAll(code);
}
result.add(treeFactory.newTextTree(text.substring(index + 3)));
return result;
}
/**
* Returns whether or not the doc comment for a record contains an {@code @param}}
* for a state component of the record.
* @param elem the record element
* @param component the name of the component
* @return whether or not there is a {@code @param}} for the component
*/
private boolean hasParamForComponent(TypeElement elem, Name component) {
DocCommentTree elemComment = utils.getDocCommentTree(elem);
if (elemComment == null) {
return false;
}
for (DocTree t : elemComment.getBlockTags()) {
if (t instanceof ParamTree && ((ParamTree) t).getName().getName() == component) {
return true;
}
}
return false;
}
/**
* Creates a description that contains the simple name of a program element
* The description is looked up as a resource, and should contain {@code {0}} where the
* name is to be inserted.
* @param key the resource key for the description
* @param name the name
* @return the description
*/
private List<DocTree> makeDescriptionWithName(String key, Name name) {
String text = resources.getText(key);
int index = text.indexOf("{0}");
if (index == -1) {
return List.of(treeFactory.newTextTree(text));
} else {
Name CODE = elementUtils.getName("code");
return List.of(
treeFactory.newTextTree(text.substring(0, index)),
treeFactory.newStartElementTree(CODE, List.of(), false),
treeFactory.newTextTree(name.toString()),
treeFactory.newEndElementTree(CODE),
treeFactory.newTextTree(text.substring(index + 3))
);
}
}
/*
@ -215,7 +445,7 @@ public class CommentUtils {
}
public void setDocCommentTree(Element element, List<? extends DocTree> fullBody,
List<? extends DocTree> blockTags, Utils utils) {
List<? extends DocTree> blockTags) {
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, blockTags);
dcTreesMap.put(element, new DocCommentDuo(null, docTree));
// A method having null comment (no comment) that might need to be replaced

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -94,6 +94,15 @@ public interface PackageSummaryWriter {
public abstract void addEnumSummary(SortedSet<TypeElement> enums,
Content summaryContentTree);
/**
* Adds the table of records to the documentation tree.
*
* @param records the records to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
public abstract void addRecordSummary(SortedSet<TypeElement> records,
Content summaryContentTree);
/**
* Adds the table of exceptions to the documentation tree.
*

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -49,6 +49,7 @@ public class Resources {
public final String exceptionSummary;
public final String interfaceSummary;
public final String packageSummary;
public final String recordSummary;
protected ResourceBundle commonBundle;
protected ResourceBundle docletBundle;
@ -76,6 +77,7 @@ public class Resources {
this.exceptionSummary = getText("doclet.Exception_Summary");
this.interfaceSummary = getText("doclet.Interface_Summary");
this.packageSummary = getText("doclet.Package_Summary");
this.recordSummary = getText("doclet.Record_Summary");
}
/**

View file

@ -25,11 +25,21 @@
package jdk.javadoc.internal.doclets.toolkit.builders;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
import jdk.javadoc.internal.doclets.toolkit.CommentUtils;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.DocFilesHandler;
import jdk.javadoc.internal.doclets.toolkit.DocletException;
@ -69,6 +79,16 @@ public class ClassBuilder extends AbstractBuilder {
*/
private final boolean isEnum;
/**
* Keep track of whether or not this typeElement is a record.
*/
private final boolean isRecord;
/**
* The content tree for the class documentation.
*/
private Content contentTree;
private final Utils utils;
/**
@ -86,13 +106,21 @@ public class ClassBuilder extends AbstractBuilder {
if (utils.isInterface(typeElement)) {
isInterface = true;
isEnum = false;
isRecord = false;
} else if (utils.isEnum(typeElement)) {
isInterface = false;
isEnum = true;
utils.setEnumDocumentation(typeElement);
isRecord = false;
setEnumDocumentation(typeElement);
} else if (utils.isRecord(typeElement)) {
isInterface = false;
isEnum = false;
isRecord = true;
setRecordDocumentation(typeElement);
} else {
isInterface = false;
isEnum = false;
isRecord = false;
}
}
@ -127,6 +155,8 @@ public class ClassBuilder extends AbstractBuilder {
key = "doclet.Interface";
} else if (isEnum) {
key = "doclet.Enum";
} else if (isRecord) {
key = "doclet.Record";
} else {
key = "doclet.Class";
}
@ -162,7 +192,7 @@ public class ClassBuilder extends AbstractBuilder {
*/
protected void buildClassInfo(Content classContentTree) throws DocletException {
Content classInfoTree = new ContentBuilder();
buildTypeParamInfo(classInfoTree);
buildParamInfo(classInfoTree);
buildSuperInterfacesInfo(classInfoTree);
buildImplementedInterfacesInfo(classInfoTree);
buildSubClassInfo(classInfoTree);
@ -179,12 +209,12 @@ public class ClassBuilder extends AbstractBuilder {
}
/**
* Build the type parameters of this class.
* Build the type parameters and state components of this class.
*
* @param classInfoTree the content tree to which the documentation will be added
*/
protected void buildTypeParamInfo(Content classInfoTree) {
writer.addTypeParamInfo(classInfoTree);
protected void buildParamInfo(Content classInfoTree) {
writer.addParamInfo(classInfoTree);
}
/**
@ -386,4 +416,96 @@ public class ClassBuilder extends AbstractBuilder {
protected void buildMethodDetails(Content memberDetailsTree) throws DocletException {
builderFactory.getMethodBuilder(writer).build(memberDetailsTree);
}
/**
* The documentation for values() and valueOf() in Enums are set by the
* doclet only iff the user or overridden methods are missing.
* @param elem the enum element
*/
private void setEnumDocumentation(TypeElement elem) {
CommentUtils cmtUtils = configuration.cmtUtils;
for (ExecutableElement ee : utils.getMethods(elem)) {
if (!utils.getFullBody(ee).isEmpty()) // ignore if already set
continue;
Name name = ee.getSimpleName();
if (name.contentEquals("values") && ee.getParameters().isEmpty()) {
utils.removeCommentHelper(ee); // purge previous entry
cmtUtils.setEnumValuesTree(ee);
} else if (name.contentEquals("valueOf") && ee.getParameters().size() == 1) {
// TODO: check parameter type
utils.removeCommentHelper(ee); // purge previous entry
cmtUtils.setEnumValueOfTree(ee);
}
}
}
/**
* Sets the documentation as needed for the mandated parts of a record type.
* This includes the canonical constructor, methods like {@code equals},
* {@code hashCode}, {@code toString}, the accessor methods, and the underlying
* field.
* @param elem the record element
*/
@SuppressWarnings("preview")
private void setRecordDocumentation(TypeElement elem) {
CommentUtils cmtUtils = configuration.cmtUtils;
Set<Name> componentNames = elem.getRecordComponents().stream()
.map(Element::getSimpleName)
.collect(Collectors.toSet());
for (ExecutableElement ee : utils.getConstructors(elem)) {
if (utils.isCanonicalRecordConstructor(ee)) {
if (utils.getFullBody(ee).isEmpty()) {
utils.removeCommentHelper(ee); // purge previous entry
cmtUtils.setRecordConstructorTree(ee);
}
// only one canonical constructor; no need to keep looking
break;
}
}
for (VariableElement ve : utils.getFields(elem)) {
// The fields for the record component cannot be declared by the
// user and so cannot have any pre-existing comment.
Name name = ve.getSimpleName();
if (componentNames.contains(name)) {
utils.removeCommentHelper(ve); // purge previous entry
cmtUtils.setRecordFieldTree(ve);
}
}
TypeMirror objectType = utils.getObjectType();
for (ExecutableElement ee : utils.getMethods(elem)) {
if (!utils.getFullBody(ee).isEmpty()) {
continue;
}
Name name = ee.getSimpleName();
List<? extends VariableElement> params = ee.getParameters();
if (name.contentEquals("equals")) {
if (params.size() == 1 && utils.typeUtils.isSameType(params.get(0).asType(), objectType)) {
utils.removeCommentHelper(ee); // purge previous entry
cmtUtils.setRecordEqualsTree(ee);
}
} else if (name.contentEquals("hashCode")) {
if (params.isEmpty()) {
utils.removeCommentHelper(ee); // purge previous entry
cmtUtils.setRecordHashCodeTree(ee);
}
} else if (name.contentEquals("toString")) {
if (params.isEmpty()) {
utils.removeCommentHelper(ee); // purge previous entry
cmtUtils.setRecordToStringTree(ee);
}
} else if (componentNames.contains(name)) {
if (params.isEmpty()) {
utils.removeCommentHelper(ee); // purge previous entry
cmtUtils.setRecordAccessorTree(ee);
}
}
}
}
}

View file

@ -411,7 +411,7 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder {
blockTags.add(cmtutils.makeSeeTree(sb.toString(), setter));
}
}
cmtutils.setDocCommentTree(member, fullBody, blockTags, utils);
cmtutils.setDocCommentTree(member, fullBody, blockTags);
}
/**

View file

@ -151,6 +151,7 @@ public class PackageSummaryBuilder extends AbstractBuilder {
buildInterfaceSummary(summaryContentTree);
buildClassSummary(summaryContentTree);
buildEnumSummary(summaryContentTree);
buildRecordSummary(summaryContentTree);
buildExceptionSummary(summaryContentTree);
buildErrorSummary(summaryContentTree);
buildAnnotationTypeSummary(summaryContentTree);
@ -206,6 +207,22 @@ public class PackageSummaryBuilder extends AbstractBuilder {
}
}
/**
* Build the summary for the records in this package.
*
* @param summaryContentTree the summary tree to which the record summary will
* be added
*/
protected void buildRecordSummary(Content summaryContentTree) {
SortedSet<TypeElement> rlist = utils.isSpecified(packageElement)
? utils.getTypeElementsAsSortedSet(utils.getRecords(packageElement))
: configuration.typeElementCatalog.records(packageElement);
SortedSet<TypeElement> records = utils.filterOutPrivateClasses(rlist, configuration.javafx);
if (!records.isEmpty()) {
packageWriter.addRecordSummary(records, summaryContentTree);
}
}
/**
* Build the summary for the exceptions in this package.
*

View file

@ -591,10 +591,10 @@ public class SerializedFormBuilder extends AbstractBuilder {
}
/**
* Return true if any of the given typeElements have a @serialinclude tag.
* Return true if any of the given typeElements have a {@code @serial include} tag.
*
* @param classes the typeElements to check.
* @return true if any of the given typeElements have a @serialinclude tag.
* @return true if any of the given typeElements have a {@code @serial include} tag.
*/
private boolean serialClassFoundToDocument(SortedSet<TypeElement> classes) {
for (TypeElement aClass : classes) {

View file

@ -93,10 +93,13 @@ doclet.PropertySetterWithName=Sets the value of the property {0}.
doclet.Default=Default:
doclet.Parameters=Parameters:
doclet.TypeParameters=Type Parameters:
doclet.RecordComponents=Record Components:
doclet.Parameters_warn=@param argument "{0}" is not a parameter name.
doclet.Parameters_dup_warn=Parameter "{0}" is documented more than once.
doclet.Type_Parameters_warn=@param argument "{0}" is not a type parameter name.
doclet.Type_Parameters_dup_warn=Type parameter "{0}" is documented more than once.
doclet.TypeParameters_warn=@param argument "{0}" is not the name of a type parameter.
doclet.TypeParameters_dup_warn=Type parameter "{0}" is documented more than once.
doclet.RecordComponents_warn=@param argument "{0}" is not the name of a record component.
doclet.RecordComponents_dup_warn=Record component "{0}" is documented more than once.
doclet.Returns=Returns:
doclet.Return_tag_on_void_method=@return tag cannot be used in method with void return type.
doclet.See_Also=See Also:
@ -137,6 +140,7 @@ doclet.Property_Summary=Property Summary
doclet.Enum_Constant_Summary=Enum Constant Summary
doclet.Constructor_Summary=Constructor Summary
doclet.Method_Summary=Method Summary
doclet.Record_Summary=Record Summary
doclet.Interfaces=Interfaces
doclet.Enums=Enums
doclet.AnnotationTypes=Annotation Types
@ -160,6 +164,7 @@ doclet.interface=interface
doclet.interfaces=interfaces
doclet.class=class
doclet.classes=classes
doclet.Record=Record
doclet.Error=Error
doclet.error=error
doclet.errors=errors
@ -268,3 +273,58 @@ doclet.enum_valueof_doc.throws_ila=\
doclet.enum_valueof_doc.throws_npe=\
if the argument is null
#Documentation for records
doclet.record_constructor_doc.fullbody=\
Creates an instance of a {0} record.
doclet.record_constructor_doc.param_name=\
the value for the {0} record component
doclet.record_equals_doc.fullbody.head=\
Indicates whether some other object is "equal to" this one. \
The objects are equal if the other object is of the same class \
and if all the record components are equal.
doclet.record_equals_doc.fullbody.tail.both=\
Reference components are compared with \
{@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}; \
primitive components are compared with '=='.
doclet.record_equals_doc.fullbody.tail.primitive=\
All components in this record are compared with '=='.
doclet.record_equals_doc.fullbody.tail.reference=\
All components in this record are compared with \
{@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}.
doclet.record_equals_doc.param_name=\
the object with which to compare
doclet.record_equals_doc.return=\
<code>true</code> if this object is the same as the {0} argument; <code>false</code> otherwise.
doclet.record_hashCode_doc.fullbody=\
Returns a hash code value for this object. \
The value is derived from the hash code of each of the record components.
doclet.record_hashCode_doc.return=\
a hash code value for this object
doclet.record_toString_doc.fullbody=\
Returns a string representation of this record. \
The representation contains the name of the type, followed by \
the name and value of each of the record components.
doclet.record_toString_doc.return=\
a string representation of this object
doclet.record_accessor_doc.fullbody=\
Returns the value of the {0} record component.
doclet.record_accessor_doc.return=\
the value of the {0} record component
doclet.record_field_doc.fullbody=\
The field for the {0} record component.

View file

@ -29,6 +29,7 @@ import java.util.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import com.sun.source.doctree.DocTree;
@ -53,6 +54,14 @@ import static com.sun.source.doctree.DocTree.Kind.PARAM;
* @author Jamie Ho
*/
public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
private enum ParamKind {
/** Parameter of an executable element. */
PARAMETER,
/** State components of a record. */
RECORD_COMPONENT,
/** Type parameters of an executable element or type element. */
TYPE_PARAMETER
}
/**
* Construct a ParamTaglet.
@ -101,7 +110,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
String pname = input.isTypeVariableParamTag
? utils.getTypeName(e.asType(), false)
: utils.getSimpleName(e);
if (pname.equals(target)) {
if (pname.contentEquals(target)) {
input.tagId = String.valueOf(i);
break;
}
@ -128,19 +137,23 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
}
@Override
@SuppressWarnings("preview")
public Content getTagletOutput(Element holder, TagletWriter writer) {
Utils utils = writer.configuration().utils;
if (utils.isExecutableElement(holder)) {
ExecutableElement member = (ExecutableElement) holder;
Content output = getTagletOutput(false, member, writer,
Content output = getTagletOutput(ParamKind.TYPE_PARAMETER, member, writer,
member.getTypeParameters(), utils.getTypeParamTrees(member));
output.add(getTagletOutput(true, member, writer,
output.add(getTagletOutput(ParamKind.PARAMETER, member, writer,
member.getParameters(), utils.getParamTrees(member)));
return output;
} else {
TypeElement typeElement = (TypeElement) holder;
return getTagletOutput(false, typeElement, writer,
Content output = getTagletOutput(ParamKind.TYPE_PARAMETER, typeElement, writer,
typeElement.getTypeParameters(), utils.getTypeParamTrees(typeElement));
output.add(getTagletOutput(ParamKind.RECORD_COMPONENT, typeElement, writer,
typeElement.getRecordComponents(), utils.getParamTrees(typeElement)));
return output;
}
}
@ -150,25 +163,25 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
*
* @param holder the element that holds the param tags.
* @param writer the TagletWriter that will write this tag.
* @param formalParameters The array of parmeters (from type or executable
* @param formalParameters The array of parameters (from type or executable
* member) to check.
*
* @return the content representation of these {@code @param DocTree}s.
*/
private Content getTagletOutput(boolean isParameters, Element holder,
private Content getTagletOutput(ParamKind kind, Element holder,
TagletWriter writer, List<? extends Element> formalParameters, List<? extends DocTree> paramTags) {
Content result = writer.getOutputInstance();
Set<String> alreadyDocumented = new HashSet<>();
if (!paramTags.isEmpty()) {
result.add(
processParamTags(holder, isParameters, paramTags,
processParamTags(holder, kind, paramTags,
getRankMap(writer.configuration().utils, formalParameters), writer, alreadyDocumented)
);
}
if (alreadyDocumented.size() != formalParameters.size()) {
//Some parameters are missing corresponding @param tags.
//Try to inherit them.
result.add(getInheritedTagletOutput(isParameters, holder,
result.add(getInheritedTagletOutput(kind, holder,
writer, formalParameters, alreadyDocumented));
}
return result;
@ -178,7 +191,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
* Loop through each individual parameter, despite not having a
* corresponding param tag, try to inherit it.
*/
private Content getInheritedTagletOutput(boolean isParameters, Element holder,
private Content getInheritedTagletOutput(ParamKind kind, Element holder,
TagletWriter writer, List<? extends Element> formalParameters,
Set<String> alreadyDocumented) {
Utils utils = writer.configuration().utils;
@ -191,16 +204,16 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
// This parameter does not have any @param documentation.
// Try to inherit it.
Input input = new DocFinder.Input(writer.configuration().utils, holder, this,
Integer.toString(i), !isParameters);
Integer.toString(i), kind == ParamKind.TYPE_PARAMETER);
DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input);
if (inheritedDoc.inlineTags != null && !inheritedDoc.inlineTags.isEmpty()) {
Element e = formalParameters.get(i);
String lname = isParameters
String lname = kind != ParamKind.TYPE_PARAMETER
? utils.getSimpleName(e)
: utils.getTypeName(e.asType(), false);
CommentHelper ch = utils.getCommentHelper(holder);
ch.setOverrideElement(inheritedDoc.holder);
Content content = processParamTag(holder, isParameters, writer,
Content content = processParamTag(holder, kind, writer,
inheritedDoc.holderTag,
lname,
alreadyDocumented.isEmpty());
@ -230,7 +243,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
when parameter documentation is inherited.
* @return the Content representation of this {@code @param DocTree}.
*/
private Content processParamTags(Element e, boolean isParams,
private Content processParamTags(Element e, ParamKind kind,
List<? extends DocTree> paramTags, Map<String, String> rankMap, TagletWriter writer,
Set<String> alreadyDocumented) {
Messages messages = writer.configuration().getMessages();
@ -238,26 +251,33 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
if (!paramTags.isEmpty()) {
CommentHelper ch = writer.configuration().utils.getCommentHelper(e);
for (DocTree dt : paramTags) {
String paramName = isParams
? ch.getParameterName(dt)
: "<" + ch.getParameterName(dt) + ">";
if (!rankMap.containsKey(ch.getParameterName(dt))) {
messages.warning(ch.getDocTreePath(dt),
isParams
? "doclet.Parameters_warn"
: "doclet.Type_Parameters_warn",
paramName);
String name = ch.getParameterName(dt);
String paramName = kind != ParamKind.TYPE_PARAMETER
? name.toString()
: "<" + name + ">";
if (!rankMap.containsKey(name)) {
String key;
switch (kind) {
case PARAMETER: key = "doclet.Parameters_warn" ; break;
case TYPE_PARAMETER: key = "doclet.TypeParameters_warn" ; break;
case RECORD_COMPONENT: key = "doclet.RecordComponents_warn" ; break;
default: throw new IllegalArgumentException(kind.toString());
}
String rank = rankMap.get(ch.getParameterName(dt));
messages.warning(ch.getDocTreePath(dt), key, paramName);
}
String rank = rankMap.get(name);
if (rank != null && alreadyDocumented.contains(rank)) {
messages.warning(ch.getDocTreePath(dt),
isParams
? "doclet.Parameters_dup_warn"
: "doclet.Type_Parameters_dup_warn",
paramName);
String key;
switch (kind) {
case PARAMETER: key = "doclet.Parameters_dup_warn" ; break;
case TYPE_PARAMETER: key = "doclet.TypeParameters_dup_warn" ; break;
case RECORD_COMPONENT: key = "doclet.RecordComponents_dup_warn" ; break;
default: throw new IllegalArgumentException(kind.toString());
}
result.add(processParamTag(e, isParams, writer, dt,
ch.getParameterName(dt), alreadyDocumented.isEmpty()));
messages.warning(ch.getDocTreePath(dt), key, paramName);
}
result.add(processParamTag(e, kind, writer, dt,
name, alreadyDocumented.isEmpty()));
alreadyDocumented.add(rank);
}
}
@ -268,8 +288,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
* Convert the individual ParamTag into Content.
*
* @param e the owner element
* @param isParams true if this is just a regular param tag. False
* if this is a type param tag.
* @param kind the kind of param tag
* @param writer the taglet writer for output writing.
* @param paramTag the tag whose inline tags will be printed.
* @param name the name of the parameter. We can't rely on
@ -278,13 +297,19 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
* @param isFirstParam true if this is the first param tag being printed.
*
*/
private Content processParamTag(Element e, boolean isParams,
private Content processParamTag(Element e, ParamKind kind,
TagletWriter writer, DocTree paramTag, String name,
boolean isFirstParam) {
Content result = writer.getOutputInstance();
String header = writer.configuration().getResources().getText(
isParams ? "doclet.Parameters" : "doclet.TypeParameters");
if (isFirstParam) {
String key;
switch (kind) {
case PARAMETER: key = "doclet.Parameters" ; break;
case TYPE_PARAMETER: key = "doclet.TypeParameters" ; break;
case RECORD_COMPONENT: key = "doclet.RecordComponents" ; break;
default: throw new IllegalArgumentException(kind.toString());
}
String header = writer.configuration().getResources().getText(key);
result.add(writer.getParamHeader(header));
}
result.add(writer.paramTagOutput(e, paramTag, name));

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -34,7 +34,7 @@ import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import javax.tools.JavaFileManager;
import javax.tools.StandardJavaFileManager;
@ -333,6 +333,7 @@ public class TagletManager {
* @param trees the trees containing the comments
* @param areInlineTags true if the array of tags are inline and false otherwise.
*/
@SuppressWarnings("preview")
public void checkTags(Element element, Iterable<? extends DocTree> trees, boolean areInlineTags) {
if (trees == null) {
return;
@ -365,7 +366,7 @@ public class TagletManager {
if (element == null) {
return;
}
new SimpleElementVisitor9<Void, Void>() {
new SimpleElementVisitor14<Void, Void>() {
@Override
public Void visitModule(ModuleElement e, Void p) {
if (!taglet.inModule()) {
@ -521,6 +522,7 @@ public class TagletManager {
case INTERFACE:
case CLASS:
case ENUM:
case RECORD:
return blockTagletsBySite.get(Site.TYPE);
case MODULE:
return blockTagletsBySite.get(Site.MODULE);

View file

@ -26,7 +26,6 @@
package jdk.javadoc.internal.doclets.toolkit.taglets;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
@ -233,8 +232,8 @@ public abstract class TagletWriter {
tagletManager.checkTags(element, utils.getFullBody(element), true);
for (Taglet taglet : taglets) {
if (utils.isTypeElement(element) && taglet instanceof ParamTaglet) {
//The type parameters are documented in a special section away
//from the tag info, so skip here.
// The type parameters and state components are documented in a special
// section away from the tag info, so skip here.
continue;
}
if (taglet instanceof DeprecatedTaglet) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 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
@ -41,7 +41,7 @@ import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import javax.lang.model.util.SimpleTypeVisitor9;
import javax.lang.model.util.Types;
@ -483,8 +483,9 @@ public class ClassUseMapper {
private <T extends Element> void mapTypeParameters(final Map<TypeElement, List<T>> map,
Element element, final T holder) {
SimpleElementVisitor9<Void, Void> elementVisitor
= new SimpleElementVisitor9<Void, Void>() {
@SuppressWarnings("preview")
SimpleElementVisitor14<Void, Void> elementVisitor
= new SimpleElementVisitor14<Void, Void>() {
private void addParameters(TypeParameterElement e) {
for (TypeMirror type : utils.getBounds(e)) {
@ -560,9 +561,10 @@ public class ClassUseMapper {
* @param e whose type parameters are being checked.
* @param holder owning the type parameters.
*/
@SuppressWarnings("preview")
private <T extends Element> void mapAnnotations(final Map<TypeElement, List<T>> map,
Element e, final T holder) {
new SimpleElementVisitor9<Void, Void>() {
new SimpleElementVisitor14<Void, Void>() {
void addAnnotations(Element e) {
for (AnnotationMirror a : e.getAnnotationMirrors()) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -32,6 +32,7 @@ import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
@ -99,7 +100,7 @@ public class CommentHelper {
public void setOverrideElement(Element ove) {
if (this.element == ove) {
throw new AssertionError("cannot set given element as overriden element");
throw new AssertionError("cannot set given element as overridden element");
}
overriddenElement = ove;
}
@ -147,6 +148,9 @@ public class CommentHelper {
Element getElement(BaseConfiguration c, ReferenceTree rtree) {
// likely a synthesized tree
if (path == null) {
// NOTE: this code path only supports module/package/type signatures
// and not member signatures. For more complete support,
// set a suitable path and avoid this branch.
TypeMirror symbol = c.utils.getSymbol(rtree.getSignature());
if (symbol == null) {
return null;
@ -547,7 +551,7 @@ public class CommentHelper {
return new SimpleDocTreeVisitor<List<? extends DocTree>, Void>() {
List<? extends DocTree> asList(String content) {
List<DocTree> out = new ArrayList<>();
out.add((TextTree)c.cmtUtils.makeTextTree(content));
out.add(c.cmtUtils.makeTextTree(content));
return out;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -73,6 +73,11 @@ public class TypeElementCatalog {
*/
private final Map<PackageElement, SortedSet<TypeElement>> enums;
/**
* Stores records for each package.
*/
private final Map<PackageElement, SortedSet<TypeElement>> records;
/**
* Stores annotation types for each package.
*/
@ -116,6 +121,7 @@ public class TypeElementCatalog {
ordinaryClasses = new HashMap<>();
exceptions = new HashMap<>();
enums = new HashMap<>();
records = new HashMap<>();
annotationTypes = new HashMap<>();
errors = new HashMap<>();
interfaces = new HashMap<>();
@ -138,6 +144,8 @@ public class TypeElementCatalog {
addTypeElement(typeElement, exceptions);
} else if (utils.isEnum(typeElement)) {
addTypeElement(typeElement, enums);
} else if (utils.isRecord(typeElement)) {
addTypeElement(typeElement, records);
} else if (utils.isAnnotationType(typeElement)) {
addTypeElement(typeElement, annotationTypes);
} else if (utils.isError(typeElement)) {
@ -191,9 +199,7 @@ public class TypeElementCatalog {
}
/**
* Return all of the classes specified on the command-line that belong to the given package.
*
* @param packageName the name of the package specified on the command-line.
* Return all of the classes specified on the command-line that belong to the unnamed package.
*/
public SortedSet<TypeElement> allUnnamedClasses() {
for (PackageElement pkg : allClasses.keySet()) {
@ -214,7 +220,7 @@ public class TypeElementCatalog {
/**
* Return all of the errors specified on the command-line that belong to the given package.
*
* @param packageName the name of the package specified on the command-line.
* @param pkg the name of the package specified on the command-line.
*/
public SortedSet<TypeElement> errors(PackageElement pkg) {
return getSet(errors, pkg);
@ -223,7 +229,7 @@ public class TypeElementCatalog {
/**
* Return all of the exceptions specified on the command-line that belong to the given package.
*
* @param packageName the name of the package specified on the command-line.
* @param pkg the name of the package specified on the command-line.
*/
public SortedSet<TypeElement> exceptions(PackageElement pkg) {
return getSet(exceptions, pkg);
@ -232,17 +238,26 @@ public class TypeElementCatalog {
/**
* Return all of the enums specified on the command-line that belong to the given package.
*
* @param packageName the name of the package specified on the command-line.
* @param pkg the name of the package specified on the command-line.
*/
public SortedSet<TypeElement> enums(PackageElement pkg) {
return getSet(enums, pkg);
}
/**
* Return all of the records specified on the command-line that belong to the given package.
*
* @param pkg the name of the package specified on the command-line.
*/
public SortedSet<TypeElement> records(PackageElement pkg) {
return getSet(records, pkg);
}
/**
* Return all of the annotation types specified on the command-line that belong to the given
* package.
*
* @param packageName the name of the package specified on the command-line.
* @param pkg the name of the package specified on the command-line.
*/
public SortedSet<TypeElement> annotationTypes(PackageElement pkg) {
return getSet(annotationTypes, pkg);
@ -251,7 +266,7 @@ public class TypeElementCatalog {
/**
* Return all of the interfaces specified on the command-line that belong to the given package.
*
* @param packageName the name of the package specified on the command-line.
* @param pkg the name of the package specified on the command-line.
*/
public SortedSet<TypeElement> interfaces(PackageElement pkg) {
return getSet(interfaces, pkg);
@ -261,7 +276,7 @@ public class TypeElementCatalog {
* Return all of the ordinary classes specified on the command-line that belong to the given
* package.
*
* @param packageName the name of the package specified on the command-line.
* @param pkg the name of the package specified on the command-line.
*/
public SortedSet<TypeElement> ordinaryClasses(PackageElement pkg) {
return getSet(ordinaryClasses, pkg);

View file

@ -47,6 +47,7 @@ import javax.lang.model.element.Modifier;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.ModuleElement.RequiresDirective;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.RecordComponentElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
@ -60,9 +61,9 @@ import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.ElementKindVisitor9;
import javax.lang.model.util.ElementKindVisitor14;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import javax.lang.model.util.SimpleTypeVisitor9;
import javax.lang.model.util.TypeKindVisitor9;
import javax.lang.model.util.Types;
@ -301,8 +302,9 @@ public class Utils {
return !e.getAnnotationMirrors().isEmpty();
}
@SuppressWarnings("preview")
public boolean isAnnotationType(Element e) {
return new SimpleElementVisitor9<Boolean, Void>() {
return new SimpleElementVisitor14<Boolean, Void>() {
@Override
public Boolean visitExecutable(ExecutableElement e, Void p) {
return visit(e.getEnclosingElement());
@ -416,6 +418,34 @@ public class Utils {
return typeUtils.isSubtype(e.asType(), getExternalizableType());
}
@SuppressWarnings("preview")
public boolean isRecord(TypeElement e) {
return e.getKind() == ElementKind.RECORD;
}
@SuppressWarnings("preview")
public boolean isCanonicalRecordConstructor(ExecutableElement ee) {
TypeElement te = (TypeElement) ee.getEnclosingElement();
List<? extends RecordComponentElement> stateComps = te.getRecordComponents();
List<? extends VariableElement> params = ee.getParameters();
if (stateComps.size() != params.size()) {
return false;
}
Iterator<? extends RecordComponentElement> stateIter = stateComps.iterator();
Iterator<? extends VariableElement> paramIter = params.iterator();
while (paramIter.hasNext() && stateIter.hasNext()) {
VariableElement param = paramIter.next();
RecordComponentElement comp = stateIter.next();
if (!Objects.equals(param.getSimpleName(), comp.getSimpleName())
|| !typeUtils.isSameType(param.asType(), comp.asType())) {
return false;
}
}
return true;
}
public SortedSet<VariableElement> serializableFields(TypeElement aclass) {
return configuration.workArounds.getSerializableFields(aclass);
}
@ -428,85 +458,93 @@ public class Utils {
return configuration.workArounds.definesSerializableFields( aclass);
}
@SuppressWarnings("preview")
public String modifiersToString(Element e, boolean trailingSpace) {
SortedSet<Modifier> set = new TreeSet<>(e.getModifiers());
set.remove(Modifier.NATIVE);
set.remove(Modifier.STRICTFP);
set.remove(Modifier.SYNCHRONIZED);
SortedSet<Modifier> modifiers = new TreeSet<>(e.getModifiers());
modifiers.remove(NATIVE);
modifiers.remove(STRICTFP);
modifiers.remove(SYNCHRONIZED);
return new ElementKindVisitor9<String, SortedSet<Modifier>>() {
return new ElementKindVisitor14<String, SortedSet<Modifier>>() {
final StringBuilder sb = new StringBuilder();
void addVisibilityModifier(Set<Modifier> modifiers) {
if (modifiers.contains(PUBLIC)) {
sb.append("public").append(" ");
append("public");
} else if (modifiers.contains(PROTECTED)) {
sb.append("protected").append(" ");
append("protected");
} else if (modifiers.contains(PRIVATE)) {
sb.append("private").append(" ");
append("private");
}
}
void addStatic(Set<Modifier> modifiers) {
if (modifiers.contains(STATIC)) {
sb.append("static").append(" ");
append("static");
}
}
void addModifers(Set<Modifier> modifiers) {
String s = set.stream().map(Modifier::toString).collect(Collectors.joining(" "));
sb.append(s);
if (!s.isEmpty())
void addModifiers(Set<Modifier> modifiers) {
modifiers.stream().map(Modifier::toString).forEach(this::append);
}
void append(String s) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(s);
}
String finalString(String s) {
sb.append(s);
append(s);
if (trailingSpace) {
if (sb.lastIndexOf(" ") == sb.length() - 1) {
return sb.toString();
} else {
return sb.append(" ").toString();
sb.append(" ");
}
} else {
return sb.toString().trim();
}
return sb.toString();
}
@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);
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) {
addModifers(p);
return finalString("class");
public String visitTypeAsRecord(TypeElement e, SortedSet<Modifier> mods) {
mods.remove(FINAL); // suppress the implicit `final`
return visitTypeAsClass(e, mods);
}
@Override
protected String defaultAction(Element e, SortedSet<Modifier> p) {
addModifers(p);
@SuppressWarnings("preview")
public String visitTypeAsClass(TypeElement e, SortedSet<Modifier> mods) {
addModifiers(mods);
String keyword = e.getKind() == ElementKind.RECORD ? "record" : "class";
return finalString(keyword);
}
@Override
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) {
@ -593,7 +631,7 @@ public class Utils {
public boolean isTypeElement(Element e) {
switch (e.getKind()) {
case CLASS: case ENUM: case INTERFACE: case ANNOTATION_TYPE:
case CLASS: case ENUM: case INTERFACE: case ANNOTATION_TYPE: case RECORD:
return true;
default:
return false;
@ -1362,27 +1400,6 @@ public class Utils {
return sb;
}
/**
* The documentation for values() and valueOf() in Enums are set by the
* doclet only iff the user or overridden methods are missing.
* @param elem
*/
public void setEnumDocumentation(TypeElement elem) {
for (Element e : getMethods(elem)) {
ExecutableElement ee = (ExecutableElement)e;
if (!getFullBody(e).isEmpty()) // ignore if already set
continue;
if (ee.getSimpleName().contentEquals("values") && ee.getParameters().isEmpty()) {
removeCommentHelper(ee); // purge previous entry
configuration.cmtUtils.setEnumValuesTree(e);
}
if (ee.getSimpleName().contentEquals("valueOf") && ee.getParameters().size() == 1) {
removeCommentHelper(ee); // purge previous entry
configuration.cmtUtils.setEnumValueOfTree(e);
}
}
}
/**
* Returns a locale independent upper cased String. That is, it
* always uses US locale, this is a clone of the one in StringUtils.
@ -1760,7 +1777,7 @@ public class Utils {
result = compareStrings(getFullyQualifiedName(o1), getFullyQualifiedName(o2));
if (result != 0)
return result;
return compareElementTypeKinds(o1, o2);
return compareElementKinds(o1, o2);
}
};
}
@ -1809,7 +1826,7 @@ public class Utils {
return result;
}
// if names are the same, compare element kinds
result = compareElementTypeKinds(e1, e2);
result = compareElementKinds(e1, e2);
if (result != 0) {
return result;
}
@ -1917,8 +1934,9 @@ public class Utils {
return getFullyQualifiedName(e, true);
}
@SuppressWarnings("preview")
public String getFullyQualifiedName(Element e, final boolean outer) {
return new SimpleElementVisitor9<String, Void>() {
return new SimpleElementVisitor14<String, Void>() {
@Override
public String visitModule(ModuleElement e, Void p) {
return e.getQualifiedName().toString();
@ -1985,7 +2003,7 @@ public class Utils {
if (result != 0) {
return result;
}
return compareElementTypeKinds(e1, e2);
return compareElementKinds(e1, e2);
}
};
}
@ -1997,6 +2015,8 @@ public class Utils {
* 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.
@ -2005,21 +2025,6 @@ public class Utils {
* @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) {
@ -2082,12 +2087,31 @@ public class Utils {
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());
}
}
@SuppressWarnings("preview")
boolean hasParameters(Element e) {
return new SimpleElementVisitor9<Boolean, Void>() {
return new SimpleElementVisitor14<Boolean, Void>() {
@Override
public Boolean visitExecutable(ExecutableElement e, Void p) {
return true;
@ -2107,8 +2131,9 @@ public class Utils {
* @return a negative integer, zero, or a positive integer as the first argument is less
* than, equal to, or greater than the second.
*/
@SuppressWarnings("preview")
private String getFullyQualifiedName(Element e) {
return new SimpleElementVisitor9<String, Void>() {
return new SimpleElementVisitor14<String, Void>() {
@Override
public String visitModule(ModuleElement e, Void p) {
return e.getQualifiedName().toString();
@ -2187,6 +2212,7 @@ public class Utils {
out.addAll(getClasses(pkg));
out.addAll(getEnums(pkg));
out.addAll(getAnnotationTypes(pkg));
out.addAll(getRecords(pkg));
return out;
}
@ -2217,6 +2243,16 @@ public class Utils {
return convertToTypeElement(getItems(e, false, ANNOTATION_TYPE));
}
@SuppressWarnings("preview")
public List<TypeElement> getRecords(Element e) {
return convertToTypeElement(getItems(e, true, RECORD));
}
@SuppressWarnings("preview")
public List<TypeElement> getRecordsUnfiltered(Element e) {
return convertToTypeElement(getItems(e, false, RECORD));
}
public List<VariableElement> getFields(Element e) {
return convertToVariableElement(getItems(e, true, FIELD));
}
@ -2371,6 +2407,7 @@ public class Utils {
List<TypeElement> clist = getClassesUnfiltered(e);
clist.addAll(getInterfacesUnfiltered(e));
clist.addAll(getAnnotationTypesUnfiltered(e));
clist.addAll(getRecordsUnfiltered(e));
SortedSet<TypeElement> oset = new TreeSet<>(makeGeneralPurposeComparator());
oset.addAll(clist);
return oset;
@ -2391,6 +2428,7 @@ public class Utils {
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);
@ -2459,9 +2497,10 @@ public class Utils {
.collect(Collectors.toList());
}
@SuppressWarnings("preview")
List<Element> getItems(Element e, boolean filter, ElementKind select) {
List<Element> elements = new ArrayList<>();
return new SimpleElementVisitor9<List<Element>, Void>() {
return new SimpleElementVisitor14<List<Element>, Void>() {
@Override
public List<Element> visitPackage(PackageElement e, Void p) {
@ -2506,11 +2545,13 @@ public class Utils {
return elements;
}
private SimpleElementVisitor9<Boolean, Void> shouldDocumentVisitor = null;
@SuppressWarnings("preview")
private SimpleElementVisitor14<Boolean, Void> shouldDocumentVisitor = null;
protected boolean shouldDocument(Element e) {
@SuppressWarnings("preview")
public boolean shouldDocument(Element e) {
if (shouldDocumentVisitor == null) {
shouldDocumentVisitor = new SimpleElementVisitor9<Boolean, Void>() {
shouldDocumentVisitor = new SimpleElementVisitor14<Boolean, Void>() {
private boolean hasSource(TypeElement e) {
return configuration.docEnv.getFileKind(e) ==
javax.tools.JavaFileObject.Kind.SOURCE;
@ -2560,11 +2601,13 @@ public class Utils {
return nameCache.computeIfAbsent(e, this::getSimpleName0);
}
private SimpleElementVisitor9<String, Void> snvisitor = null;
@SuppressWarnings("preview")
private SimpleElementVisitor14<String, Void> snvisitor = null;
@SuppressWarnings("preview")
private String getSimpleName0(Element e) {
if (snvisitor == null) {
snvisitor = new SimpleElementVisitor9<String, Void>() {
snvisitor = new SimpleElementVisitor14<String, Void>() {
@Override
public String visitModule(ModuleElement e, Void p) {
return e.getQualifiedName().toString(); // temp fix for 8182736
@ -2745,10 +2788,12 @@ public class Utils {
return configuration.docEnv.isIncluded(e);
}
private SimpleElementVisitor9<Boolean, Void> specifiedVisitor = null;
@SuppressWarnings("preview")
private SimpleElementVisitor14<Boolean, Void> specifiedVisitor = null;
@SuppressWarnings("preview")
public boolean isSpecified(Element e) {
if (specifiedVisitor == null) {
specifiedVisitor = new SimpleElementVisitor9<Boolean, Void>() {
specifiedVisitor = new SimpleElementVisitor14<Boolean, Void>() {
@Override
public Boolean visitModule(ModuleElement e, Void p) {
return configuration.getSpecifiedModuleElements().contains(e);
@ -3196,20 +3241,20 @@ public class Utils {
return getBlockTags(element, DocTree.Kind.EXCEPTION, DocTree.Kind.THROWS);
}
public List<? extends DocTree> getTypeParamTrees(Element element) {
public List<? extends ParamTree> getTypeParamTrees(Element element) {
return getParamTrees(element, true);
}
public List<? extends DocTree> getParamTrees(Element element) {
public List<? extends ParamTree> getParamTrees(Element element) {
return getParamTrees(element, false);
}
private List<? extends DocTree> getParamTrees(Element element, boolean isTypeParameters) {
List<DocTree> out = new ArrayList<>();
private List<? extends ParamTree> getParamTrees(Element element, boolean isTypeParameters) {
List<ParamTree> out = new ArrayList<>();
for (DocTree dt : getBlockTags(element, PARAM)) {
ParamTree pt = (ParamTree) dt;
if (pt.isTypeParameter() == isTypeParameters) {
out.add(dt);
out.add(pt);
}
}
return out;

View file

@ -32,7 +32,7 @@ import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Collections;
@ -666,6 +666,7 @@ public class VisibleMemberTable {
case INTERFACE:
case ENUM:
case ANNOTATION_TYPE:
case RECORD:
addMember(e, Kind.INNER_CLASSES);
break;
case FIELD:
@ -700,8 +701,9 @@ public class VisibleMemberTable {
}
}
@SuppressWarnings("preview")
String getMemberKey(Element e) {
return new SimpleElementVisitor9<String, Void>() {
return new SimpleElementVisitor14<String, Void>() {
@Override
public String visitExecutable(ExecutableElement e, Void aVoid) {
return e.getSimpleName() + ":" + e.getParameters().size();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -47,7 +47,7 @@ import javax.lang.model.element.ModuleElement.RequiresDirective;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleElementVisitor14;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
@ -985,7 +985,8 @@ public class ElementsTable {
return (xclasses || toolEnv.getFileKind(te) == SOURCE) && isSelected(te);
}
SimpleElementVisitor9<Boolean, Void> visibleElementVisitor = null;
@SuppressWarnings("preview")
SimpleElementVisitor14<Boolean, Void> visibleElementVisitor = null;
/**
* Returns true if the element is selected, by applying
* the access filter checks. Special treatment is applied to
@ -996,12 +997,13 @@ public class ElementsTable {
* @param e the element to be checked
* @return true if the element is visible
*/
@SuppressWarnings("preview")
public boolean isSelected(Element e) {
if (toolEnv.isSynthetic((Symbol) e)) {
return false;
}
if (visibleElementVisitor == null) {
visibleElementVisitor = new SimpleElementVisitor9<Boolean, Void>() {
visibleElementVisitor = new SimpleElementVisitor14<Boolean, Void>() {
@Override
public Boolean visitType(TypeElement e, Void p) {
if (!accessFilter.checkModifier(e)) {
@ -1035,7 +1037,8 @@ public class ElementsTable {
return visibleElementVisitor.visit(e);
}
private class IncludedVisitor extends SimpleElementVisitor9<Boolean, Void> {
@SuppressWarnings("preview")
private class IncludedVisitor extends SimpleElementVisitor14<Boolean, Void> {
final private Set<Element> includedCache;
public IncludedVisitor() {
@ -1200,7 +1203,7 @@ public class ElementsTable {
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 +1288,7 @@ public class ElementsTable {
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:

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -31,7 +31,10 @@ import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.comp.MemberEnter;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Names;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.Kind.*;
@ -61,6 +64,7 @@ public class JavadocMemberEnter extends MemberEnter {
final ToolEnvironment toolEnv;
protected JavadocMemberEnter(Context context) {
super(context);
toolEnv = ToolEnvironment.instance(context);
@ -79,7 +83,12 @@ public class JavadocMemberEnter extends MemberEnter {
toolEnv.setElementToTreePath(meth, treePath);
}
// release resources
// handle constructors for record types specially, because of downstream checks
if ((env.enclClass.mods.flags & Flags.RECORD) != 0 && TreeInfo.isConstructor(tree)) {
tree.body.stats = List.nil();
} else {
tree.body = null;
}
}
@Override