From 2155d525dd58fb8aa7a6709758d15c9dfa171941 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Thu, 18 Jun 2020 15:54:26 -0700 Subject: [PATCH 01/20] 8247880: bad HTML(href==...) in table Reviewed-by: lancea, darcy --- src/jdk.zipfs/share/classes/module-info.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.zipfs/share/classes/module-info.java b/src/jdk.zipfs/share/classes/module-info.java index f74a926c239..dcb2545b74a 100644 --- a/src/jdk.zipfs/share/classes/module-info.java +++ b/src/jdk.zipfs/share/classes/module-info.java @@ -234,9 +234,9 @@ import java.util.Set; * null/unset * * A value representing the version entry to use when accessing a - * + * * multi-release JAR. If the JAR is not a - * + * * multi-release JAR, the value will be ignored and the JAR will be * considered un-versioned. *

From 6c2c0563eb74a64059593ef5ca89265e3ba1b87e Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Thu, 18 Jun 2020 16:19:07 -0700 Subject: [PATCH 02/20] 8247894: Invalid @see in java.management Reviewed-by: mchung, darcy --- .../share/classes/java/lang/management/package.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.management/share/classes/java/lang/management/package.html b/src/java.management/share/classes/java/lang/management/package.html index ff95579fad9..c10a97618f3 100644 --- a/src/java.management/share/classes/java/lang/management/package.html +++ b/src/java.management/share/classes/java/lang/management/package.html @@ -234,7 +234,7 @@ java.lang.NullPointerException NullPointerException} to be thrown.

