diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java index 3f4bd418b05..daf0aabab27 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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,9 +31,9 @@ import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; +import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ModuleElement; @@ -48,15 +48,12 @@ import javax.tools.JavaFileManager.Location; import com.sun.source.util.TreePath; import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.Scope; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.ModuleSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; -import com.sun.tools.javac.comp.AttrContext; -import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Options; @@ -408,7 +405,7 @@ public class WorkArounds { * @param feature the name of the PreviewFeature.Feature enum value * @return the map of PreviewFeature.JEP annotation element values, or an empty map */ - public Map<? extends ExecutableElement, ? extends AnnotationValue> getJepInfo(String feature) { + public Map<String, Object> getJepInfo(String feature) { TypeElement featureType = elementUtils.getTypeElement("jdk.internal.javac.PreviewFeature.Feature"); TypeElement jepType = elementUtils.getTypeElement("jdk.internal.javac.PreviewFeature.JEP"); var featureVar = featureType.getEnclosedElements().stream() @@ -416,7 +413,11 @@ public class WorkArounds { if (featureVar.isPresent()) { for (AnnotationMirror anno : featureVar.get().getAnnotationMirrors()) { if (anno.getAnnotationType().asElement().equals(jepType)) { - return anno.getElementValues(); + return anno.getElementValues().entrySet() + .stream() + .collect(Collectors.toMap( + e -> e.getKey().getSimpleName().toString(), + e -> e.getValue().getValue())); } } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java index d6e8d127abf..781131234c6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ public class DeprecatedAPIListBuilder extends SummaryAPIListBuilder { * @param since list of releases passed via <code>--since</code> option */ public DeprecatedAPIListBuilder(BaseConfiguration configuration, List<String> since) { - super(configuration, configuration.utils::isDeprecated); + super(configuration); this.foundReleases = new HashSet<>(); buildSummaryAPIInfo(); // The releases list is set to the intersection of releases defined via `--since` option @@ -73,6 +73,11 @@ public class DeprecatedAPIListBuilder extends SummaryAPIListBuilder { return forRemoval; } + @Override + protected boolean belongsToSummary(Element element) { + return utils.isDeprecated(element); + } + @Override protected void handleElement(Element e) { foundReleases.add(utils.getDeprecatedSince(e)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/NewAPIBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/NewAPIBuilder.java index 0220f6155a3..962ad84bd03 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/NewAPIBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/NewAPIBuilder.java @@ -46,16 +46,17 @@ public class NewAPIBuilder extends SummaryAPIListBuilder { public final List<String> releases; public NewAPIBuilder(BaseConfiguration configuration, List<String> releases) { - super(configuration, element -> isNewAPI(element, configuration.utils, releases)); + super(configuration); this.releases = releases; buildSummaryAPIInfo(); } - private static boolean isNewAPI(Element e, Utils utils, List<String> releases) { - if (!utils.hasDocCommentTree(e)) { + @Override + protected boolean belongsToSummary(Element element) { + if (!utils.hasDocCommentTree(element)) { return false; } - var sinceTrees = utils.getBlockTags(e, SINCE, SinceTree.class); + var sinceTrees = utils.getBlockTags(element, SINCE, SinceTree.class); if (sinceTrees.isEmpty()) { return false; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/PreviewAPIListBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/PreviewAPIListBuilder.java index 65d0a50a4b6..e9e92c13e8f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/PreviewAPIListBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/PreviewAPIListBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -27,14 +27,13 @@ package jdk.javadoc.internal.doclets.toolkit.util; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; -import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; /** * Build list of all the preview packages, classes, constructors, fields and methods. @@ -43,6 +42,7 @@ public class PreviewAPIListBuilder extends SummaryAPIListBuilder { private final Map<Element, JEP> elementJeps = new HashMap<>(); private final Map<String, JEP> jeps = new HashMap<>(); + private static final JEP NULL_SENTINEL = new JEP(0, "", ""); /** * The JEP for a preview feature in this release. @@ -60,40 +60,51 @@ public class PreviewAPIListBuilder extends SummaryAPIListBuilder { * @param configuration the current configuration of the doclet */ public PreviewAPIListBuilder(BaseConfiguration configuration) { - super(configuration, configuration.utils::isPreviewAPI); + super(configuration); buildSummaryAPIInfo(); } @Override - protected void handleElement(Element e) { - String feature = Objects.requireNonNull(utils.getPreviewFeature(e), + protected boolean belongsToSummary(Element element) { + if (!utils.isPreviewAPI(element)) { + return false; + } + String feature = Objects.requireNonNull(utils.getPreviewFeature(element), "Preview feature not specified").toString(); - JEP jep = jeps.computeIfAbsent(feature, (featureName) -> { - Map<? extends ExecutableElement, ? extends AnnotationValue> anno = configuration.workArounds.getJepInfo(featureName); - int number = 0; - String title = ""; - String status = "Preview"; // Default value is not returned by the method we use above. - for (var entry : anno.entrySet()) { - if ("number".equals(entry.getKey().getSimpleName().toString())) { - number = (int) entry.getValue().getValue(); - } else if ("title".equals(entry.getKey().getSimpleName().toString())) { - title = (String) entry.getValue().getValue(); - } else if ("status".equals(entry.getKey().getSimpleName().toString())) { - status = (String) entry.getValue().getValue(); - } else { - throw new IllegalArgumentException(entry.getKey().getSimpleName().toString()); + JEP jep = jeps.computeIfAbsent(feature, featureName -> { + Map<String, Object> jepInfo = configuration.workArounds.getJepInfo(featureName); + if (!jepInfo.isEmpty()) { + int number = 0; + String title = ""; + String status = "Preview"; // Default value is not returned by the method we used above. + for (var entry : jepInfo.entrySet()) { + switch (entry.getKey()) { + case "number" -> number = (int) entry.getValue(); + case "title" -> title = (String) entry.getValue(); + case "status" -> status = (String) entry.getValue(); + default -> throw new IllegalArgumentException(entry.getKey()); + } } + return new JEP(number, title, status); } - return new JEP(number, title, status); + return NULL_SENTINEL; }); - elementJeps.put(e, jep); + if (jep != NULL_SENTINEL) { + elementJeps.put(element, jep); + return true; + } + // Preview features without JEP are not included. + return false; } /** * {@return a sorted set of preview feature JEPs in this release} */ public Set<JEP> getJEPs() { - return new TreeSet<>(jeps.values()); + return jeps.values() + .stream() + .filter(jep -> jep != NULL_SENTINEL) + .collect(Collectors.toCollection(TreeSet::new)); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/RestrictedAPIListBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/RestrictedAPIListBuilder.java index caf89cabebe..05ff0143298 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/RestrictedAPIListBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/RestrictedAPIListBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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,12 @@ public class RestrictedAPIListBuilder extends SummaryAPIListBuilder { * @param configuration the current configuration of the doclet */ public RestrictedAPIListBuilder(BaseConfiguration configuration) { - super(configuration, configuration.utils::isRestrictedAPI); + super(configuration); buildSummaryAPIInfo(); } + + @Override + protected boolean belongsToSummary(Element element) { + return utils.isRestrictedAPI(element); + } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java index 5125656c821..74f9fe97d7a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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,7 +26,6 @@ package jdk.javadoc.internal.doclets.toolkit.util; import java.util.*; -import java.util.function.Predicate; import javax.lang.model.element.Element; import javax.lang.model.element.ModuleElement; @@ -39,14 +38,13 @@ import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; /** * Build list of all the summary packages, classes, constructors, fields and methods. */ -public class SummaryAPIListBuilder { +public abstract class SummaryAPIListBuilder { /** * List of summary type Lists. */ private final Map<SummaryElementKind, SortedSet<Element>> summaryMap; protected final BaseConfiguration configuration; protected final Utils utils; - private final Predicate<Element> belongsToSummary; public enum SummaryElementKind { MODULE, @@ -69,11 +67,9 @@ public class SummaryAPIListBuilder { * * @param configuration the current configuration of the doclet */ - public SummaryAPIListBuilder(BaseConfiguration configuration, - Predicate<Element> belongsToSummary) { + protected SummaryAPIListBuilder(BaseConfiguration configuration) { this.configuration = configuration; this.utils = configuration.utils; - this.belongsToSummary = belongsToSummary; summaryMap = new EnumMap<>(SummaryElementKind.class); for (SummaryElementKind kind : SummaryElementKind.values()) { summaryMap.put(kind, createSummarySet()); @@ -93,7 +89,7 @@ public class SummaryAPIListBuilder { SortedSet<ModuleElement> modules = configuration.modules; SortedSet<Element> mset = summaryMap.get(SummaryElementKind.MODULE); for (Element me : modules) { - if (belongsToSummary.test(me)) { + if (belongsToSummary(me)) { mset.add(me); handleElement(me); } @@ -101,14 +97,14 @@ public class SummaryAPIListBuilder { SortedSet<PackageElement> packages = configuration.packages; SortedSet<Element> pset = summaryMap.get(SummaryElementKind.PACKAGE); for (Element pe : packages) { - if (belongsToSummary.test(pe)) { + if (belongsToSummary(pe)) { pset.add(pe); handleElement(pe); } } for (TypeElement te : configuration.getIncludedTypeElements()) { SortedSet<Element> eset; - if (belongsToSummary.test(te)) { + if (belongsToSummary(te)) { switch (te.getKind()) { case ANNOTATION_TYPE -> { eset = summaryMap.get(SummaryElementKind.ANNOTATION_TYPE); @@ -149,7 +145,7 @@ public class SummaryAPIListBuilder { } if (utils.isRecord(te)) { for (RecordComponentElement component : te.getRecordComponents()) { - if (belongsToSummary.test(component)) { + if (belongsToSummary(component)) { throw new AssertionError("record components not supported in summary builders: " + "component: " + component.getSimpleName() + " of record: " + te.getQualifiedName()); @@ -164,6 +160,14 @@ public class SummaryAPIListBuilder { } } + /** + * This method decides whether Element {@code element} should be included in this summary list. + * + * @param element an element + * @return true if the element should be included + */ + protected abstract boolean belongsToSummary(Element element); + /** * Add the members into a single list of summary members. * @@ -172,7 +176,7 @@ public class SummaryAPIListBuilder { */ private void composeSummaryList(SortedSet<Element> sset, List<? extends Element> members) { for (Element member : members) { - if (belongsToSummary.test(member)) { + if (belongsToSummary(member)) { sset.add(member); handleElement(member); } diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java index d5107f7598f..a59e68d25a0 100644 --- a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java +++ b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java @@ -24,6 +24,7 @@ /* * @test * @bug 8250768 8261976 8277300 8282452 8287597 8325325 8325874 8297879 + * 8331947 * @summary test generated docs for items declared using preview * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -156,6 +157,9 @@ public class TestPreview extends JavadocTester { <li><a href="package-summary.html">preview</a></li> <li><a href="Core.html" class="current-selection">Core</a></li> </ol>"""); + + // 8331947: Support preview features without JEP should not be included in Preview API page + checkOutput("preview-list.html", false, "supportMethod"); } @Test diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/NoPreview.java b/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/NoPreview.java index 951b557ce6d..b4ff5f0da00 100644 --- a/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/NoPreview.java +++ b/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/NoPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,4 +34,8 @@ public class NoPreview { @PreviewFeature(feature=Feature.TEST) public static class T {} + + // Preview support feature without JEP should not be listed + @PreviewFeature(feature=Feature.LANGUAGE_MODEL) + public void supportMethod() {} }