The java.lang.management API is thread-safe. -@see {@linkplain javax.management JMX Specification} +@see javax.management JMX Specification @author Mandy Chung @since 1.5 From 510354452f92dbb46d7451fd1c589e579f3951c5 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Thu, 18 Jun 2020 16:21:34 -0700 Subject: [PATCH 03/20] 8247896: Invalid (@throw) tags in 2 java.io classes Reviewed-by: mchung --- src/java.base/share/classes/java/io/PipedWriter.java | 2 +- src/java.base/share/classes/java/io/SequenceInputStream.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/io/PipedWriter.java b/src/java.base/share/classes/java/io/PipedWriter.java index a2489357f88..eb09adc8ce6 100644 --- a/src/java.base/share/classes/java/io/PipedWriter.java +++ b/src/java.base/share/classes/java/io/PipedWriter.java @@ -112,7 +112,7 @@ public class PipedWriter extends Writer { * Implements the {@code write} method of {@code Writer}. * * @param c the {@code char} to be written. - * @throw IOException if the pipe is + * @throws IOException if the pipe is * {@code broken}, * {@link #connect(java.io.PipedReader) unconnected}, closed * or an I/O error occurs. diff --git a/src/java.base/share/classes/java/io/SequenceInputStream.java b/src/java.base/share/classes/java/io/SequenceInputStream.java index 05f797fc9a0..441b4ad970c 100644 --- a/src/java.base/share/classes/java/io/SequenceInputStream.java +++ b/src/java.base/share/classes/java/io/SequenceInputStream.java @@ -121,7 +121,7 @@ public class SequenceInputStream extends InputStream { * skipped over) from the current underlying input stream * without blocking or {@code 0} if this input stream * has been closed by invoking its {@link #close()} method - * @throw IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @since 1.1 */ From e208d9aa1f185c11734a07db399bab0be77ef15f Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Thu, 18 Jun 2020 17:32:57 -0700 Subject: [PATCH 04/20] 8247899: HTML errors and warnings in threadPrimitiveDeprecation.html Reviewed-by: lancea --- .../java/lang/doc-files/threadPrimitiveDeprecation.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html b/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html index 9d69fc6a17f..a427266453b 100644 --- a/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html +++ b/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html @@ -282,7 +282,7 @@ The resulting run method is: } } -


+

Can I combine the two techniques to produce a thread that may be safely "stopped" or "suspended"?

Yes, it's reasonably straightforward. The one subtlety is that the @@ -324,6 +324,5 @@ If the stop method calls Thread.interrupt, as described above, it needn't call notify as well, but it still must be synchronized. This ensures that the target thread won't miss an interrupt due to a race condition. -

From bf1e6903a2499d0c2ab2f8703a1dc29046e8375d Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 18 Jun 2020 22:03:18 +0200 Subject: [PATCH 05/20] 8233014: Enable ShowCodeDetailsInExceptionMessages by default Reviewed-by: coleenp, stuefe, dholmes --- src/hotspot/share/runtime/globals.hpp | 2 +- .../NullPointerException/SuppressMessagesTest.java | 10 +++++----- test/hotspot/jtreg/vmTestbase/jit/t/t104/t104.gold | 2 +- test/langtools/jdk/jshell/ToolSimpleTest.java | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index d1ba6c1405f..0fa47b34c40 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -617,7 +617,7 @@ const size_t minimumSymbolTableSize = 1024; product(bool, OmitStackTraceInFastThrow, true, \ "Omit backtraces for some 'hot' exceptions in optimized code") \ \ - manageable(bool, ShowCodeDetailsInExceptionMessages, false, \ + manageable(bool, ShowCodeDetailsInExceptionMessages, true, \ "Show exception messages from RuntimeExceptions that contain " \ "snippets of the failing code. Disable this to improve privacy.") \ \ diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/SuppressMessagesTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/SuppressMessagesTest.java index b791d5872cb..b6d5acc7a46 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/SuppressMessagesTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/SuppressMessagesTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019 SAP SE. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020 SAP SE. 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 @@ -24,12 +24,12 @@ /** * @test - * @summary Test that the default of flag ShowCodeDetailsInExceptionMessages is 'false', - * i.e., make sure the VM does not print the message on default. + * @summary Test that the default of flag ShowCodeDetailsInExceptionMessages is 'true', + * i.e., make sure the VM does print the message by default. * @bug 8218628 * @library /test/lib * @compile -g SuppressMessagesTest.java - * @run main/othervm SuppressMessagesTest noMessage + * @run main/othervm SuppressMessagesTest printMessage */ /** * @test diff --git a/test/hotspot/jtreg/vmTestbase/jit/t/t104/t104.gold b/test/hotspot/jtreg/vmTestbase/jit/t/t104/t104.gold index e3a49f7ec64..64a23127c8b 100644 --- a/test/hotspot/jtreg/vmTestbase/jit/t/t104/t104.gold +++ b/test/hotspot/jtreg/vmTestbase/jit/t/t104/t104.gold @@ -1,2 +1,2 @@ Exception thrown. -java.lang.NullPointerException +java.lang.NullPointerException: Cannot enter synchronized block because "" is null diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index dc840d1445d..d51efae0703 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -132,7 +132,7 @@ public class ToolSimpleTest extends ReplToolTesting { + "| Caused by: java.io.IOException: bar\n" + "| at n (#2:1)\n" + "| ...\n" - + "| Caused by: java.lang.NullPointerException\n" + + "| Caused by: java.lang.NullPointerException: Cannot invoke \"String.toString()\" because \"null\" is null\n" + "| at p (#1:1)\n" + "| ..."), (a) -> assertCommand(a, "/drop p", From 326ba317872d377bee1ffcc6682e7bb5a85891d7 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 19 Jun 2020 11:32:51 +0200 Subject: [PATCH 06/20] 8237950: C2 compilation fails with "Live Node limit exceeded limit" during ConvI2L::Ideal optimization Postpone ConvI2L::Ideal optimization to IGVN. Reviewed-by: kvn, neliasso --- src/hotspot/share/opto/convertnode.cpp | 7 ++ .../stringopts/TestLongStringConcat.java | 81 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/stringopts/TestLongStringConcat.java diff --git a/src/hotspot/share/opto/convertnode.cpp b/src/hotspot/share/opto/convertnode.cpp index cf2af1f40f3..20de89a0d98 100644 --- a/src/hotspot/share/opto/convertnode.cpp +++ b/src/hotspot/share/opto/convertnode.cpp @@ -334,6 +334,13 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* z = in(1); int op = z->Opcode(); if (op == Op_AddI || op == Op_SubI) { + if (!can_reshape) { + // Postpone this optimization to after parsing because with deep AddNode + // chains a large amount of dead ConvI2L nodes might be created that are + // not removed during parsing. As a result, we might hit the node limit. + phase->record_for_igvn(this); + return this_changed; + } Node* x = z->in(1); Node* y = z->in(2); assert (x != z && y != z, "dead loop in ConvI2LNode::Ideal"); diff --git a/test/hotspot/jtreg/compiler/stringopts/TestLongStringConcat.java b/test/hotspot/jtreg/compiler/stringopts/TestLongStringConcat.java new file mode 100644 index 00000000000..a1cb9f774d1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/stringopts/TestLongStringConcat.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8237950 + * @summary Test very long chain of StringBuilder append calls. + * @run main/othervm -Xbatch compiler.stringopts.TestLongStringConcat + */ + +package compiler.stringopts; + +public class TestLongStringConcat { + + public static String test() { + return (new StringBuilder("")).append("1").append("2").append("3").append("4"). + append("5").append("6").append("7").append("8").append("9").append("10"). + append("11").append("12").append("13").append("14").append("15").append("16"). + append("17").append("18").append("19").append("20").append("21").append("22"). + append("23").append("24").append("25").append("26").append("27").append("28"). + append("29").append("30").append("31").append("32").append("33").append("34"). + append("35").append("36").append("37").append("38").append("39").append("40"). + append("41").append("42").append("43").append("44").append("45").append("46"). + append("47").append("48").append("49").append("50").append("51").append("52"). + append("53").append("54").append("55").append("56").append("57").append("58"). + append("59").append("60").append("61").append("62").append("63").append("64"). + append("65").append("66").append("67").append("68").append("69").append("70"). + append("71").append("72").append("73").append("74").append("75").append("76"). + append("77").append("78").append("79").append("80").append("81").append("82"). + append("83").append("84").append("85").append("86").append("87").append("88"). + append("89").append("90").append("91").append("92").append("93").append("94"). + append("95").append("96").append("97").append("98").append("99").append("100"). + append("101").append("102").append("103").append("104").append("105"). + append("106").append("107").append("108").append("109").append("110"). + append("111").append("112").append("113").append("114").append("115"). + append("116").append("117").append("118").append("119").append("120"). + append("121").append("122").append("123").append("124").append("125"). + append("126").append("127").append("128").append("129").append("130"). + append("131").append("132").append("133").append("134").append("135"). + append("136").append("137").append("138").append("139").append("140"). + append("141").append("142").append("143").append("144").append("145"). + append("146").append("147").append("148").append("149").append("150"). + append("151").append("152").append("153").append("154").append("155"). + append("156").append("157").append("158").append("159").append("160"). + append("161").append("162").append("163").append("164").append("165"). + append("166").append("167").append("168").append("169").append("170"). + append("171").append("172").append("173").append("174").append("175"). + append("176").append("177").append("178").append("179").append("180"). + append("181").append("182").append("183").append("184").append("185"). + append("186").append("187").append("188").append("189").append("190"). + append("191").append("192").append("193").append("194").append("195"). + append("196").append("197").append("198").append("199").append("200"). + toString(); + } + + public static void main(String[] args) { + for (int i = 0; i < 100_000; ++i) { + test(); + } + } +} From 5d1255bf5256413d5731c5c994d223a8bfacc38d Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Fri, 19 Jun 2020 11:52:01 +0100 Subject: [PATCH 07/20] 8246078: Javadoc Search specification link from Javadoc Help page points to JDK 13 spec Reviewed-by: jjg --- .../jdk/javadoc/internal/Versions.java | 108 ++++++++++++++++++ .../doclets/formats/html/HelpWriter.java | 2 +- .../formats/html/HtmlConfiguration.java | 29 +++-- .../formats/html/HtmlDocletWriter.java | 2 +- .../formats/html/IndexRedirectWriter.java | 2 +- .../formats/html/SourceToHTMLConverter.java | 2 +- .../doclets/toolkit/BaseConfiguration.java | 14 ++- .../jdk/javadoc/internal/tool/Start.java | 44 +++---- .../doclet/testHelpPage/TestHelpPage.java | 98 ++++++++++++++++ 9 files changed, 253 insertions(+), 48 deletions(-) create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/Versions.java create mode 100644 test/langtools/jdk/javadoc/doclet/testHelpPage/TestHelpPage.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/Versions.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/Versions.java new file mode 100644 index 00000000000..9d08ee670f6 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/Versions.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal; + +import java.util.ResourceBundle; + +import static java.util.ResourceBundle.getBundle; + +public final class Versions { + + private Versions() { throw new AssertionError(); } + + /** + * Returns the version of the {@code javadoc} tool and the Standard doclet. + * + *

This is typically the same as the version of the JDK platform being + * used to run the tool, but may be different when running the tool on an + * older version of the platform. + * + * @throws RuntimeException in an unlikely event of the version info + * not being available + * + * @apiNote This method does not return {@code null}, has the return type of + * {@code Optional}, or throw a checked exception. Those + * would warp the API to cater for something that is probably a result of + * a build error anyway. Hence, {@code RuntimeException}. + * + * @return the version + */ + public static Runtime.Version javadocVersion() throws RuntimeException { + /* + * The "jdk.javadoc.internal.tool.resources.version" resource bundle is + * non-localized and represented by a class compiled from a source like this: + * + * $ cat build/.../support/gensrc/jdk.javadoc/jdk/javadoc/internal/tool/resources/version.java + * package jdk.javadoc.internal.tool.resources; + * + * public final class version extends java.util.ListResourceBundle { + * protected final Object[][] getContents() { + * return new Object[][] { + * { "full", "15-internal+0-2020-06-02-1426246.duke..." }, + * { "jdk", "15" }, + * { "release", "15-internal" }, + * }; + * } + * } + * + * The string keyed by "full" should be parseable by Runtime.Version.parse() + */ + ResourceBundle bundle = getBundle("jdk.javadoc.internal.tool.resources.version"); + return Runtime.Version.parse(bundle.getString("full")); + } + + /** + * Returns a short string representation of the provided version. + * + *

Examples of strings returned from this method are: "15" and + * "15-internal". + * + * @return a short string representation of the provided version + * + * @throws NullPointerException if {@code v == null} + */ + public static String shortVersionStringOf(Runtime.Version v) { + String svstr = String.valueOf(v.feature()); + if (v.pre().isPresent()) { + svstr += "-" + v.pre().get(); + } + return svstr; + } + + /** + * Returns a full string representation of the provided version. + * + *

Examples of strings returned from this method are "14+36-1461" and + * "15-internal+0-2020-06-02-1426246.duke...". + * + * @return a full string representation of the provided version + * + * @throws NullPointerException if {@code v == null} + */ + public static String fullVersionStringOf(Runtime.Version v) { + return v.toString(); + } +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java index 5a961c692c7..56eee939d96 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java @@ -276,7 +276,7 @@ public class HelpWriter extends HtmlDocletWriter { HtmlTree.CODE(new StringContent(example[0])), example[1]))); } Content searchSpecLink = HtmlTree.A( - resources.getText("doclet.help.search.spec.url", Runtime.version().feature()), + resources.getText("doclet.help.search.spec.url", configuration.getDocletVersion().feature()), getContent("doclet.help.search.spec.title")); Content searchRefer = HtmlTree.P(getContent("doclet.help.search.refer", searchSpecLink)); section.add(searchIntro) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java index a189a431636..a055d21daa8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java @@ -42,6 +42,7 @@ import jdk.javadoc.doclet.DocletEnvironment; import jdk.javadoc.doclet.Reporter; import jdk.javadoc.doclet.StandardDoclet; import jdk.javadoc.doclet.Taglet; +import jdk.javadoc.internal.Versions; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.Messages; @@ -51,8 +52,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFile; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; -import static javax.tools.Diagnostic.Kind.*; - /** * Configure the output based on the command-line options. *

@@ -142,31 +141,29 @@ public class HtmlConfiguration extends BaseConfiguration { contents = new Contents(this); options = new HtmlOptions(this); - String v; + Runtime.Version v; try { - // the version bundle is not localized - ResourceBundle rb = ResourceBundle.getBundle(versionBundleName, Locale.getDefault()); - try { - v = rb.getString("release"); - } catch (MissingResourceException e) { - v = defaultDocletVersion; - } - } catch (MissingResourceException e) { - v = defaultDocletVersion; + v = Versions.javadocVersion(); + } catch (RuntimeException e) { + assert false : e; + v = Runtime.version(); // arguably, the only sensible default } docletVersion = v; } - private static final String versionBundleName = "jdk.javadoc.internal.tool.resources.version"; - private static final String defaultDocletVersion = System.getProperty("java.version"); - public final String docletVersion; + private final Runtime.Version docletVersion; public final Date startTime = new Date(); @Override - public String getDocletVersion() { + public Runtime.Version getDocletVersion() { return docletVersion; } + @Override + public String getDocletVersionString() { + return Versions.shortVersionStringOf(docletVersion); + } + @Override public Resources getDocResources() { return docResources; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index c8ec0e7e88f..26999451093 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -431,7 +431,7 @@ public class HtmlDocletWriter { Content htmlComment = contents.newPage; List additionalStylesheets = configuration.getAdditionalStylesheets(); additionalStylesheets.addAll(localStylesheets); - Head head = new Head(path, configuration.docletVersion, configuration.startTime) + Head head = new Head(path, configuration.getDocletVersionString(), configuration.startTime) .setTimestamp(!options.noTimestamp()) .setDescription(description) .setGenerator(getGenerator(getClass())) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java index 2794ca8c883..e9ace055240 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java @@ -75,7 +75,7 @@ public class IndexRedirectWriter extends HtmlDocletWriter { */ private void generateIndexFile() throws DocFileIOException { Content htmlComment = contents.newPage; - Head head = new Head(path, configuration.docletVersion, configuration.startTime) + Head head = new Head(path, configuration.getDocletVersionString(), configuration.startTime) .setTimestamp(!options.noTimestamp()) .setDescription("index redirect") .setGenerator(getGenerator(getClass())) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java index 5262a5ca144..f1c58b93957 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java @@ -235,7 +235,7 @@ public class SourceToHTMLConverter { * @param path the path for the file. */ private void writeToFile(Content body, DocPath path, TypeElement te) throws DocFileIOException { - Head head = new Head(path, configuration.docletVersion, configuration.startTime) + Head head = new Head(path, configuration.getDocletVersionString(), configuration.startTime) // .setTimestamp(!options.notimestamp) // temporary: compatibility! .setTitle(resources.getText("doclet.Window_Source_title")) // .setCharset(options.charset) // temporary: compatibility! diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java index c27710cc431..2f537fc6bc7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java @@ -151,11 +151,19 @@ public abstract class BaseConfiguration { public abstract Resources getDocResources(); /** - * Returns a string identifying the version of the doclet. + * Returns the version of the {@link #doclet doclet}. * - * @return a version string + * @return the version */ - public abstract String getDocletVersion(); + public abstract Runtime.Version getDocletVersion(); + + /** + * Returns a short string representation of the version returned by + * {@linkplain #getDocletVersion()}. + * + * @return a short string representation of the version + */ + public abstract String getDocletVersionString(); /** * This method should be defined in all those doclets (configurations), diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java index ef695034c0e..24cce42cf57 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java @@ -31,16 +31,14 @@ import java.io.PrintWriter; import java.text.BreakIterator; import java.text.Collator; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.IllformedLocaleException; import java.util.List; import java.util.Locale; -import java.util.MissingResourceException; import java.util.Objects; -import java.util.ResourceBundle; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import javax.tools.JavaFileManager; @@ -62,6 +60,7 @@ import jdk.javadoc.doclet.Doclet; import jdk.javadoc.doclet.Doclet.Option; import jdk.javadoc.doclet.DocletEnvironment; import jdk.javadoc.doclet.StandardDoclet; +import jdk.javadoc.internal.Versions; import jdk.javadoc.internal.tool.Main.Result; import jdk.javadoc.internal.tool.ToolOptions.ToolOption; @@ -167,17 +166,30 @@ public class Start { @Override public void version() { - showVersion("javadoc.version", "release"); + showVersion("javadoc.version", orDefault(() -> Versions.shortVersionStringOf(toolVersion()))); } @Override public void fullVersion() { - showVersion("javadoc.fullversion", "full"); + showVersion("javadoc.fullversion", orDefault(() -> Versions.fullVersionStringOf(toolVersion()))); + } + + private String orDefault(Supplier s) { + try { + return s.get(); + } catch (RuntimeException e) { + assert false : e; + return Log.getLocalizedString("version.not.available"); + } } }; return new ToolOptions(context, messager, helper); } + private Runtime.Version toolVersion() { + return Versions.javadocVersion(); + } + private void showUsage() { showUsage("main.usage", ToolOption.Kind.STANDARD, "main.usage.foot"); } @@ -196,26 +208,8 @@ public class Start { messager.notice(footerKey); } - private static final String versionRBName = "jdk.javadoc.internal.tool.resources.version"; - private static ResourceBundle versionRB; - - private void showVersion(String labelKey, String versionKey) { - messager.notice(labelKey, messager.programName, getVersion(versionKey)); - } - - private static String getVersion(String key) { - if (versionRB == null) { - try { - versionRB = ResourceBundle.getBundle(versionRBName); - } catch (MissingResourceException e) { - return Log.getLocalizedString("version.not.available"); - } - } - try { - return versionRB.getString(key); - } catch (MissingResourceException e) { - return Log.getLocalizedString("version.not.available"); - } + private void showVersion(String labelKey, String value) { + messager.notice(labelKey, messager.programName, value); } private void showToolOptions(ToolOption.Kind kind) { diff --git a/test/langtools/jdk/javadoc/doclet/testHelpPage/TestHelpPage.java b/test/langtools/jdk/javadoc/doclet/testHelpPage/TestHelpPage.java new file mode 100644 index 00000000000..a3ee65ac70d --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testHelpPage/TestHelpPage.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8246078 + * @library ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build javadoc.tester.* + * @run main TestHelpPage + */ + +import javadoc.tester.JavadocTester; + +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TestHelpPage extends JavadocTester { + + public static void main(String... args) throws Exception { + TestHelpPage tester = new TestHelpPage(); + tester.runTests(); + } + + @Test + public void test() { + + setOutputDirectoryCheck(DirectoryCheck.NONE); + setAutomaticCheckLinks(false); + setAutomaticCheckAccessibility(false); + + javadoc("--version"); + List lines = getOutputLines(Output.OUT); + System.out.println("lines: " + Arrays.toString(lines.toArray())); + String firstLine = lines.get(0); + Matcher m = Pattern.compile("javadoc\\s+(.*)").matcher(firstLine); + m.matches(); + String vstr = m.group(1); + System.out.printf("vstr='%s'%n", vstr); + Runtime.Version v = Runtime.Version.parse(vstr); + System.out.printf("v=%s, v.feature()=%s%n", v, v.feature()); + + javadoc("-d", "out", + "-sourcepath", testSrc, + testSrc("TestHelpPage.java")); + checkExit(Exit.OK); + + checking("Reference to a particular version"); + Pattern searchSpecLink = Pattern.compile( + "\\Q\\E"); + + String helpContents = readOutputFile("help-doc.html"); + Matcher m2 = searchSpecLink.matcher(helpContents); + if (!m2.find()) { + failed("Reference not found: " + helpContents); + return; + } + + if (!String.valueOf(v.feature()).equals(m2.group(1))) { + failed("Reference to a wrong version: " + m2.group(1)); + return; + } + + boolean foundMore = false; + while (m2.find()) { + // print all found before failing + foundMore = true; + System.out.println(m2.group(0)); + } + if (foundMore) { + failed("Multiple references: " + helpContents); + } else { + passed("All good"); + } + } +} From 226e85283103eca0ce26a85c1110a3660cca101a Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 19 Jun 2020 14:26:09 +0200 Subject: [PATCH 08/20] 8242214: NullPointerException in JDK 14 javac compiling a method reference Ensuring a proper receiver is used to invoke protected method when method reference is unrolled into a lambda. Reviewed-by: vromero --- .../sun/tools/javac/comp/LambdaToMethod.java | 18 +++++---- .../ProtectedInaccessibleMethodRefTest2.java | 37 +++++++++++++------ .../javac/lambda/methodReference/pack/I.java | 4 ++ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java index 2986bf1d60d..55e27282e46 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java @@ -999,7 +999,10 @@ public class LambdaToMethod extends TreeTranslator { private JCExpression makeReceiver(VarSymbol rcvr) { if (rcvr == null) return null; JCExpression rcvrExpr = make.Ident(rcvr); - Type rcvrType = tree.ownerAccessible ? tree.sym.enclClass().type : tree.expr.type; + boolean protAccess = + isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner); + Type rcvrType = tree.ownerAccessible && !protAccess ? tree.sym.enclClass().type + : tree.expr.type; if (rcvrType == syms.arrayClass.type) { // Map the receiver type to the actually type, not just "array" rcvrType = tree.getQualifierExpression().type; @@ -2270,11 +2273,6 @@ public class LambdaToMethod extends TreeTranslator { types.erasure(owner.enclClass().asType())); } - boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage() { - return ((tree.sym.flags() & PROTECTED) != 0 && - tree.sym.packge() != owner.packge()); - } - /** * Erasure destroys the implementation parameter subtype * relationship for intersection types. @@ -2311,7 +2309,7 @@ public class LambdaToMethod extends TreeTranslator { needsVarArgsConversion() || isArrayOp() || (!nestmateLambdas && isPrivateInOtherClass()) || - isProtectedInSuperClassOfEnclosingClassInOtherPackage() || + isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner) || !receiverAccessible() || (tree.getMode() == ReferenceMode.NEW && tree.kind != ReferenceKind.ARRAY_CTOR && @@ -2386,6 +2384,12 @@ public class LambdaToMethod extends TreeTranslator { } } + private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference, + Symbol currentClass) { + return ((targetReference.flags() & PROTECTED) != 0 && + targetReference.packge() != currentClass.packge()); + } + /** * Signature Generation */ diff --git a/test/langtools/tools/javac/lambda/methodReference/ProtectedInaccessibleMethodRefTest2.java b/test/langtools/tools/javac/lambda/methodReference/ProtectedInaccessibleMethodRefTest2.java index aa17b0d8530..02e1d95cf2f 100644 --- a/test/langtools/tools/javac/lambda/methodReference/ProtectedInaccessibleMethodRefTest2.java +++ b/test/langtools/tools/javac/lambda/methodReference/ProtectedInaccessibleMethodRefTest2.java @@ -23,45 +23,58 @@ /* * @test - * @bug 8234729 + * @bug 8234729 8242214 * @summary Javac should eagerly change code generation for method references to avert IllegalAccessError in future. + * @compile ProtectedInaccessibleMethodRefTest2.java * @run main ProtectedInaccessibleMethodRefTest2 */ import pack.I; import pack.J; +import java.lang.reflect.Method; import java.nio.file.Path; import java.nio.file.Paths; import java.util.function.Function; -import java.lang.reflect.Method; -import java.util.concurrent.Callable; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.BiFunction; public final class ProtectedInaccessibleMethodRefTest2 extends I { public static void main(String... args) { ProtectedInaccessibleMethodRefTest2 m = new ProtectedInaccessibleMethodRefTest2(); m.test(Paths.get("test")); - // Verify that the method reference has been folded into a lambda. - boolean lambdaFound = false; + // Verify that the method references have been folded into lambdas: + Set methodNames = new HashSet<>(); for (Method meth : ProtectedInaccessibleMethodRefTest2.class.getDeclaredMethods()) { - if (meth.getName().equals("lambda$test$0")) { - lambdaFound = true; - break; - } + methodNames.add(meth.getName()); } - if (!lambdaFound) { + List expectedMethods = + Arrays.asList("lambda$test$0", "lambda$test$1", "lambda$test$2"); + if (!methodNames.containsAll(expectedMethods)) { throw new AssertionError("Did not find evidence of new code generation"); } } void test(Path outputDir) { - Sub c = new Sub(this::readFile); - c.check(outputDir); + Sub c1 = new Sub(this::readFile); + c1.check(outputDir); + Sub c2 = new Sub(ProtectedInaccessibleMethodRefTest2::readFile, this); + c2.check(outputDir); + Sub c3 = new Sub(ProtectedInaccessibleMethodRefTest2::readFile2); + c3.check(outputDir); } + public class Sub extends J { Sub(Function fileReader) { super(fileReader); } + Sub(BiFunction fileReader, + ProtectedInaccessibleMethodRefTest2 instance) { + super(p -> fileReader.apply(instance, p)); + } } } diff --git a/test/langtools/tools/javac/lambda/methodReference/pack/I.java b/test/langtools/tools/javac/lambda/methodReference/pack/I.java index 02f6356a786..018ed463d92 100644 --- a/test/langtools/tools/javac/lambda/methodReference/pack/I.java +++ b/test/langtools/tools/javac/lambda/methodReference/pack/I.java @@ -29,4 +29,8 @@ public class I { protected String readFile(Path file) { return file.toString(); } + + protected static String readFile2(Path file) { + return file.toString(); + } } From ffbee17d8a50d779dc8af4df5a59d67be81fa286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 19 Jun 2020 17:17:40 +0200 Subject: [PATCH 09/20] 8198705: Javadoc search needs a fix to handle duplicate package names in different modules Reviewed-by: jjg --- .../formats/html/AbstractIndexWriter.java | 21 +++++++-- .../doclets/formats/html/SearchIndexItem.java | 10 ++++- .../doclets/formats/html/resources/search.js | 43 +++++++++++-------- .../doclets/toolkit/util/IndexItem.java | 11 ++++- .../testModules/TestModulePackages.java | 10 ++++- .../javadoc/doclet/testSearch/TestSearch.java | 18 ++++---- 6 files changed, 79 insertions(+), 34 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java index 41262280e82..50a11e061db 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java @@ -27,6 +27,7 @@ package jdk.javadoc.internal.doclets.formats.html; import java.io.IOException; import java.io.Writer; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -105,8 +106,12 @@ public class AbstractIndexWriter extends HtmlDocletWriter { addHeading(uc, contentTree); HtmlTree dl = HtmlTree.DL(HtmlStyle.index); + Map duplicateLabelCheck = new HashMap<>(); + memberlist.forEach(e -> duplicateLabelCheck.compute(e.getFullyQualifiedLabel(utils), + (k, v) -> v == null ? 1 : v + 1)); for (IndexItem indexItem : memberlist) { - addDescription(indexItem, dl); + addDescription(indexItem, dl, + duplicateLabelCheck.get(indexItem.getFullyQualifiedLabel(utils)) > 1); } contentTree.add(dl); } @@ -120,14 +125,14 @@ public class AbstractIndexWriter extends HtmlDocletWriter { contentTree.add(heading); } - protected void addDescription(IndexItem indexItem, Content dl) { + protected void addDescription(IndexItem indexItem, Content dl, boolean addModuleInfo) { SearchIndexItem si = indexItem.getSearchTag(); if (si != null) { addDescription(si, dl); } else { si = new SearchIndexItem(); si.setLabel(indexItem.getLabel()); - addElementDescription(indexItem, dl, si); + addElementDescription(indexItem, dl, si, addModuleInfo); searchItems.add(si); } } @@ -138,8 +143,10 @@ public class AbstractIndexWriter extends HtmlDocletWriter { * @param indexItem the element to be documented * @param dlTree the content tree to which the description will be added * @param si the search index item + * @param addModuleInfo whether to include module information */ - protected void addElementDescription(IndexItem indexItem, Content dlTree, SearchIndexItem si) { + protected void addElementDescription(IndexItem indexItem, Content dlTree, SearchIndexItem si, + boolean addModuleInfo) { Content dt; Element element = indexItem.getElement(); String label = indexItem.getLabel(); @@ -165,6 +172,9 @@ public class AbstractIndexWriter extends HtmlDocletWriter { dt = HtmlTree.DT(getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.INDEX, (TypeElement)element).strong(true))); si.setContainingPackage(utils.getPackageName(utils.containingPackage(element))); + if (configuration.showModules && addModuleInfo) { + si.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element))); + } si.setCategory(Category.TYPES); dt.add(" - "); addClassInfo((TypeElement)element, dt); @@ -175,6 +185,9 @@ public class AbstractIndexWriter extends HtmlDocletWriter { getDocLink(LinkInfoImpl.Kind.INDEX, containingType, element, new StringContent(label)))); si.setContainingPackage(utils.getPackageName(utils.containingPackage(element))); si.setContainingClass(utils.getSimpleName(containingType)); + if (configuration.showModules && addModuleInfo) { + si.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element))); + } if (utils.isExecutableElement(element)) { String url = HtmlTree.encodeURL(links.getName(getAnchor((ExecutableElement)element))); if (!label.equals(url)) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchIndexItem.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchIndexItem.java index a5043d8492d..0f2c6181d00 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchIndexItem.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchIndexItem.java @@ -148,6 +148,9 @@ public class SearchIndexItem { if (!containingPackage.isEmpty()) { item.append("\"p\":\"").append(containingPackage).append("\","); } + if (!containingModule.isEmpty()) { + item.append("\"m\":\"").append(containingModule).append("\","); + } item.append("\"l\":\"").append(label).append("\""); if (!url.isEmpty()) { item.append(",\"u\":\"").append(url).append("\""); @@ -155,8 +158,11 @@ public class SearchIndexItem { item.append("}"); break; case MEMBERS: - item.append("{") - .append("\"p\":\"").append(containingPackage).append("\",") + item.append("{"); + if (!containingModule.isEmpty()) { + item.append("\"m\":\"").append(containingModule).append("\","); + } + item.append("\"p\":\"").append(containingPackage).append("\",") .append("\"c\":\"").append(containingClass).append("\",") .append("\"l\":\"").append(label).append("\""); if (!url.isEmpty()) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js index 9a684ca1b55..c4e4e8b6c84 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js @@ -34,6 +34,7 @@ var searchPattern = ""; var RANKING_THRESHOLD = 2; var NO_MATCH = 0xffff; var MAX_RESULTS_PER_CATEGORY = 500; +var UNNAMED = ""; function escapeHtml(str) { return str.replace(//g, ">"); } @@ -48,14 +49,16 @@ function getURLPrefix(ui) { return ui.item.l + slash; } else if (ui.item.category === catPackages && ui.item.m) { return ui.item.m + slash; - } else if ((ui.item.category === catTypes && ui.item.p) || ui.item.category === catMembers) { - $.each(packageSearchIndex, function(index, item) { - if (item.m && ui.item.p == item.l) { - urlPrefix = item.m + slash; - } - }); - return urlPrefix; - } else { + } else if (ui.item.category === catTypes || ui.item.category === catMembers) { + if (ui.item.m) { + urlPrefix = ui.item.m + slash; + } else { + $.each(packageSearchIndex, function(index, item) { + if (item.m && ui.item.p === item.l) { + urlPrefix = item.m + slash; + } + }); + } return urlPrefix; } return urlPrefix; @@ -121,7 +124,7 @@ $.widget("custom.catcomplete", $.ui.autocomplete, { rMenu.menu.bindings = $(); $.each(items, function(index, item) { var li; - if (item.l !== noResult.l && item.category !== currentCategory) { + if (item.category && item.category !== currentCategory) { ul.append("

  • " + item.category + "
  • "); currentCategory = item.category; } @@ -141,15 +144,15 @@ $.widget("custom.catcomplete", $.ui.autocomplete, { if (item.category === catModules) { label = getHighlightedText(item.l, matcher); } else if (item.category === catPackages) { - label = (item.m) - ? getHighlightedText(item.m + "/" + item.l, matcher) - : getHighlightedText(item.l, matcher); + label = getHighlightedText(item.l, matcher); } else if (item.category === catTypes) { - label = (item.p) + label = (item.p && item.p !== UNNAMED) ? getHighlightedText(item.p + "." + item.l, matcher) : getHighlightedText(item.l, matcher); } else if (item.category === catMembers) { - label = getHighlightedText(item.p + "." + (item.c + "." + item.l), matcher); + label = (item.p && item.p !== UNNAMED) + ? getHighlightedText(item.p + "." + item.c + "." + item.l, matcher) + : getHighlightedText(item.c + "." + item.l, matcher); } else if (item.category === catSearchTags) { label = getHighlightedText(item.l, matcher); } else { @@ -165,7 +168,11 @@ $.widget("custom.catcomplete", $.ui.autocomplete, { div.html(label + " (" + item.h + ")"); } } else { - div.html(label); + if (item.m) { + div.html(item.m + "/" + label); + } else { + div.html(label); + } } return li; } @@ -317,7 +324,7 @@ $(function() { collision: "flip" }, select: function(event, ui) { - if (ui.item.l !== noResult.l) { + if (ui.item.category) { var url = getURLPrefix(ui); if (ui.item.category === catModules) { url += "module-summary.html"; @@ -330,13 +337,13 @@ $(function() { } else if (ui.item.category === catTypes) { if (ui.item.u) { url = ui.item.u; - } else if (ui.item.p === "") { + } else if (ui.item.p === UNNAMED) { url += ui.item.l + ".html"; } else { url += ui.item.p.replace(/\./g, '/') + "/" + ui.item.l + ".html"; } } else if (ui.item.category === catMembers) { - if (ui.item.p === "") { + if (ui.item.p === UNNAMED) { url += ui.item.c + ".html" + "#"; } else { url += ui.item.p.replace(/\./g, '/') + "/" + ui.item.c + ".html" + "#"; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexItem.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexItem.java index d88d1fa4e13..75e818c8d24 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexItem.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexItem.java @@ -26,7 +26,6 @@ package jdk.javadoc.internal.doclets.toolkit.util; import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem; -import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -90,6 +89,16 @@ public class IndexItem { return label; } + public String getFullyQualifiedLabel(Utils utils) { + if (typeElement != null) { + return utils.getFullyQualifiedName(typeElement) + "." + label; + } else if (element != null) { + return utils.getFullyQualifiedName(element); + } else { + return label; + } + } + public Element getElement() { return element; } diff --git a/test/langtools/jdk/javadoc/doclet/testModules/TestModulePackages.java b/test/langtools/jdk/javadoc/doclet/testModules/TestModulePackages.java index 324f13b9d01..a416b697844 100644 --- a/test/langtools/jdk/javadoc/doclet/testModules/TestModulePackages.java +++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModulePackages.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8178070 8196201 8184205 8246429 + * @bug 8178070 8196201 8184205 8246429 8198705 * @summary Test packages table in module summary pages * @library /tools/lib ../../lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -167,6 +167,14 @@ public class TestModulePackages extends JavadocTester {
    Package p
    """); + checkOutput("type-search-index.js", true, + """ + {"p":"p","m":"m","l":"C"},{"p":"p","m":"o","l":"C"}"""); + checkOutput("member-search-index.js", true, + """ + {"m":"m","p":"p","c":"C","l":"C()","u":"%3Cinit%3E()"}""", + """ + {"m":"o","p":"p","c":"C","l":"C()","u":"%3Cinit%3E()"}"""); } @Test diff --git a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java index c97128c8ad9..18dd2b1c462 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java +++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java @@ -726,14 +726,16 @@ public class TestSearch extends JavadocTester { return ui.item.l + slash; } else if (ui.item.category === catPackages && ui.item.m) { return ui.item.m + slash; - } else if ((ui.item.category === catTypes && ui.item.p) || ui.item.category === catMembers) { - $.each(packageSearchIndex, function(index, item) { - if (item.m && ui.item.p == item.l) { - urlPrefix = item.m + slash; - } - }); - return urlPrefix; - } else { + } else if (ui.item.category === catTypes || ui.item.category === catMembers) { + if (ui.item.m) { + urlPrefix = ui.item.m + slash; + } else { + $.each(packageSearchIndex, function(index, item) { + if (item.m && ui.item.p === item.l) { + urlPrefix = item.m + slash; + } + }); + } return urlPrefix; } return urlPrefix; From 983e012c9f4593b25a3c5874a23b829af92a26e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 19 Jun 2020 17:24:46 +0200 Subject: [PATCH 10/20] 8241969: Type annotation is not shown for wildcard type in Javadoc Reviewed-by: jjg --- .../toolkit/util/links/LinkFactory.java | 3 +- .../TestTypeAnnotations.java | 31 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/links/LinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/links/LinkFactory.java index cc6deb73720..261c2d53886 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/links/LinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/links/LinkFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, 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 @@ -109,6 +109,7 @@ public abstract class LinkFactory { @Override public Content visitWildcard(WildcardType type, LinkInfo linkInfo) { linkInfo.isTypeBound = true; + link.add(getTypeAnnotationLinks(linkInfo)); link.add("?"); TypeMirror extendsBound = type.getExtendsBound(); if (extendsBound != null) { diff --git a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java index d29adf5622d..83b70b37f86 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java @@ -24,7 +24,7 @@ /* * @test * @bug 8005091 8009686 8025633 8026567 6469562 8071982 8071984 8162363 8175200 8186332 8182765 - * 8187288 + * 8187288 8241969 * @summary Make sure that type annotations are displayed correctly * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -335,6 +335,35 @@ public class TestTypeAnnotations extends JavadocTester { tation in typeannos">@WldB("m") java.lang.String> returnWcExtends()"""); + checkOutput("typeannos/SelfTest.html", true, + """ +
    MyList<@WldA ?> returnWcExtends\ + ()
    """, + """ +
    MyList<@WldA ? extends @WldA MyList<@WldB("m") ?>>&\ + nbsp;complex()
    """); + + checkOutput("typeannos/SelfWithValue.html", true, + """ +
    MyList<@WldB("m") ?> returnWcEx\ + tends()
    """, + """ +
    MyList<@WldB("m") ? extends MyList<@WldB\ + ("m") ? super java.lang.String>> com\ + plex()
    """); + + // Test for receiver annotations (Receivers.java). checkOutput("typeannos/DefaultUnmodified.html", true, """ From f2b191a6e94bd39f83a1be4dd75283ea777c9e30 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Fri, 19 Jun 2020 08:27:59 -0700 Subject: [PATCH 11/20] 8247444: Trust final fields in records Co-authored-by: Christoph Dreis Reviewed-by: jrose, dholmes, forax, coleenp, vlivanov --- src/hotspot/share/ci/ciField.cpp | 3 + src/hotspot/share/ci/ciInstanceKlass.cpp | 2 + src/hotspot/share/ci/ciInstanceKlass.hpp | 5 ++ src/hotspot/share/classfile/javaClasses.cpp | 6 ++ src/hotspot/share/classfile/javaClasses.hpp | 4 + src/hotspot/share/classfile/vmSymbols.hpp | 1 + src/hotspot/share/prims/methodHandles.cpp | 6 +- src/hotspot/share/runtime/fieldDescriptor.cpp | 5 ++ src/hotspot/share/runtime/fieldDescriptor.hpp | 2 + src/hotspot/share/runtime/reflection.cpp | 3 + .../classes/java/lang/invoke/MemberName.java | 7 +- .../java/lang/invoke/MethodHandleNatives.java | 1 + .../java/lang/invoke/MethodHandles.java | 10 +-- .../java/lang/reflect/AccessibleObject.java | 14 +++- .../classes/java/lang/reflect/Field.java | 15 +++- .../java/lang/reflect/ReflectAccess.java | 6 +- .../access/JavaLangReflectAccess.java | 5 +- .../jdk/internal/reflect/Reflection.java | 9 +++ .../internal/reflect/ReflectionFactory.java | 4 +- .../reflect/UnsafeFieldAccessorFactory.java | 3 +- .../share/classes/sun/misc/Unsafe.java | 23 +++++- .../src => unreflect}/Fields.java | 0 .../lang/invoke/unreflect/TEST.properties | 24 ++++++ .../UnreflectTest.java | 25 ++++++- .../reflect/records/RecordReflectionTest.java | 19 ++++- test/jdk/sun/misc/UnsafeFieldOffsets.java | 74 ++++++++++++++----- 26 files changed, 227 insertions(+), 49 deletions(-) rename test/jdk/java/lang/invoke/{defineHiddenClass/src => unreflect}/Fields.java (100%) create mode 100644 test/jdk/java/lang/invoke/unreflect/TEST.properties rename test/jdk/java/lang/invoke/{defineHiddenClass => unreflect}/UnreflectTest.java (86%) diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index c75433a4d57..949213d3290 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -231,6 +231,9 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) { // Trust final fields in all boxed classes if (holder->is_box_klass()) return true; + // Trust final fields in records + if (holder->is_record()) + return true; // Trust final fields in String if (holder->name() == ciSymbol::java_lang_String()) return true; diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index 987e001b424..4fb1be82e98 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -64,6 +64,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) : _has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods(); _is_unsafe_anonymous = ik->is_unsafe_anonymous(); _is_hidden = ik->is_hidden(); + _is_record = ik->is_record(); _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields: _has_injected_fields = -1; _implementor = NULL; // we will fill these lazily @@ -125,6 +126,7 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name, _has_injected_fields = -1; _is_unsafe_anonymous = false; _is_hidden = false; + _is_record = false; _loader = loader; _protection_domain = protection_domain; _is_shared = false; diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index 9ecc3da6e03..d03ecdc3a87 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -57,6 +57,7 @@ private: bool _has_nonstatic_concrete_methods; bool _is_unsafe_anonymous; bool _is_hidden; + bool _is_record; ciFlags _flags; jint _nonstatic_field_size; @@ -200,6 +201,10 @@ public: return _is_hidden; } + bool is_record() const { + return _is_record; + } + ciInstanceKlass* get_canonical_holder(int offset); ciField* get_field_by_offset(int field_offset, bool is_static); ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index d5ae4a06c5a..ca1f1f0d71d 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -3141,6 +3141,7 @@ int java_lang_reflect_Field::_name_offset; int java_lang_reflect_Field::_type_offset; int java_lang_reflect_Field::_slot_offset; int java_lang_reflect_Field::_modifiers_offset; +int java_lang_reflect_Field::_trusted_final_offset; int java_lang_reflect_Field::_signature_offset; int java_lang_reflect_Field::_annotations_offset; @@ -3150,6 +3151,7 @@ int java_lang_reflect_Field::_annotations_offset; macro(_type_offset, k, vmSymbols::type_name(), class_signature, false); \ macro(_slot_offset, k, vmSymbols::slot_name(), int_signature, false); \ macro(_modifiers_offset, k, vmSymbols::modifiers_name(), int_signature, false); \ + macro(_trusted_final_offset, k, vmSymbols::trusted_final_name(), bool_signature, false); \ macro(_signature_offset, k, vmSymbols::signature_name(), string_signature, false); \ macro(_annotations_offset, k, vmSymbols::annotations_name(), byte_array_signature, false); @@ -3214,6 +3216,10 @@ void java_lang_reflect_Field::set_modifiers(oop field, int value) { field->int_field_put(_modifiers_offset, value); } +void java_lang_reflect_Field::set_trusted_final(oop field) { + field->bool_field_put(_trusted_final_offset, true); +} + void java_lang_reflect_Field::set_signature(oop field, oop value) { field->obj_field_put(_signature_offset, value); } diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index c219abc954a..e33391c63e0 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -696,6 +696,7 @@ class java_lang_reflect_Field : public java_lang_reflect_AccessibleObject { static int _type_offset; static int _slot_offset; static int _modifiers_offset; + static int _trusted_final_offset; static int _signature_offset; static int _annotations_offset; @@ -723,6 +724,8 @@ class java_lang_reflect_Field : public java_lang_reflect_AccessibleObject { static int modifiers(oop field); static void set_modifiers(oop field, int value); + static void set_trusted_final(oop field); + static void set_signature(oop constructor, oop value); static void set_annotations(oop constructor, oop value); static void set_parameter_annotations(oop method, oop value); @@ -1121,6 +1124,7 @@ class java_lang_invoke_MemberName: AllStatic { MN_IS_FIELD = 0x00040000, // field MN_IS_TYPE = 0x00080000, // nested type MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected + MN_TRUSTED_FINAL = 0x00200000, // trusted final field MN_REFERENCE_KIND_SHIFT = 24, // refKind MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT, // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers: diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 13e5dd640ad..28cb9bae2e2 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -266,6 +266,7 @@ template(returnType_name, "returnType") \ template(signature_name, "signature") \ template(slot_name, "slot") \ + template(trusted_final_name, "trustedFinal") \ \ /* Support for annotations (JDK 1.5 and above) */ \ \ diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 7516ff594a5..5eebb5c2fce 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -126,6 +126,7 @@ enum { IS_FIELD = java_lang_invoke_MemberName::MN_IS_FIELD, IS_TYPE = java_lang_invoke_MemberName::MN_IS_TYPE, CALLER_SENSITIVE = java_lang_invoke_MemberName::MN_CALLER_SENSITIVE, + TRUSTED_FINAL = java_lang_invoke_MemberName::MN_TRUSTED_FINAL, REFERENCE_KIND_SHIFT = java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT, REFERENCE_KIND_MASK = java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK, SEARCH_SUPERCLASSES = java_lang_invoke_MemberName::MN_SEARCH_SUPERCLASSES, @@ -339,8 +340,10 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) { } oop MethodHandles::init_field_MemberName(Handle mname, fieldDescriptor& fd, bool is_setter) { + InstanceKlass* ik = fd.field_holder(); int flags = (jushort)( fd.access_flags().as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS ); flags |= IS_FIELD | ((fd.is_static() ? JVM_REF_getStatic : JVM_REF_getField) << REFERENCE_KIND_SHIFT); + if (fd.is_trusted_final()) flags |= TRUSTED_FINAL; if (is_setter) flags += ((JVM_REF_putField - JVM_REF_getField) << REFERENCE_KIND_SHIFT); int vmindex = fd.offset(); // determines the field uniquely when combined with static bit @@ -348,7 +351,7 @@ oop MethodHandles::init_field_MemberName(Handle mname, fieldDescriptor& fd, bool java_lang_invoke_MemberName::set_flags (mname_oop, flags); java_lang_invoke_MemberName::set_method (mname_oop, NULL); java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex); - java_lang_invoke_MemberName::set_clazz (mname_oop, fd.field_holder()->java_mirror()); + java_lang_invoke_MemberName::set_clazz (mname_oop, ik->java_mirror()); oop type = field_signature_type_or_null(fd.signature()); oop name = field_name_or_null(fd.name()); @@ -1107,6 +1110,7 @@ void MethodHandles::trace_method_handle_interpreter_entry(MacroAssembler* _masm, template(java_lang_invoke_MemberName,MN_IS_FIELD) \ template(java_lang_invoke_MemberName,MN_IS_TYPE) \ template(java_lang_invoke_MemberName,MN_CALLER_SENSITIVE) \ + template(java_lang_invoke_MemberName,MN_TRUSTED_FINAL) \ template(java_lang_invoke_MemberName,MN_SEARCH_SUPERCLASSES) \ template(java_lang_invoke_MemberName,MN_SEARCH_INTERFACES) \ template(java_lang_invoke_MemberName,MN_REFERENCE_KIND_SHIFT) \ diff --git a/src/hotspot/share/runtime/fieldDescriptor.cpp b/src/hotspot/share/runtime/fieldDescriptor.cpp index 6123a502848..e3be65c6cca 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.cpp +++ b/src/hotspot/share/runtime/fieldDescriptor.cpp @@ -58,6 +58,11 @@ Symbol* fieldDescriptor::generic_signature() const { return NULL; } +bool fieldDescriptor::is_trusted_final() const { + InstanceKlass* ik = field_holder(); + return is_final() && (is_static() || ik->is_hidden() || ik->is_record()); +} + AnnotationArray* fieldDescriptor::annotations() const { InstanceKlass* ik = field_holder(); Array* md = ik->fields_annotations(); diff --git a/src/hotspot/share/runtime/fieldDescriptor.hpp b/src/hotspot/share/runtime/fieldDescriptor.hpp index 189f785bb4c..a2594a5ef29 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.hpp +++ b/src/hotspot/share/runtime/fieldDescriptor.hpp @@ -102,6 +102,8 @@ class fieldDescriptor { bool has_initialized_final_update() const { return access_flags().has_field_initialized_final_update(); } bool has_generic_signature() const { return access_flags().field_has_generic_signature(); } + bool is_trusted_final() const; + inline void set_is_field_access_watched(const bool value); inline void set_is_field_modification_watched(const bool value); inline void set_has_initialized_final_update(const bool value); diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index e9366f8fa18..02e7b1973fa 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -897,6 +897,9 @@ oop Reflection::new_field(fieldDescriptor* fd, TRAPS) { java_lang_reflect_Field::set_slot(rh(), fd->index()); java_lang_reflect_Field::set_name(rh(), name()); java_lang_reflect_Field::set_type(rh(), type()); + if (fd->is_trusted_final()) { + java_lang_reflect_Field::set_trusted_final(rh()); + } // Note the ACC_ANNOTATION bit, which is a per-class access flag, is never set here. java_lang_reflect_Field::set_modifiers(rh(), fd->access_flags().as_int() & JVM_RECOGNIZED_FIELD_MODIFIERS); java_lang_reflect_Field::set_override(rh(), false); diff --git a/src/java.base/share/classes/java/lang/invoke/MemberName.java b/src/java.base/share/classes/java/lang/invoke/MemberName.java index dbd8d746830..afbb9ae636d 100644 --- a/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2020, 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 @@ -480,7 +480,8 @@ final class MemberName implements Member, Cloneable { IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor IS_FIELD = MN_IS_FIELD, // field IS_TYPE = MN_IS_TYPE, // nested type - CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected + CALLER_SENSITIVE = MN_CALLER_SENSITIVE, // @CallerSensitive annotation detected + TRUSTED_FINAL = MN_TRUSTED_FINAL; // trusted final field static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE; @@ -520,6 +521,8 @@ final class MemberName implements Member, Cloneable { public boolean isCallerSensitive() { return testAllFlags(CALLER_SENSITIVE); } + /** Query whether this member is a trusted final field. */ + public boolean isTrustedFinalField() { return testAllFlags(TRUSTED_FINAL|IS_FIELD); } /** Utility method to query whether this member is accessible from a given lookup class. */ public boolean isAccessibleFrom(Class lookupClass) { diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java index ca161156c74..ff87bcedcaf 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -118,6 +118,7 @@ class MethodHandleNatives { MN_IS_FIELD = 0x00040000, // field MN_IS_TYPE = 0x00080000, // nested type MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected + MN_TRUSTED_FINAL = 0x00200000, // trusted final field MN_REFERENCE_KIND_SHIFT = 24, // refKind MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT, // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers: diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 23f31cc6b85..4038f5841d7 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -3273,10 +3273,10 @@ return mh1; private MethodHandle unreflectField(Field f, boolean isSetter) throws IllegalAccessException { MemberName field = new MemberName(f, isSetter); if (isSetter && field.isFinal()) { - if (field.isStatic()) { - throw field.makeAccessException("static final field has no write access", this); - } else if (field.getDeclaringClass().isHidden()){ - throw field.makeAccessException("final field in a hidden class has no write access", this); + if (field.isTrustedFinalField()) { + String msg = field.isStatic() ? "static final field has no write access" + : "final field has no write access"; + throw field.makeAccessException(msg, this); } } assert(isSetter @@ -3839,7 +3839,7 @@ return mh1; refc = lookupClass(); } return VarHandles.makeFieldHandle(getField, refc, getField.getFieldType(), - this.allowedModes == TRUSTED && !getField.getDeclaringClass().isHidden()); + this.allowedModes == TRUSTED && !getField.isTrustedFinalField()); } /** Check access and get the requested constructor. */ private MethodHandle getDirectConstructor(Class refc, MemberName ctor) throws IllegalAccessException { diff --git a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java index 4707276c720..3db39d8e92c 100644 --- a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java +++ b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java @@ -177,10 +177,16 @@ public class AccessibleObject implements AnnotatedElement { * to the caller's module.

    * *

    This method cannot be used to enable {@linkplain Field#set write} - * access to a final field declared in a {@linkplain Class#isHidden() hidden class}, - * since such fields are not modifiable. The {@code accessible} flag when - * {@code true} suppresses Java language access control checks to only - * enable {@linkplain Field#get read} access to such fields. + * access to a non-modifiable final field. The following fields + * are non-modifiable: + *

      + *
    • static final fields declared in any class or interface
    • + *
    • final fields declared in a {@linkplain Class#isHidden() hidden class}
    • + *
    • final fields declared in a {@linkplain Class#isRecord() record}
    • + *
    + *

    The {@code accessible} flag when {@code true} suppresses Java language access + * control checks to only enable {@linkplain Field#get read} access to + * these non-modifiable final fields. * *

    If there is a security manager, its * {@code checkPermission} method is first called with a diff --git a/src/java.base/share/classes/java/lang/reflect/Field.java b/src/java.base/share/classes/java/lang/reflect/Field.java index 5589dc7bb7b..75bf314c5e0 100644 --- a/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/src/java.base/share/classes/java/lang/reflect/Field.java @@ -72,6 +72,7 @@ class Field extends AccessibleObject implements Member { private String name; private Class type; private int modifiers; + private boolean trustedFinal; // Generics and annotations support private transient String signature; // generic info repository; lazily initialized @@ -119,6 +120,7 @@ class Field extends AccessibleObject implements Member { String name, Class type, int modifiers, + boolean trustedFinal, int slot, String signature, byte[] annotations) @@ -127,6 +129,7 @@ class Field extends AccessibleObject implements Member { this.name = name; this.type = type; this.modifiers = modifiers; + this.trustedFinal = trustedFinal; this.slot = slot; this.signature = signature; this.annotations = annotations; @@ -148,7 +151,7 @@ class Field extends AccessibleObject implements Member { if (this.root != null) throw new IllegalArgumentException("Can not copy a non-root Field"); - Field res = new Field(clazz, name, type, modifiers, slot, signature, annotations); + Field res = new Field(clazz, name, type, modifiers, trustedFinal, slot, signature, annotations); res.root = this; // Might as well eagerly propagate this if already present res.fieldAccessor = fieldAccessor; @@ -728,7 +731,9 @@ class Field extends AccessibleObject implements Member { * this {@code Field} object; *

  • the field is non-static; and
  • *
  • the field's declaring class is not a {@linkplain Class#isHidden() - * hidden class}.
  • + * hidden class}; and + *
  • the field's declaring class is not a {@linkplain Class#isRecord() + * record class}.
  • * * If any of the above checks is not met, this method throws an * {@code IllegalAccessException}. @@ -1145,10 +1150,14 @@ class Field extends AccessibleObject implements Member { } @Override - Field getRoot() { + /* package-private */ Field getRoot() { return root; } + /* package-private */ boolean isTrustedFinal() { + return trustedFinal; + } + /** * {@inheritDoc} * diff --git a/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java b/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java index 2ed950cc76f..6ac890156b0 100644 --- a/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java +++ b/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, 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 @@ -118,6 +118,10 @@ class ReflectAccess implements jdk.internal.access.JavaLangReflectAccess { return (T) obj.getRoot(); } + public boolean isTrustedFinalField(Field f) { + return f.isTrustedFinal(); + } + public T newInstance(Constructor ctor, Object[] args, Class caller) throws IllegalAccessException, InstantiationException, InvocationTargetException { diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java index 8e537b68cbf..4082fae336f 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, 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 @@ -96,6 +96,9 @@ public interface JavaLangReflectAccess { /** Gets the root of the given AccessibleObject object; null if arg is the root */ public T getRoot(T obj); + /** Tests if this is a trusted final field */ + public boolean isTrustedFinalField(Field f); + /** Returns a new instance created by the given constructor with access check */ public T newInstance(Constructor ctor, Object[] args, Class caller) throws IllegalAccessException, InstantiationException, InvocationTargetException; diff --git a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index 3152089a272..410297cac0b 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import jdk.internal.HotSpotIntrinsicCandidate; +import jdk.internal.access.SharedSecrets; import jdk.internal.misc.VM; /** Common utility routines used by both java.lang and @@ -336,6 +337,14 @@ public class Reflection { return false; } + /* + * Tests if the given Field is a trusted final field and it cannot be + * modified reflectively regardless of the value of its accessible flag. + */ + public static boolean isTrustedFinalField(Field field) { + return SharedSecrets.getJavaLangReflectAccess().isTrustedFinalField(field); + } + /** * Returns an IllegalAccessException with an exception message based on * the access that is denied. diff --git a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java index 2a7728df542..4f344d22a8f 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -181,7 +181,9 @@ public class ReflectionFactory { field = root; } } - return UnsafeFieldAccessorFactory.newFieldAccessor(field, override); + boolean isFinal = Modifier.isFinal(field.getModifiers()); + boolean isReadOnly = isFinal && (!override || langReflectAccess.isTrustedFinalField(field)); + return UnsafeFieldAccessorFactory.newFieldAccessor(field, isReadOnly); } public MethodAccessor newMethodAccessor(Method method) { diff --git a/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorFactory.java b/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorFactory.java index ba292087bfd..d13043ce988 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorFactory.java +++ b/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorFactory.java @@ -29,13 +29,12 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; class UnsafeFieldAccessorFactory { - static FieldAccessor newFieldAccessor(Field field, boolean override) { + static FieldAccessor newFieldAccessor(Field field, boolean isReadOnly) { Class type = field.getType(); boolean isStatic = Modifier.isStatic(field.getModifiers()); boolean isFinal = Modifier.isFinal(field.getModifiers()); boolean isVolatile = Modifier.isVolatile(field.getModifiers()); boolean isQualified = isFinal || isVolatile; - boolean isReadOnly = isFinal && (isStatic || !override || field.getDeclaringClass().isHidden()); if (isStatic) { // This code path does not guarantee that the field's // declaring class has been initialized, but it must be diff --git a/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java b/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java index cbdeddbfba4..d8074ddcbea 100644 --- a/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java +++ b/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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 @@ -636,13 +636,18 @@ public final class Unsafe { * @see #getInt(Object, long) */ @ForceInline + @SuppressWarnings("preview") public long objectFieldOffset(Field f) { if (f == null) { throw new NullPointerException(); } - if (f.getDeclaringClass().isHidden()) { + Class declaringClass = f.getDeclaringClass(); + if (declaringClass.isHidden()) { throw new UnsupportedOperationException("can't get field offset on a hidden class: " + f); } + if (declaringClass.isRecord()) { + throw new UnsupportedOperationException("can't get field offset on a record (preview): " + f); + } return theInternalUnsafe.objectFieldOffset(f); } @@ -664,13 +669,18 @@ public final class Unsafe { * @see #getInt(Object, long) */ @ForceInline + @SuppressWarnings("preview") public long staticFieldOffset(Field f) { if (f == null) { throw new NullPointerException(); } - if (f.getDeclaringClass().isHidden()) { + Class declaringClass = f.getDeclaringClass(); + if (declaringClass.isHidden()) { throw new UnsupportedOperationException("can't get field offset on a hidden class: " + f); } + if (declaringClass.isRecord()) { + throw new UnsupportedOperationException("can't get field offset on a record (preview): " + f); + } return theInternalUnsafe.staticFieldOffset(f); } @@ -685,13 +695,18 @@ public final class Unsafe { * this class. */ @ForceInline + @SuppressWarnings("preview") public Object staticFieldBase(Field f) { if (f == null) { throw new NullPointerException(); } - if (f.getDeclaringClass().isHidden()) { + Class declaringClass = f.getDeclaringClass(); + if (declaringClass.isHidden()) { throw new UnsupportedOperationException("can't get base address on a hidden class: " + f); } + if (declaringClass.isRecord()) { + throw new UnsupportedOperationException("can't get base address on a record (preview): " + f); + } return theInternalUnsafe.staticFieldBase(f); } diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/src/Fields.java b/test/jdk/java/lang/invoke/unreflect/Fields.java similarity index 100% rename from test/jdk/java/lang/invoke/defineHiddenClass/src/Fields.java rename to test/jdk/java/lang/invoke/unreflect/Fields.java diff --git a/test/jdk/java/lang/invoke/unreflect/TEST.properties b/test/jdk/java/lang/invoke/unreflect/TEST.properties new file mode 100644 index 00000000000..2ab57ceb5d6 --- /dev/null +++ b/test/jdk/java/lang/invoke/unreflect/TEST.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +enablePreview=true diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/UnreflectTest.java b/test/jdk/java/lang/invoke/unreflect/UnreflectTest.java similarity index 86% rename from test/jdk/java/lang/invoke/defineHiddenClass/UnreflectTest.java rename to test/jdk/java/lang/invoke/unreflect/UnreflectTest.java index f1bf40c7906..206287c57c6 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/UnreflectTest.java +++ b/test/jdk/java/lang/invoke/unreflect/UnreflectTest.java @@ -23,9 +23,10 @@ /** * @test - * @compile src/Fields.java - * @run testng/othervm UnreflectTest - * @summary Test Lookup::unreflectSetter and Lookup::unreflectVarHandle + * @bug 8238358 8247444 + * @run testng/othervm --enable-preview UnreflectTest + * @summary Test Lookup::unreflectSetter and Lookup::unreflectVarHandle on + * trusted final fields (declared in hidden classes and records) */ import java.io.IOException; @@ -89,6 +90,24 @@ public class UnreflectTest { readWriteAccessibleObject(hiddenClass, "NON_FINAL", o, false); } + static record TestRecord(int i) { + static final Object STATIC_FINAL = new Object(); + static Object STATIC_NON_FINAL = new Object(); + } + + /* + * Test Lookup::unreflectSetter and Lookup::unreflectVarHandle that + * cannot write the value of a non-static final field in a record class + */ + @SuppressWarnings("preview") + public void testFieldsInRecordClass() throws Throwable { + assertTrue(TestRecord.class.isRecord()); + Object o = new TestRecord(1); + readOnlyAccessibleObject(TestRecord.class, "STATIC_FINAL", null, true); + readWriteAccessibleObject(TestRecord.class, "STATIC_NON_FINAL", null, false); + readOnlyAccessibleObject(TestRecord.class, "i", o, true); + } + /* * Verify read-only access via unreflectSetter and unreflectVarHandle */ diff --git a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java index 2ad1547b575..b121bac5ef5 100644 --- a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java +++ b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8235369 8235550 + * @bug 8235369 8235550 8247444 * @summary reflection test for records * @compile --enable-preview -source ${jdk.version} RecordReflectionTest.java * @run testng/othervm --enable-preview RecordReflectionTest @@ -187,4 +187,19 @@ public class RecordReflectionTest { assertEquals(f.getAnnotatedType().getAnnotations().length, 1); assertEquals(f.getAnnotatedType().getAnnotations()[0].toString(), annos[0].toString()); } + + public void testReadOnlyFieldInRecord() throws Throwable { + R2 o = new R2(1, 2); + Class recordClass = R2.class; + String fieldName = "i"; + Field f = recordClass.getDeclaredField(fieldName); + assertTrue(f.trySetAccessible()); + assertTrue(f.get(o) != null); + try { + f.set(o, null); + assertTrue(false, "should fail to set " + fieldName); + } catch (IllegalAccessException e) { + } + } + } diff --git a/test/jdk/sun/misc/UnsafeFieldOffsets.java b/test/jdk/sun/misc/UnsafeFieldOffsets.java index aeaa92206a9..e2c63c350f4 100644 --- a/test/jdk/sun/misc/UnsafeFieldOffsets.java +++ b/test/jdk/sun/misc/UnsafeFieldOffsets.java @@ -22,10 +22,12 @@ */ /* @test + * @bug 8238358 8247444 * @summary Ensure that sun.misc.Unsafe::objectFieldOffset and staticFieldOffset - * throw UnsupportedOperationException on Field of a hidden class + * throw UnsupportedOperationException on Field of a hidden or record class * @modules jdk.unsupported - * @run main UnsafeFieldOffsets + * @compile --enable-preview -source ${jdk.version} UnsafeFieldOffsets.java + * @run testng/othervm --enable-preview UnsafeFieldOffsets */ import sun.misc.Unsafe; @@ -38,6 +40,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + public class UnsafeFieldOffsets { static class Fields { static final Object STATIC_FINAL = new Object(); @@ -45,9 +50,14 @@ public class UnsafeFieldOffsets { final Object FINAL = new Object(); Object NON_FINAL = new Object(); } + record TestRecord(int i) { + static final Object STATIC_FINAL = new Object(); + static Object STATIC_NON_FINAL = new Object(); + } private static Unsafe UNSAFE = getUnsafe(); private static final Class HIDDEN_CLASS = defineHiddenClass(); + private static final Class RECORD_CLASS = TestRecord.class; private static Unsafe getUnsafe() { try { @@ -65,7 +75,7 @@ public class UnsafeFieldOffsets { try { byte[] bytes = Files.readAllBytes(cf); Class c = MethodHandles.lookup().defineHiddenClass(bytes, true).lookupClass(); - assertHiddenClass(c); + assertTrue(c.isHidden()); return c; } catch (IOException e) { throw new UncheckedIOException(e); @@ -74,13 +84,8 @@ public class UnsafeFieldOffsets { } } - public static void main(String[] args) throws Exception { - // non-hidden class - testStaticField(Fields.class, "STATIC_FINAL"); - testStaticField(Fields.class, "STATIC_NON_FINAL"); - testInstanceField(Fields.class, "FINAL"); - testInstanceField(Fields.class, "NON_FINAL"); - + @Test + public void testNormalClass() throws Throwable { // hidden class testStaticField(HIDDEN_CLASS, "STATIC_FINAL"); testStaticField(HIDDEN_CLASS, "STATIC_NON_FINAL"); @@ -88,13 +93,30 @@ public class UnsafeFieldOffsets { testInstanceField(HIDDEN_CLASS, "NON_FINAL"); } + @Test + public void testHiddenClass() throws Throwable { + // hidden class + testStaticField(HIDDEN_CLASS, "STATIC_FINAL"); + testStaticField(HIDDEN_CLASS, "STATIC_NON_FINAL"); + testInstanceField(HIDDEN_CLASS, "FINAL"); + testInstanceField(HIDDEN_CLASS, "NON_FINAL"); + } + + @Test + public void testRecordClass() throws Throwable { + // record class + testRecordStaticField(RECORD_CLASS, "STATIC_FINAL"); + testRecordStaticField(RECORD_CLASS, "STATIC_NON_FINAL"); + testRecordInstanceField(RECORD_CLASS, "i"); + } + private static void testStaticField(Class c, String name) throws Exception { Field f = c.getDeclaredField(name); try { UNSAFE.staticFieldOffset(f); - assertNonHiddenClass(c); + assertFalse(c.isHidden(), "Expected UOE thrown: " + c); } catch (UnsupportedOperationException e) { - assertHiddenClass(c); + assertTrue(c.isHidden(), "Expected hidden class: " + c); } } @@ -102,19 +124,31 @@ public class UnsafeFieldOffsets { Field f = c.getDeclaredField(name); try { UNSAFE.objectFieldOffset(f); - assertNonHiddenClass(c); + assertFalse(c.isHidden(), "Expected UOE thrown: " + c); } catch (UnsupportedOperationException e) { - assertHiddenClass(c); + assertTrue(c.isHidden(), "Expected hidden class: " + c); } } - private static void assertNonHiddenClass(Class c) { - if (c.isHidden()) - throw new RuntimeException("Expected UOE but not thrown: " + c); + @SuppressWarnings("preview") + private static void testRecordStaticField(Class c, String name) throws Exception { + Field f = c.getDeclaredField(name); + try { + UNSAFE.staticFieldOffset(f); + assertFalse(c.isRecord(), "Expected UOE thrown: " + c); + } catch (UnsupportedOperationException e) { + assertTrue(c.isRecord(), "Expected record class: " + c); + } } - private static void assertHiddenClass(Class c) { - if (!c.isHidden()) - throw new RuntimeException("Expected hidden class but is not: " + c); + @SuppressWarnings("preview") + private static void testRecordInstanceField(Class c, String name) throws Exception { + Field f = c.getDeclaredField(name); + try { + UNSAFE.objectFieldOffset(f); + assertFalse(c.isRecord(), "Expected UOE thrown: " + c); + } catch (UnsupportedOperationException e) { + assertTrue(c.isRecord(), "Expected record class: " + c); + } } } From 9d40d80237b0dc854e9f8a0d9408c4834df040a6 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Fri, 19 Jun 2020 16:42:52 +0100 Subject: [PATCH 12/20] 8247780: Refine the Help page for API Documentation Reviewed-by: jjg --- .../doclets/formats/html/resources/standard.properties | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index 063cbaef5e1..a3356bdb1fa 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -144,7 +144,7 @@ doclet.help.package.intro=\ each. These pages may contain six categories: doclet.help.module.intro=\ Each module has a page that contains a list of its packages, dependencies on other modules, \ - and services, with a summary for each. These page may contain three categories: + and services, with a summary for each. These pages may contain three categories: doclet.help.class_interface.head=\ Class or Interface doclet.help.class_interface.intro=\ @@ -164,7 +164,6 @@ doclet.help.class_interface.declaration=\ doclet.help.class_interface.description=\ Class or Interface Description doclet.help.class_interface.summary=\ - Each summary entry contains the first sentence from the detailed description for that item. \ The summary entries are alphabetical, while the detailed descriptions are in the order they \ appear in the source code. This preserves the logical groupings established by the programmer. doclet.help.use.head=\ @@ -189,7 +188,7 @@ doclet.help.tree.package=\ hierarchy for only that package. doclet.help.deprecated.body=\ The {0} page lists all of the API that have been deprecated. A deprecated API is not \ - recommended for use, generally due to improvements, and a replacement API is usually given. \ + recommended for use, generally due to shortcomings, and a replacement API is usually given. \ Deprecated APIs may be removed in future implementations. doclet.help.index.head=\ Index @@ -198,9 +197,9 @@ doclet.help.index.body=\ and fields, as well as lists of all packages and all classes. doclet.help.serial_form.body=\ Each serializable or externalizable class has a description of its serialization fields and \ - methods. This information is of interest to re-implementors, not to developers using the API. \ + methods. This information is of interest to those who implement rather than use the API. \ While there is no link in the navigation bar, you can get to this information by going to any \ - serialized class and clicking "Serialized Form" in the "See also" section of the class \ + serialized class and clicking "Serialized Form" in the "See Also" section of the class \ description. doclet.help.constants.body=\ The {0} page lists the static final fields and their values. From 2e6923ffd6d5e466669ebdba60a4b5fa74473b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 19 Jun 2020 18:21:08 +0200 Subject: [PATCH 13/20] 8243533: Only one of several deprecated overloaded methods listed in the Deprecated list Reviewed-by: jjg --- .../formats/html/DeprecatedListWriter.java | 3 - .../doclets/toolkit/util/Comparators.java | 68 ++++++++----- .../TestDeprecatedDocs.java | 97 ++++++++++++++++++- .../testDeprecatedDocs/pkg/TestClass.java | 18 +++- 4 files changed, 154 insertions(+), 32 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java index 7613136899f..b9a6fc52922 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java @@ -205,8 +205,6 @@ public class DeprecatedListWriter extends SubWriterHolderWriter { private EnumMap writerMap; - private HtmlConfiguration configuration; - private final Navigation navBar; /** @@ -218,7 +216,6 @@ public class DeprecatedListWriter extends SubWriterHolderWriter { public DeprecatedListWriter(HtmlConfiguration configuration, DocPath filename) { super(configuration, filename); - this.configuration = configuration; this.navBar = new Navigation(null, configuration, PageMode.DEPRECATED, path); NestedClassWriterImpl classW = new NestedClassWriterImpl(this); writerMap = new EnumMap<>(DeprElementKind.class); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java index dbe42598ba5..3a2931c6886 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java @@ -139,9 +139,15 @@ public class Comparators { @Override public int compare(Element e1, Element e2) { int result = compareFullyQualifiedNames(e1, e2); - if (result == 0) - result = compareModuleNames(e1, e2); - return result; + if (result != 0) { + return result; + } + // if elements are executable compare their parameter arrays + result = compareParameters(e1, e2); + if (result != 0) { + return result; + } + return compareModuleNames(e1, e2); } }; } @@ -256,19 +262,11 @@ public class Comparators { if (result != 0) { return result; } - // if element kinds are the same, and are methods, - // compare the method parameters - if (hasParameters(e1)) { - List parameters1 = ((ExecutableElement)e1).getParameters(); - List parameters2 = ((ExecutableElement)e2).getParameters(); - result = compareParameters(false, parameters1, parameters2); - if (result != 0) { - return result; - } - result = compareParameters(true, parameters1, parameters2); - if (result != 0) { - return result; - } + // if element kinds are the same, and are executable, + // compare the parameter arrays + result = compareParameters(e1, e2); + if (result != 0) { + return result; } // else fall back on fully qualified names result = compareFullyQualifiedNames(e1, e2); @@ -383,15 +381,7 @@ public class Comparators { if (result != 0) { return result; } - if (hasParameters(e1) && hasParameters(e2)) { - List parameters1 = ((ExecutableElement)e1).getParameters(); - List parameters2 = ((ExecutableElement)e2).getParameters(); - result = compareParameters(false, parameters1, parameters2); - if (result != 0) { - return result; - } - result = compareParameters(true, parameters1, parameters2); - } + result = compareParameters(e1, e2); if (result != 0) { return result; } @@ -504,6 +494,34 @@ public class Comparators { return 0; } + /** + * Compares the parameter arrays of two elements if they both are executable. + * @param e1 the first element + * @param e2 the second element + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second + */ + protected int compareParameters(Element e1, Element e2) { + int result = 0; + if (hasParameters(e1) && hasParameters(e2)) { + List parameters1 = ((ExecutableElement)e1).getParameters(); + List parameters2 = ((ExecutableElement)e2).getParameters(); + result = compareParameters(false, parameters1, parameters2); + if (result != 0) { + return result; + } + result = compareParameters(true, parameters1, parameters2); + } + return result; + } + + /** + * Compares the kinds of two elements. + * @param e1 the first element + * @param e2 the second element + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second + */ protected int compareElementKinds(Element e1, Element e2) { return Integer.compare(getKindIndex(e1), getKindIndex(e2)); } diff --git a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java index 05a437a0286..81732538029 100644 --- a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java +++ b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java @@ -24,7 +24,7 @@ /* * @test * @bug 4927552 8026567 8071982 8162674 8175200 8175218 8183511 8186332 - * 8169819 8074407 8191030 8182765 8184205 + * 8169819 8074407 8191030 8182765 8184205 8243533 * @summary test generated docs for deprecated items * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -164,9 +164,28 @@ public class TestDeprecatedDocs extends JavadocTester { """, """ -
    Deprecated. +
    Deprecated, for removal: This \ + API element is subject to removal in a future version.
    class_test4 passes.
    + """, + """ + +
    Deprecated. +
    class_test5 passes.
    +
    + """, + """ + +
    Deprecated. +
    class_test6 passes.
    +
    + """, + """ + +
    Deprecated. +
    class_test7 passes.
    +
    """); checkOutput("pkg/TestClass.html", false, @@ -355,6 +374,78 @@ public class TestDeprecatedDocs extends JavadocTester { -
    """); + """, + """ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """, + """ +
    +
    Methods
    MethodDescription
    pkg.DeprecatedClassByAnnotation.method()
    pkg.TestAnnotationType.optional() +
    annotation_test2 passes.
    +
    pkg.TestAnnotationType.required() +
    annotation_test3 passes.
    +
    pkg.TestClass.method() +
    class_test5 passes. This is the second sentence of deprecated description for a method.
    +
    pkg.TestClass.overloadedMethod​(int) +
    class_test7 passes. Overloaded method 2.
    +
    pkg.TestClass.overloadedMethod​(String) +
    class_test6 passes. Overloaded method 1.
    +
    + + + + + + + + + + + + + + + + + + + + """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/pkg/TestClass.java b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/pkg/TestClass.java index 0fb178252ce..82f7ab2e81f 100644 --- a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/pkg/TestClass.java +++ b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/pkg/TestClass.java @@ -41,7 +41,23 @@ public class TestClass { public TestClass() {} /** - * @deprecated class_test4 passes. This is the second sentence of deprecated description for a method. + * @deprecated class_test4 passes. Overloaded constructor. + */ + @Deprecated(forRemoval=true) + public TestClass(String s) {} + + /** + * @deprecated class_test5 passes. This is the second sentence of deprecated description for a method. */ public void method() {} + + /** + * @deprecated class_test6 passes. Overloaded method 1. + */ + public void overloadedMethod(String s) {} + + /** + * @deprecated class_test7 passes. Overloaded method 2. + */ + public void overloadedMethod(int i) {} } From 8b6d3147fb8164e44dcd215794a31bdcf1bc21eb Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 19 Jun 2020 11:04:52 -0700 Subject: [PATCH 14/20] 8247815: doclint: recategorize "no description for ..." as MISSING, not SYNTAX Reviewed-by: prappo --- .../share/classes/com/sun/tools/doclint/Checker.java | 2 +- .../jdk/javadoc/tool/doclint/DocLintTest.java | 6 +++--- test/langtools/tools/doclint/EmptyAuthorTest.java | 6 +++--- test/langtools/tools/doclint/EmptyExceptionTest.java | 8 ++++---- test/langtools/tools/doclint/EmptyParamTest.java | 8 ++++---- test/langtools/tools/doclint/EmptyReturnTest.java | 8 ++++---- .../langtools/tools/doclint/EmptySerialDataTest.java | 12 ++++++++---- test/langtools/tools/doclint/EmptySerialDataTest.out | 6 +++--- .../tools/doclint/EmptySerialFieldTest.java | 6 +++--- test/langtools/tools/doclint/EmptySinceTest.java | 8 ++++---- test/langtools/tools/doclint/EmptyVersionTest.java | 8 ++++---- .../tools/doclint/MultipleDocLintOptionsTest.java | 4 ++-- test/langtools/tools/javac/doclint/DocLintTest.java | 2 +- 13 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/doclint/Checker.java b/src/jdk.compiler/share/classes/com/sun/tools/doclint/Checker.java index dbb577aa52d..2d8fc787956 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/doclint/Checker.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/doclint/Checker.java @@ -1168,7 +1168,7 @@ public class Checker extends DocTreePathScanner { return; } } - env.messages.warning(SYNTAX, tree, "dc.empty", tree.getKind().tagName); + env.messages.warning(MISSING, tree, "dc.empty", tree.getKind().tagName); } boolean hasNonWhitespace(TextTree tree) { diff --git a/test/langtools/jdk/javadoc/tool/doclint/DocLintTest.java b/test/langtools/jdk/javadoc/tool/doclint/DocLintTest.java index 7c16d266a31..295873ddd21 100644 --- a/test/langtools/jdk/javadoc/tool/doclint/DocLintTest.java +++ b/test/langtools/jdk/javadoc/tool/doclint/DocLintTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8004834 8007610 8129909 8182765 + * @bug 8004834 8007610 8129909 8182765 8247815 * @summary Add doclint support into javadoc * @modules jdk.compiler/com.sun.tools.javac.main */ @@ -178,7 +178,7 @@ public class DocLintTest { Main.Result.OK, EnumSet.of(Message.DL_WRN12)); - test(List.of(htmlVersion, rawDiags, "-Xdoclint:syntax"), + test(List.of(htmlVersion, rawDiags, "-Xdoclint:missing"), Main.Result.OK, EnumSet.of(Message.DL_WRN12)); @@ -186,7 +186,7 @@ public class DocLintTest { Main.Result.ERROR, EnumSet.of(Message.DL_ERR6, Message.DL_ERR9, Message.DL_WRN12)); - test(List.of(htmlVersion, rawDiags, "-Xdoclint:syntax", "-private"), + test(List.of(htmlVersion, rawDiags, "-Xdoclint:missing,syntax", "-private"), Main.Result.ERROR, EnumSet.of(Message.DL_ERR6, Message.DL_WRN12)); diff --git a/test/langtools/tools/doclint/EmptyAuthorTest.java b/test/langtools/tools/doclint/EmptyAuthorTest.java index 0a5db470e6b..ecd7e91271c 100644 --- a/test/langtools/tools/doclint/EmptyAuthorTest.java +++ b/test/langtools/tools/doclint/EmptyAuthorTest.java @@ -1,11 +1,11 @@ /* * @test /nodynamiccopyright/ - * @bug 8004832 + * @bug 8004832 8247815 * @summary Add new doclint package * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester - * @run main DocLintTester -Xmsgs:-syntax EmptyAuthorTest.java - * @run main DocLintTester -Xmsgs:syntax -ref EmptyAuthorTest.out EmptyAuthorTest.java + * @run main DocLintTester -Xmsgs:-missing EmptyAuthorTest.java + * @run main DocLintTester -Xmsgs:missing -ref EmptyAuthorTest.out EmptyAuthorTest.java */ /** @author */ diff --git a/test/langtools/tools/doclint/EmptyExceptionTest.java b/test/langtools/tools/doclint/EmptyExceptionTest.java index 6a5db240020..8a93ec69d02 100644 --- a/test/langtools/tools/doclint/EmptyExceptionTest.java +++ b/test/langtools/tools/doclint/EmptyExceptionTest.java @@ -1,15 +1,15 @@ /* * @test /nodynamiccopyright/ - * @bug 8004832 + * @bug 8004832 8247815 * @summary Add new doclint package * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester - * @run main DocLintTester -Xmsgs:-syntax EmptyExceptionTest.java - * @run main DocLintTester -Xmsgs:syntax -ref EmptyExceptionTest.out EmptyExceptionTest.java + * @run main DocLintTester -Xmsgs:-missing EmptyExceptionTest.java + * @run main DocLintTester -Xmsgs:missing -ref EmptyExceptionTest.out EmptyExceptionTest.java */ /** . */ public class EmptyExceptionTest { /** @exception NullPointerException */ - int emptyException() throws NullPointerException { } + void emptyException() throws NullPointerException { } } diff --git a/test/langtools/tools/doclint/EmptyParamTest.java b/test/langtools/tools/doclint/EmptyParamTest.java index 37f76ae075c..ce92ecc19e5 100644 --- a/test/langtools/tools/doclint/EmptyParamTest.java +++ b/test/langtools/tools/doclint/EmptyParamTest.java @@ -1,15 +1,15 @@ /* * @test /nodynamiccopyright/ - * @bug 8004832 + * @bug 8004832 8247815 * @summary Add new doclint package * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester - * @run main DocLintTester -Xmsgs:-syntax EmptyParamTest.java - * @run main DocLintTester -Xmsgs:syntax -ref EmptyParamTest.out EmptyParamTest.java + * @run main DocLintTester -Xmsgs:-missing EmptyParamTest.java + * @run main DocLintTester -Xmsgs:missing -ref EmptyParamTest.out EmptyParamTest.java */ /** . */ public class EmptyParamTest { /** @param i */ - int emptyParam(int i) { } + void emptyParam(int i) { } } diff --git a/test/langtools/tools/doclint/EmptyReturnTest.java b/test/langtools/tools/doclint/EmptyReturnTest.java index b0c787fe6fe..34ff7f4cbd8 100644 --- a/test/langtools/tools/doclint/EmptyReturnTest.java +++ b/test/langtools/tools/doclint/EmptyReturnTest.java @@ -1,15 +1,15 @@ /* * @test /nodynamiccopyright/ - * @bug 8004832 + * @bug 8004832 8247815 * @summary Add new doclint package * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester - * @run main DocLintTester -Xmsgs:-syntax EmptyReturnTest.java - * @run main DocLintTester -Xmsgs:syntax -ref EmptyReturnTest.out EmptyReturnTest.java + * @run main DocLintTester -Xmsgs:-missing EmptyReturnTest.java + * @run main DocLintTester -Xmsgs:missing -ref EmptyReturnTest.out EmptyReturnTest.java */ /** . */ public class EmptyReturnTest { /** @return */ - int emptyReturn() { } + int emptyReturn() { return 0; } } diff --git a/test/langtools/tools/doclint/EmptySerialDataTest.java b/test/langtools/tools/doclint/EmptySerialDataTest.java index 38c04659910..f6c353069e8 100644 --- a/test/langtools/tools/doclint/EmptySerialDataTest.java +++ b/test/langtools/tools/doclint/EmptySerialDataTest.java @@ -1,11 +1,11 @@ /* * @test /nodynamiccopyright/ - * @bug 8004832 + * @bug 8004832 8247815 * @summary Add new doclint package * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester - * @run main DocLintTester -Xmsgs:-syntax EmptySerialDataTest.java - * @run main DocLintTester -Xmsgs:syntax -ref EmptySerialDataTest.out EmptySerialDataTest.java + * @run main DocLintTester -Xmsgs:-missing EmptySerialDataTest.java + * @run main DocLintTester -Xmsgs:missing -ref EmptySerialDataTest.out EmptySerialDataTest.java */ import java.io.ObjectOutputStream; @@ -13,6 +13,10 @@ import java.io.Serializable; /** . */ public class EmptySerialDataTest implements Serializable { - /** @serialData */ + /** + * . + * @serialData + * @param s . + */ private void writeObject(ObjectOutputStream s) { } } diff --git a/test/langtools/tools/doclint/EmptySerialDataTest.out b/test/langtools/tools/doclint/EmptySerialDataTest.out index f34a77a144c..dcfa059796d 100644 --- a/test/langtools/tools/doclint/EmptySerialDataTest.out +++ b/test/langtools/tools/doclint/EmptySerialDataTest.out @@ -1,5 +1,5 @@ -EmptySerialDataTest.java:16: warning: no description for @serialData - /** @serialData */ - ^ +EmptySerialDataTest.java:18: warning: no description for @serialData + * @serialData + ^ 1 warning diff --git a/test/langtools/tools/doclint/EmptySerialFieldTest.java b/test/langtools/tools/doclint/EmptySerialFieldTest.java index 533370969ab..79789cc6588 100644 --- a/test/langtools/tools/doclint/EmptySerialFieldTest.java +++ b/test/langtools/tools/doclint/EmptySerialFieldTest.java @@ -1,11 +1,11 @@ /* * @test /nodynamiccopyright/ - * @bug 8004832 + * @bug 8004832 8247815 * @summary Add new doclint package * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester - * @run main DocLintTester -Xmsgs:-syntax EmptySerialFieldTest.java - * @run main DocLintTester -Xmsgs:syntax -ref EmptySerialFieldTest.out EmptySerialFieldTest.java + * @run main DocLintTester -Xmsgs:-missing EmptySerialFieldTest.java + * @run main DocLintTester -Xmsgs:missing -ref EmptySerialFieldTest.out EmptySerialFieldTest.java */ import java.io.ObjectStreamField; diff --git a/test/langtools/tools/doclint/EmptySinceTest.java b/test/langtools/tools/doclint/EmptySinceTest.java index 4af2249a18c..5992cc9d901 100644 --- a/test/langtools/tools/doclint/EmptySinceTest.java +++ b/test/langtools/tools/doclint/EmptySinceTest.java @@ -1,15 +1,15 @@ /* * @test /nodynamiccopyright/ - * @bug 8004832 + * @bug 8004832 8247815 * @summary Add new doclint package * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester - * @run main DocLintTester -Xmsgs:-syntax EmptySinceTest.java - * @run main DocLintTester -Xmsgs:syntax -ref EmptySinceTest.out EmptySinceTest.java + * @run main DocLintTester -Xmsgs:-missing EmptySinceTest.java + * @run main DocLintTester -Xmsgs:missing -ref EmptySinceTest.out EmptySinceTest.java */ /** . */ public class EmptySinceTest { /** @since */ - int emptySince() { } + void emptySince() { } } diff --git a/test/langtools/tools/doclint/EmptyVersionTest.java b/test/langtools/tools/doclint/EmptyVersionTest.java index 43590818cc0..e2c3799410f 100644 --- a/test/langtools/tools/doclint/EmptyVersionTest.java +++ b/test/langtools/tools/doclint/EmptyVersionTest.java @@ -1,15 +1,15 @@ /* * @test /nodynamiccopyright/ - * @bug 8004832 + * @bug 8004832 8247815 * @summary Add new doclint package * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester - * @run main DocLintTester -Xmsgs:-syntax EmptyVersionTest.java - * @run main DocLintTester -Xmsgs:syntax -ref EmptyVersionTest.out EmptyVersionTest.java + * @run main DocLintTester -Xmsgs:-missing EmptyVersionTest.java + * @run main DocLintTester -Xmsgs:missing -ref EmptyVersionTest.out EmptyVersionTest.java */ /** . */ public class EmptyVersionTest { /** @version */ - int missingVersion() { } + void missingVersion() { } } diff --git a/test/langtools/tools/doclint/MultipleDocLintOptionsTest.java b/test/langtools/tools/doclint/MultipleDocLintOptionsTest.java index b85af8e22ca..6a306cf64cb 100644 --- a/test/langtools/tools/doclint/MultipleDocLintOptionsTest.java +++ b/test/langtools/tools/doclint/MultipleDocLintOptionsTest.java @@ -1,8 +1,8 @@ /* * @test /nodynamiccopyright/ - * @bug 8198552 + * @bug 8198552 8247815 * @summary Check that -Xdoclint: option can be specified multiple times - * @compile/fail/ref=MultipleDocLintOptionsTest.out -Xdoclint:html -Xdoclint:syntax -XDrawDiagnostics MultipleDocLintOptionsTest.java + * @compile/fail/ref=MultipleDocLintOptionsTest.out -Xdoclint:html -Xdoclint:missing -XDrawDiagnostics MultipleDocLintOptionsTest.java */ /** */ diff --git a/test/langtools/tools/javac/doclint/DocLintTest.java b/test/langtools/tools/javac/doclint/DocLintTest.java index 471bd084585..110c002c277 100644 --- a/test/langtools/tools/javac/doclint/DocLintTest.java +++ b/test/langtools/tools/javac/doclint/DocLintTest.java @@ -135,7 +135,7 @@ public class DocLintTest { Main.Result.OK, EnumSet.of(Message.DL_WRN12)); - test(Arrays.asList(rawDiags, "-Xdoclint:syntax"), + test(Arrays.asList(rawDiags, "-Xdoclint:syntax,missing"), Main.Result.ERROR, EnumSet.of(Message.DL_ERR6, Message.DL_WRN12)); From e0a7782a9e4165fd9d101217d31a38e3afaf2dc7 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 19 Jun 2020 11:10:31 -0700 Subject: [PATCH 15/20] 8247784: Bad link causes invalid documentation Reviewed-by: mchung, dholmes, sspitsyn --- src/jdk.jdi/share/classes/com/sun/jdi/Type.java | 2 +- .../share/classes/com/sun/jdi/event/ClassUnloadEvent.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/Type.java b/src/jdk.jdi/share/classes/com/sun/jdi/Type.java index 91ab3dee148..c5d7554799c 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/Type.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/Type.java @@ -152,7 +152,7 @@ public interface Type extends Mirror { * Returns the name of this type. The result is of the same form as * the name returned by {@link Class#getName()}. * The returned name may not be a - * binary name. + * binary name. * * @return the name of this type */ diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/event/ClassUnloadEvent.java b/src/jdk.jdi/share/classes/com/sun/jdi/event/ClassUnloadEvent.java index e236da0838a..ae2fe364bfb 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/event/ClassUnloadEvent.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/event/ClassUnloadEvent.java @@ -44,7 +44,7 @@ public interface ClassUnloadEvent extends Event { /** * Returns the {@linkplain com.sun.jdi.Type#name() name of the class} * that has been unloaded. The returned string may not be a - * binary name. + * binary name. * * @see Class#getName() */ From 25b1e5a7bdec140173ea367fd7daca39602071a8 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Fri, 19 Jun 2020 15:22:19 -0400 Subject: [PATCH 16/20] 8247876: ProblemList various crypto tests on aarch64 Reviewed-by: wetmore --- test/jdk/ProblemList.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index de2f7a6c286..ac1cf8fe3f2 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -699,6 +699,10 @@ javax/security/auth/kerberos/KerberosTixDateTest.java 8039280 generic- sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java 8039280 generic-all sun/security/provider/PolicyParser/ExtDirsChange.java 8039280 generic-all sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic-all +sun/security/provider/SecureRandom/AbstractDrbg/SpecTest.java 8247359 linux-aarch64 +sun/security/provider/SecureRandom/SHA1PRNGReseed.java 8247359 linux-aarch64 +sun/security/provider/SecureRandom/StrongSecureRandom.java 8247359 linux-aarch64 +sun/security/provider/SeedGenerator/SeedGeneratorChoice.java 8247359 linux-aarch64 ############################################################################ From c4df79117d9613750e327a733e23c2a71131938e Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Sat, 20 Jun 2020 15:11:19 +0800 Subject: [PATCH 17/20] 8247907: XMLDsig logging does not work Reviewed-by: mullan --- .../share/lib/security/default.policy | 2 + .../com/sun/org/slf4j/internal/Logger.java | 89 ++++++++++++++++--- .../javax/xml/crypto/dsig/LogParameters.java | 58 ++++++++++++ 3 files changed, 137 insertions(+), 12 deletions(-) create mode 100644 test/jdk/javax/xml/crypto/dsig/LogParameters.java diff --git a/src/java.base/share/lib/security/default.policy b/src/java.base/share/lib/security/default.policy index ed553c9ab8e..7b3ba7b40c3 100644 --- a/src/java.base/share/lib/security/default.policy +++ b/src/java.base/share/lib/security/default.policy @@ -78,6 +78,8 @@ grant codeBase "jrt:/java.sql.rowset" { grant codeBase "jrt:/java.xml.crypto" { + permission java.lang.RuntimePermission + "getStackWalkerWithClassReference"; permission java.lang.RuntimePermission "accessClassInPackage.sun.security.util"; permission java.util.PropertyPermission "*", "read"; diff --git a/src/java.xml.crypto/share/classes/com/sun/org/slf4j/internal/Logger.java b/src/java.xml.crypto/share/classes/com/sun/org/slf4j/internal/Logger.java index 04450d0620a..e459d390ef8 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/slf4j/internal/Logger.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/slf4j/internal/Logger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, 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 @@ -24,9 +24,28 @@ */ package com.sun.org.slf4j.internal; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.logging.Level; + // Bridge to java.util.logging. public class Logger { + /** + * StackWalker to find out the caller of this class so that it can be + * shown in the log output. The multiple private log0() methods below + * skip exactly 2 frames -- one log0() itself, the other one of the + * public debug()/warn()/error()/trace() methods in this class -- + * to find the caller. + */ + private static final StackWalker WALKER; + static { + final PrivilegedAction action = + () -> StackWalker.getInstance(StackWalker.Option + .RETAIN_CLASS_REFERENCE); + WALKER = AccessController.doPrivileged(action); + } + private final java.util.logging.Logger impl; public Logger(String name) { @@ -34,46 +53,92 @@ public class Logger { } public boolean isDebugEnabled() { - return impl.isLoggable(java.util.logging.Level.FINE); + return impl.isLoggable(Level.FINE); } public boolean isTraceEnabled() { - return impl.isLoggable(java.util.logging.Level.FINE); + return impl.isLoggable(Level.FINE); } public void debug(String s) { - impl.log(java.util.logging.Level.FINE, s); + log0(Level.FINE, s); } public void debug(String s, Throwable e) { - impl.log(java.util.logging.Level.FINE, s, e); + log0(Level.FINE, s, e); } public void debug(String s, Object... o) { - impl.log(java.util.logging.Level.FINE, s, o); + log0(Level.FINE, s, o); } public void trace(String s) { - impl.log(java.util.logging.Level.FINE, s); + log0(Level.FINE, s); } public void error(String s) { - impl.log(java.util.logging.Level.SEVERE, s); + log0(Level.SEVERE, s); } public void error(String s, Throwable e) { - impl.log(java.util.logging.Level.SEVERE, s, e); + log0(Level.SEVERE, s, e); } public void error(String s, Object... o) { - impl.log(java.util.logging.Level.SEVERE, s, o); + log0(Level.SEVERE, s, o); } public void warn(String s) { - impl.log(java.util.logging.Level.WARNING, s); + log0(Level.WARNING, s); } public void warn(String s, Throwable e) { - impl.log(java.util.logging.Level.WARNING, s, e); + log0(Level.WARNING, s, e); + } + + private void log0(Level level, String s) { + if (impl.isLoggable(level)) { + var sf = WALKER.walk(f -> f.skip(2).findFirst()).get(); + impl.logp(Level.FINE, sf.getClassName(), sf.getMethodName(), s); + } + } + + public void log0(Level level, String s, Throwable e) { + if (impl.isLoggable(level)) { + var sf = WALKER.walk(f -> f.skip(2).findFirst()).get(); + impl.logp(Level.FINE, sf.getClassName(), sf.getMethodName(), s, e); + } + } + + public void log0(Level level, String s, Object... o) { + if (impl.isLoggable(level)) { + var sf = WALKER.walk(f -> f.skip(2).findFirst()).get(); + impl.logp(Level.FINE, sf.getClassName(), sf.getMethodName(), + addIndex(s), o); + } + } + + /** + * Translate the log4j message format "Hello {}, {}" to the + * java.util.logging format "Hello {0}, {1}". + */ + private static String addIndex(String s) { + int start = 0; + int index = 0; + StringBuilder sb = new StringBuilder(); + while (true) { + int pos = s.indexOf("{}", start); + if (pos < 0) { + break; + } + sb.append(s, start, pos + 1).append(index++); + start = pos + 1; + } + if (index == 0) { + return s; + } else { + sb.append(s, start, s.length()); + return sb.toString(); + } } } diff --git a/test/jdk/javax/xml/crypto/dsig/LogParameters.java b/test/jdk/javax/xml/crypto/dsig/LogParameters.java new file mode 100644 index 00000000000..cd829761f6e --- /dev/null +++ b/test/jdk/javax/xml/crypto/dsig/LogParameters.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.hexdump.HexPrinter; + +import java.io.ByteArrayOutputStream; +import java.util.logging.*; + +/** + * @test + * @bug 8247907 + * @library /test/lib + * @modules java.xml.crypto/com.sun.org.slf4j.internal + */ +public class LogParameters { + public static void main(String[] args) { + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + Logger.getLogger(String.class.getName()).setLevel(Level.ALL); + Handler h = new StreamHandler(bout, new SimpleFormatter()); + h.setLevel(Level.ALL); + Logger.getLogger(String.class.getName()).addHandler(h); + + com.sun.org.slf4j.internal.Logger log = + com.sun.org.slf4j.internal.LoggerFactory.getLogger(String.class); + log.debug("I have {} {}s.", 10, "apple"); + + h.flush(); + + byte[] data = bout.toByteArray(); + String s = new String(data); + if (!s.contains("LogParameters main") + || !s.contains("FINE: I have 10 apples.")) { + HexPrinter.simple().format(data); + throw new RuntimeException("Unexpected log output: " + s); + } + } +} From f834dc3dc9c7e36ee5173f229c6a4ef7903b73df Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Sun, 21 Jun 2020 08:32:54 +0800 Subject: [PATCH 18/20] 8247964: All log0() in com/sun/org/slf4j/internal/Logger.java should be private Reviewed-by: rriggs, xuelei --- .../share/classes/com/sun/org/slf4j/internal/Logger.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.xml.crypto/share/classes/com/sun/org/slf4j/internal/Logger.java b/src/java.xml.crypto/share/classes/com/sun/org/slf4j/internal/Logger.java index e459d390ef8..ab98cefb648 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/slf4j/internal/Logger.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/slf4j/internal/Logger.java @@ -103,14 +103,14 @@ public class Logger { } } - public void log0(Level level, String s, Throwable e) { + private void log0(Level level, String s, Throwable e) { if (impl.isLoggable(level)) { var sf = WALKER.walk(f -> f.skip(2).findFirst()).get(); impl.logp(Level.FINE, sf.getClassName(), sf.getMethodName(), s, e); } } - public void log0(Level level, String s, Object... o) { + private void log0(Level level, String s, Object... o) { if (impl.isLoggable(level)) { var sf = WALKER.walk(f -> f.skip(2).findFirst()).get(); impl.logp(Level.FINE, sf.getClassName(), sf.getMethodName(), From eb758d53f13cc8bce2855063b8985d03e6b15e16 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 18 Jun 2020 15:44:55 +0200 Subject: [PATCH 19/20] 8247763: assert(outer->outcnt() == 2) failed: 'only phis' failure in LoopNode::verify_strip_mined() Reviewed-by: kvn, thartmann --- src/hotspot/share/opto/loopopts.cpp | 3 + .../TestStoreSunkToOuterLoop.java | 69 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/loopstripmining/TestStoreSunkToOuterLoop.java diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 0372fc202ae..d29970b5d36 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -909,6 +909,9 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) { // Compute latest point this store can go Node* lca = get_late_ctrl(n, get_ctrl(n)); + if (lca->is_OuterStripMinedLoop()) { + lca = lca->in(LoopNode::EntryControl); + } if (n_loop->is_member(get_loop(lca))) { // LCA is in the loop - bail out _igvn.replace_node(hook, n); diff --git a/test/hotspot/jtreg/compiler/loopstripmining/TestStoreSunkToOuterLoop.java b/test/hotspot/jtreg/compiler/loopstripmining/TestStoreSunkToOuterLoop.java new file mode 100644 index 00000000000..defdfc7452f --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopstripmining/TestStoreSunkToOuterLoop.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8247763 + * @summary assert(outer->outcnt() == 2) failed: 'only phis' failure in LoopNode::verify_strip_mined() + * + * @run main/othervm -Xcomp -XX:CompileOnly=TestStoreSunkToOuterLoop TestStoreSunkToOuterLoop + * + */ + +public class TestStoreSunkToOuterLoop { + + public static final int N = 400; + public static long instanceCount=-62761L; + public static boolean bFld=false; + public static int iArrFld[]=new int[N]; + + public void mainTest() { + + int i15=226, i16=54621, i19=780; + float f3=0.671F, f4=-101.846F; + + i15 = 1; + do { + if (bFld) continue; + for (i16 = 1; i16 < 101; ++i16) { + iArrFld[i16 - 1] = i15; + instanceCount = i16; + } + } while (++i15 < 248); + f3 += -2061721519L; + for (f4 = 324; f4 > 3; f4--) { + for (i19 = 4; i19 < 78; ++i19) { + f3 -= -11; + } + } + + System.out.println(instanceCount); + } + + public static void main(String[] strArr) { + TestStoreSunkToOuterLoop _instance = new TestStoreSunkToOuterLoop(); + for (int i = 0; i < 10; i++ ) { + _instance.mainTest(); + } + } +} From 61e44cdb6a90fdb026adc20dc1ece68cefafd250 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 22 Jun 2020 12:03:11 +0200 Subject: [PATCH 20/20] 8247932: JShell crashes when typing text block Setting up Log before running javac's scanner, so that errors reported from the scanner are properly ignored. Reviewed-by: rfield --- .../internal/jshell/tool/ConsoleIOContext.java | 15 ++++++++++++++- test/langtools/jdk/jshell/IndentUITest.java | 7 ++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index c56dc1beb12..0d99cc3b0b2 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, 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,6 +34,7 @@ import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.io.PrintStream; +import java.net.URI; import java.nio.charset.Charset; import java.time.Instant; import java.util.ArrayList; @@ -50,6 +51,9 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; import jdk.internal.shellsupport.doc.JavadocFormatter; import jdk.internal.jshell.tool.StopDetectingInputStream.State; @@ -974,6 +978,15 @@ class ConsoleIOContext extends IOContext { int pendingBraces = 0; com.sun.tools.javac.util.Context ctx = new com.sun.tools.javac.util.Context(); + SimpleJavaFileObject source = new SimpleJavaFileObject(URI.create("mem://snippet"), + JavaFileObject.Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return code; + } + }; + ctx.put(DiagnosticListener.class, d -> {}); + com.sun.tools.javac.util.Log.instance(ctx).useSource(source); com.sun.tools.javac.parser.ScannerFactory scannerFactory = com.sun.tools.javac.parser.ScannerFactory.instance(ctx); com.sun.tools.javac.parser.Scanner scanner = diff --git a/test/langtools/jdk/jshell/IndentUITest.java b/test/langtools/jdk/jshell/IndentUITest.java index efa993ad359..4f39cbbfc42 100644 --- a/test/langtools/jdk/jshell/IndentUITest.java +++ b/test/langtools/jdk/jshell/IndentUITest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8241950 + * @bug 8241950 8247932 * @summary Check the UI behavior of indentation * @library /tools/lib * @modules @@ -70,6 +70,11 @@ public class IndentUITest extends UITesting { waitOutput(out, "^void test2\\(\\) \\{\n" + CONTINUATION_PROMPT + " System.err.println\\(1\\);\n" + CONTINUATION_PROMPT + "\\}"); + inputSink.write(INTERRUPT); + waitOutput(out, "\u001B\\[\\?2004h" + PROMPT); + inputSink.write("\"\"\"\n"); + waitOutput(out, "^\"\"\"\n" + + CONTINUATION_PROMPT); }); }
    Constructors
    ConstructorDescription
    pkg.DeprecatedClassByAnnotation()
    pkg.TestClass() +
    class_test3 passes. This is the second sentence of deprecated description for a constructor.
    +
    pkg.TestClass​(String) +
    class_test4 passes. Overloaded constructor.
    +