Merge
This commit is contained in:
commit
a16994ff7b
1
.hgtags
1
.hgtags
@ -640,4 +640,5 @@ f143729ca00ec14a98ea5c7f73acba88da97746e jdk-15+23
|
||||
93813843680bbe1b7efbca56c03fd137f20a2c31 jdk-16+0
|
||||
93813843680bbe1b7efbca56c03fd137f20a2c31 jdk-15+27
|
||||
4a485c89d5a08b495961835f5308a96038678aeb jdk-16+1
|
||||
06c9f89459daba98395fad726100feb44f89ba71 jdk-15+28
|
||||
bcbe7b8a77b8971bc221c0be1bd2abb6fb68c2d0 jdk-16+2
|
||||
|
@ -2555,7 +2555,7 @@ JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass))
|
||||
{
|
||||
if (WhiteBoxAPI) {
|
||||
// Make sure that wbclass is loaded by the null classloader
|
||||
InstanceKlass* ik = InstanceKlass::cast(JNIHandles::resolve(wbclass)->klass());
|
||||
InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(wbclass)));
|
||||
Handle loader(THREAD, ik->class_loader());
|
||||
if (loader.is_null()) {
|
||||
WhiteBox::register_methods(env, wbclass, thread, methods, sizeof(methods) / sizeof(methods[0]));
|
||||
|
@ -548,6 +548,9 @@ public class TypeAnnotations {
|
||||
*/
|
||||
private Type rewriteArrayType(ArrayType type, List<TypeCompound> annotations, TypeAnnotationPosition pos) {
|
||||
ArrayType tomodify = new ArrayType(type);
|
||||
if (type.isVarargs()) {
|
||||
tomodify = tomodify.makeVarargs();
|
||||
}
|
||||
ArrayType res = tomodify;
|
||||
|
||||
List<TypePathEntry> loc = List.nil();
|
||||
|
@ -3040,7 +3040,14 @@ public class Attr extends JCTree.Visitor {
|
||||
} finally {
|
||||
localEnv.info.scope.leave();
|
||||
if (needsRecovery) {
|
||||
attribTree(that, env, recoveryInfo);
|
||||
Type prevResult = result;
|
||||
try {
|
||||
attribTree(that, env, recoveryInfo);
|
||||
} finally {
|
||||
if (result == Type.recoveryType) {
|
||||
result = prevResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,17 +221,6 @@ public class DocCommentParser {
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
newline = false;
|
||||
addPendingText(trees, bp - 1);
|
||||
trees.add(m.at(bp).newErroneousTree(newString(bp, bp + 1), diagSource, "dc.bad.gt"));
|
||||
nextChar();
|
||||
if (textStart == -1) {
|
||||
textStart = bp;
|
||||
lastNonWhite = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '{':
|
||||
inlineTag(trees);
|
||||
break;
|
||||
|
@ -3140,9 +3140,6 @@ compiler.misc.where.description.intersection.1=\
|
||||
compiler.err.dc.bad.entity=\
|
||||
bad HTML entity
|
||||
|
||||
compiler.err.dc.bad.gt=\
|
||||
bad use of ''>''
|
||||
|
||||
compiler.err.dc.bad.inline.tag=\
|
||||
incorrect use of inline tag
|
||||
|
||||
|
@ -40,6 +40,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.imageio.ImageIO;
|
||||
@ -250,9 +251,14 @@ final class DesktopIntegration {
|
||||
data.put("APPLICATION_ICON",
|
||||
iconFile != null ? iconFile.installPath().toString() : null);
|
||||
data.put("DEPLOY_BUNDLE_CATEGORY", MENU_GROUP.fetchFrom(params));
|
||||
data.put("APPLICATION_LAUNCHER",
|
||||
thePackage.installedApplicationLayout().launchersDirectory().resolve(
|
||||
LinuxAppImageBuilder.getLauncherName(params)).toString());
|
||||
|
||||
String appLauncher = thePackage.installedApplicationLayout().launchersDirectory().resolve(
|
||||
LinuxAppImageBuilder.getLauncherName(params)).toString();
|
||||
if (Pattern.compile("\\s").matcher(appLauncher).find()) {
|
||||
// Path contains whitespace(s). Enclose in double quotes.
|
||||
appLauncher = "\"" + appLauncher + "\"";
|
||||
}
|
||||
data.put("APPLICATION_LAUNCHER", appLauncher);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 org.graalvm.compiler.core.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class DeepUnrollingTest extends SubprocessTest {
|
||||
|
||||
public static void loops() {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
for (int n = 2; n < 30; n++) {
|
||||
for (int j = 1; j <= n; j++) {
|
||||
for (int k = 1; k <= j; k++) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int reference(int a, int n) {
|
||||
int v = a;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (v % 2 == 0) {
|
||||
v = v / 2;
|
||||
} else {
|
||||
v = 3 * v + 1;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public void loopTest() {
|
||||
// warmup
|
||||
time("reference");
|
||||
time("loops");
|
||||
long reference = time("reference");
|
||||
long loops = time("loops");
|
||||
// observed ratio is ~20-30x. Pathological case before fix was ~300x
|
||||
assertTrue("Compilation of the loop nest is too slow", loops < reference * 45);
|
||||
}
|
||||
|
||||
public long time(String methodName) {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod(methodName);
|
||||
OptionValues options = new OptionValues(getInitialOptions(),
|
||||
GraalOptions.FullUnroll, true);
|
||||
long start = System.nanoTime();
|
||||
getCode(method, null, true, false, options);
|
||||
long end = System.nanoTime();
|
||||
return TimeUnit.NANOSECONDS.toMillis(end - start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws IOException, InterruptedException {
|
||||
launchSubprocess(this::loopTest);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 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,6 +24,11 @@
|
||||
|
||||
package org.graalvm.compiler.loop.phases;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.compiler.debug.CounterKey;
|
||||
import org.graalvm.compiler.debug.DebugContext;
|
||||
@ -32,11 +37,24 @@ import org.graalvm.compiler.loop.LoopPolicies;
|
||||
import org.graalvm.compiler.loop.LoopsData;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.spi.CoreProviders;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionKey;
|
||||
import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
|
||||
public class LoopFullUnrollPhase extends LoopPhase<LoopPolicies> {
|
||||
public static class Options {
|
||||
@Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> FullUnrollMaxApplication = new OptionKey<>(60);
|
||||
}
|
||||
|
||||
private static final CounterKey FULLY_UNROLLED_LOOPS = DebugContext.counter("FullUnrolls");
|
||||
public static final Comparator<LoopEx> LOOP_COMPARATOR;
|
||||
static {
|
||||
ToDoubleFunction<LoopEx> loopFreq = e -> e.loop().getHeader().getFirstPredecessor().getRelativeFrequency();
|
||||
ToIntFunction<LoopEx> loopDepth = e -> e.loop().getDepth();
|
||||
LOOP_COMPARATOR = Comparator.comparingDouble(loopFreq).thenComparingInt(loopDepth).reversed();
|
||||
}
|
||||
|
||||
private final CanonicalizerPhase canonicalizer;
|
||||
|
||||
public LoopFullUnrollPhase(CanonicalizerPhase canonicalizer, LoopPolicies policies) {
|
||||
@ -50,11 +68,14 @@ public class LoopFullUnrollPhase extends LoopPhase<LoopPolicies> {
|
||||
DebugContext debug = graph.getDebug();
|
||||
if (graph.hasLoops()) {
|
||||
boolean peeled;
|
||||
int applications = 0;
|
||||
do {
|
||||
peeled = false;
|
||||
final LoopsData dataCounted = new LoopsData(graph);
|
||||
dataCounted.detectedCountedLoops();
|
||||
for (LoopEx loop : dataCounted.countedLoops()) {
|
||||
List<LoopEx> countedLoops = dataCounted.countedLoops();
|
||||
countedLoops.sort(LOOP_COMPARATOR);
|
||||
for (LoopEx loop : countedLoops) {
|
||||
if (getPolicies().shouldFullUnroll(loop)) {
|
||||
debug.log("FullUnroll %s", loop);
|
||||
LoopTransformations.fullUnroll(loop, context, canonicalizer);
|
||||
@ -65,7 +86,8 @@ public class LoopFullUnrollPhase extends LoopPhase<LoopPolicies> {
|
||||
}
|
||||
}
|
||||
dataCounted.deleteUnusedNodes();
|
||||
} while (peeled);
|
||||
applications++;
|
||||
} while (peeled && applications < Options.FullUnrollMaxApplication.getValue(graph.getOptions()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 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
|
||||
@ -25,8 +25,6 @@
|
||||
package org.graalvm.compiler.loop;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.vm.compiler.collections.EconomicMap;
|
||||
@ -92,8 +90,8 @@ public class LoopsData {
|
||||
return loops;
|
||||
}
|
||||
|
||||
public Collection<LoopEx> countedLoops() {
|
||||
List<LoopEx> counted = new LinkedList<>();
|
||||
public List<LoopEx> countedLoops() {
|
||||
List<LoopEx> counted = new ArrayList<>();
|
||||
for (LoopEx loop : loops()) {
|
||||
if (loop.isCounted()) {
|
||||
counted.add(loop);
|
||||
|
@ -49,6 +49,8 @@ import javax.lang.model.element.PackageElement;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.JavaFileManager.Location;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -145,6 +147,15 @@ public class DocFilesHandlerImpl implements DocFilesHandler {
|
||||
return;
|
||||
}
|
||||
for (DocFile srcfile: srcdir.list()) {
|
||||
// ensure that the name is a valid component in an eventual full path
|
||||
// and so avoid an equivalent check lower down in the file manager
|
||||
// that throws IllegalArgumentException
|
||||
if (!isValidFilename(srcfile)) {
|
||||
configuration.messages.warning("doclet.Copy_Ignored_warning",
|
||||
srcfile.getPath());
|
||||
continue;
|
||||
}
|
||||
|
||||
DocFile destfile = dstdir.resolve(srcfile.getName());
|
||||
if (srcfile.isFile()) {
|
||||
if (destfile.exists() && !first) {
|
||||
@ -169,6 +180,16 @@ public class DocFilesHandlerImpl implements DocFilesHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidFilename(DocFile f) {
|
||||
try {
|
||||
String n = f.getName();
|
||||
URI u = new URI(n);
|
||||
return u.getPath().equals(n);
|
||||
} catch (URISyntaxException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleHtmlFile(DocFile srcfile, DocPath dstPath) throws DocFileIOException {
|
||||
Utils utils = configuration.utils;
|
||||
FileObject fileObject = srcfile.getFileObject();
|
||||
|
@ -55,6 +55,7 @@ Please file a bug against the javadoc tool via the Java bug reporting page\n\
|
||||
for duplicates. Include error messages and the following diagnostic in your report. Thank you.
|
||||
doclet.File_not_found=File not found: {0}
|
||||
doclet.Copy_Overwrite_warning=File {0} not copied to {1} due to existing file with same name...
|
||||
doclet.Copy_Ignored_warning=File {0} not copied: invalid name
|
||||
doclet.Copying_File_0_To_Dir_1=Copying file {0} to directory {1}...
|
||||
doclet.Copying_File_0_To_File_1=Copying file {0} to file {1}...
|
||||
doclet.No_Public_Classes_To_Document=No public or protected classes found to document.
|
||||
|
@ -28,7 +28,19 @@ package gc.z;
|
||||
* @requires vm.gc.Z & !vm.graal.enabled
|
||||
* @summary Test ZGC uncommit unused memory
|
||||
* @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=10 gc.z.TestUncommit true 2
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestUncommit
|
||||
* @requires vm.gc.Z & !vm.graal.enabled
|
||||
* @summary Test ZGC uncommit unused memory
|
||||
* @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms512M -Xmx512M -XX:ZUncommitDelay=10 gc.z.TestUncommit false 1
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestUncommit
|
||||
* @requires vm.gc.Z & !vm.graal.enabled
|
||||
* @summary Test ZGC uncommit unused memory
|
||||
* @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=10 -XX:-ZUncommit gc.z.TestUncommit false 1
|
||||
*/
|
||||
|
||||
|
@ -30,12 +30,12 @@
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import org.testng.annotations.Test;
|
||||
import static java.lang.System.out;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
@ -116,13 +116,12 @@ public class StreamRefTest {
|
||||
public void basicRefWithInvalidA() throws Exception {
|
||||
out.println("\n---");
|
||||
var a = new A(3);
|
||||
Field f = A.class.getDeclaredField("x");
|
||||
f.setAccessible(true);
|
||||
f.set(a, -3); // a "bad" value
|
||||
var b = new B(a);
|
||||
assert a.x() == -3;
|
||||
|
||||
var byteStream = serialize(a, b);
|
||||
var bytes = serializeToBytes(a, b);
|
||||
// injects a bad (negative) value for field x (of record A), in the stream
|
||||
updateIntValue(3, -3, bytes, 40);
|
||||
var byteStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
|
||||
|
||||
InvalidObjectException ioe = expectThrows(IOE, () -> deserializeOne(byteStream));
|
||||
out.println("caught expected IOE: " + ioe);
|
||||
@ -138,13 +137,12 @@ public class StreamRefTest {
|
||||
public void reverseBasicRefWithInvalidA() throws Exception {
|
||||
out.println("\n---");
|
||||
var a = new A(3);
|
||||
Field f = A.class.getDeclaredField("x");
|
||||
f.setAccessible(true);
|
||||
f.set(a, -3); // a "bad" value
|
||||
var b = new B(a);
|
||||
assert a.x() == -3;
|
||||
|
||||
var byteStream = serialize(b, a);
|
||||
var bytes = serializeToBytes(b, a);
|
||||
// injects a bad (negative) value for field x (of record A), in the stream
|
||||
updateIntValue(3, -3, bytes, 96);
|
||||
var byteStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
|
||||
|
||||
InvalidObjectException ioe = expectThrows(IOE, () -> deserializeOne(byteStream));
|
||||
out.println("caught expected IOE: " + ioe);
|
||||
@ -209,14 +207,35 @@ public class StreamRefTest {
|
||||
|
||||
// ---
|
||||
|
||||
static void assertExpectedIntValue(int expectedValue, byte[] bytes, int offset)
|
||||
throws IOException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes, offset, 4);
|
||||
DataInputStream dis = new DataInputStream(bais);
|
||||
assertEquals(dis.readInt(), expectedValue);
|
||||
}
|
||||
|
||||
static void updateIntValue(int expectedValue, int newValue, byte[] bytes, int offset)
|
||||
throws IOException
|
||||
{
|
||||
assertExpectedIntValue(expectedValue, bytes, offset);
|
||||
bytes[offset + 0] = (byte)((newValue >>> 24) & 0xFF);
|
||||
bytes[offset + 1] = (byte)((newValue >>> 16) & 0xFF);
|
||||
bytes[offset + 2] = (byte)((newValue >>> 8) & 0xFF);
|
||||
bytes[offset + 3] = (byte)((newValue >>> 0) & 0xFF);
|
||||
assertExpectedIntValue(newValue, bytes, offset);
|
||||
}
|
||||
|
||||
static ObjectInputStream serialize(Object... objs) throws IOException {
|
||||
return new ObjectInputStream(new ByteArrayInputStream(serializeToBytes(objs)));
|
||||
}
|
||||
|
||||
static byte[] serializeToBytes(Object... objs) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
for (Object obj : objs)
|
||||
oos.writeObject(obj);
|
||||
oos.close();
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
return new ObjectInputStream(bais);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -28,6 +28,7 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -332,6 +333,73 @@ public class LinuxHelper {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.addInstallVerifier(cmd -> {
|
||||
// Verify .desktop files.
|
||||
try (var files = Files.walk(cmd.appLayout().destktopIntegrationDirectory(), 1)) {
|
||||
List<Path> desktopFiles = files
|
||||
.filter(path -> path.getFileName().toString().endsWith(".desktop"))
|
||||
.collect(Collectors.toList());
|
||||
if (!integrated) {
|
||||
TKit.assertStringListEquals(List.of(),
|
||||
desktopFiles.stream().map(Path::toString).collect(
|
||||
Collectors.toList()),
|
||||
"Check there are no .desktop files in the package");
|
||||
}
|
||||
for (var desktopFile : desktopFiles) {
|
||||
verifyDesktopFile(cmd, desktopFile);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile)
|
||||
throws IOException {
|
||||
TKit.trace(String.format("Check [%s] file BEGIN", desktopFile));
|
||||
List<String> lines = Files.readAllLines(desktopFile);
|
||||
TKit.assertEquals("[Desktop Entry]", lines.get(0), "Check file header");
|
||||
|
||||
Map<String, String> data = lines.stream()
|
||||
.skip(1)
|
||||
.peek(str -> TKit.assertTextStream("=").predicate(String::contains).apply(Stream.of(str)))
|
||||
.map(str -> {
|
||||
String components[] = str.split("=(?=.+)");
|
||||
if (components.length == 1) {
|
||||
return Map.entry(str.substring(0, str.length() - 1), "");
|
||||
}
|
||||
return Map.entry(components[0], components[1]);
|
||||
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {
|
||||
TKit.assertUnexpected("Multiple values of the same key");
|
||||
return null;
|
||||
}));
|
||||
|
||||
final Set<String> mandatoryKeys = new HashSet(Set.of("Name", "Comment",
|
||||
"Exec", "Icon", "Terminal", "Type", "Categories"));
|
||||
mandatoryKeys.removeAll(data.keySet());
|
||||
TKit.assertTrue(mandatoryKeys.isEmpty(), String.format(
|
||||
"Check for missing %s keys in the file", mandatoryKeys));
|
||||
|
||||
for (var e : Map.of("Type", "Application", "Terminal", "false").entrySet()) {
|
||||
String key = e.getKey();
|
||||
TKit.assertEquals(e.getValue(), data.get(key), String.format(
|
||||
"Check value of [%s] key", key));
|
||||
}
|
||||
|
||||
// Verify value of `Exec` property in .desktop files are escaped if required
|
||||
String launcherPath = data.get("Exec");
|
||||
if (Pattern.compile("\\s").matcher(launcherPath).find()) {
|
||||
TKit.assertTrue(launcherPath.startsWith("\"")
|
||||
&& launcherPath.endsWith("\""),
|
||||
"Check path to the launcher is enclosed in double quotes");
|
||||
launcherPath = launcherPath.substring(1, launcherPath.length() - 1);
|
||||
}
|
||||
|
||||
Stream.of(launcherPath, data.get("Icon"))
|
||||
.map(Path::of)
|
||||
.map(cmd::pathToUnpackedPackageFile)
|
||||
.forEach(TKit::assertFileExists);
|
||||
|
||||
TKit.trace(String.format("Check [%s] file END", desktopFile));
|
||||
}
|
||||
|
||||
static void initFileAssociationsTestFile(Path testFile) {
|
||||
|
@ -166,6 +166,8 @@ public class ShortcutHintTest {
|
||||
"Exec=APPLICATION_LAUNCHER",
|
||||
"Terminal=false",
|
||||
"Type=Application",
|
||||
"Comment=",
|
||||
"Icon=APPLICATION_ICON",
|
||||
"Categories=DEPLOY_BUNDLE_CATEGORY",
|
||||
expectedVersionString
|
||||
));
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8008949 8234051
|
||||
* @bug 8008949 8234051 8245696
|
||||
* @summary doclet crashes if HTML files in module doc-files directories
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
@ -33,6 +33,8 @@
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import toolbox.ToolBox;
|
||||
import javadoc.tester.JavadocTester;
|
||||
@ -134,4 +136,43 @@ public class TestDocFiles extends JavadocTester {
|
||||
checkOutput("m/p/doc-files/pkg-file.html", true,
|
||||
"Package HTML file");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadFiles(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
|
||||
tb.writeJavaFiles(src,
|
||||
"package p; public class C { }");
|
||||
Path df = src.resolve("p").resolve("doc-files");
|
||||
|
||||
// note that '?' may be an illegal filename character on some systems (e.g. Windows)
|
||||
List<String> cases = List.of("valid", "#bad#", "#bad", "bad#bad", "bad?bad");
|
||||
List<Path> files = new ArrayList<>();
|
||||
for (String s : cases) {
|
||||
try {
|
||||
Path f = df.resolve(s);
|
||||
tb.writeFile(f, "dummy contents");
|
||||
files.add(f);
|
||||
} catch (Throwable t) {
|
||||
out.println("Cannot write doc-file " + s);
|
||||
}
|
||||
}
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.OK);
|
||||
|
||||
// only check for those files
|
||||
for (Path f : files) {
|
||||
if (f.getFileName().toString().contains("valid")) {
|
||||
checkOutput("p/doc-files/" + f.getFileName(), true,
|
||||
"dummy contents");
|
||||
} else {
|
||||
// be careful handing file separator characters in the message
|
||||
checkOutput(Output.OUT, true,
|
||||
"warning - File " + f + " not copied: invalid name");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ public class TestJavaFX extends JavadocTester {
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
TestJavaFX tester = new TestJavaFX();
|
||||
tester.setAutomaticCheckAccessibility(false);
|
||||
tester.setAutomaticCheckLinks(false);
|
||||
tester.runTests();
|
||||
}
|
||||
|
||||
@ -353,6 +355,6 @@ public class TestJavaFX extends JavadocTester {
|
||||
checkExit(Exit.OK);
|
||||
|
||||
// make sure the doclet indeed emits the warning
|
||||
checkOutput(Output.OUT, true, "C.java:0: warning - invalid usage of tag >");
|
||||
checkOutput(Output.OUT, true, "C.java:0: warning - invalid usage of tag <");
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class C {
|
||||
/**
|
||||
* Defines the number of cycles in this animation. The {@code cycleCount}
|
||||
* may be {@code INDEFINITE} for animations that repeat indefinitely.
|
||||
* Now we add a > to deliberately cause an Html error.
|
||||
* Now we add <> to deliberately cause an Html error.
|
||||
* @defaultValue 11
|
||||
* @since JavaFX 8.0
|
||||
*/
|
||||
|
@ -46,7 +46,7 @@ public class TestPackageHtml extends JavadocTester {
|
||||
"-sourcepath", testSrc,
|
||||
"pkg1");
|
||||
checkExit(Exit.ERROR);
|
||||
checkOutput(Output.OUT, true, "package.html:5: error: bad use of '>'");
|
||||
checkOutput(Output.OUT, true, "package.html:4: error: malformed HTML");
|
||||
}
|
||||
|
||||
// Doclet must handle empty body in package.html, must
|
||||
|
@ -1,8 +1,7 @@
|
||||
<HTML>
|
||||
<BODY>
|
||||
<!-- generate a syntax error to verify that the file is parsed -->
|
||||
<pre>
|
||||
<opaque value="TRUE"/>
|
||||
<123 value="TRUE"/>
|
||||
</pre>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
@ -1,10 +1,8 @@
|
||||
|
||||
InvalidTag.java:14: error: unknown tag: String
|
||||
* List<String> list = new ArrayList<>();
|
||||
^
|
||||
InvalidTag.java:14: error: malformed HTML
|
||||
* List<String> list = new ArrayList<>();
|
||||
^
|
||||
InvalidTag.java:14: error: bad use of '>'
|
||||
* List<String> list = new ArrayList<>();
|
||||
^
|
||||
3 errors
|
||||
2 errors
|
||||
|
13
test/langtools/tools/javac/8238735/T8238735.java
Normal file
13
test/langtools/tools/javac/8238735/T8238735.java
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8238735
|
||||
* @summary javac should fail without throwing NPE
|
||||
* @compile/fail/ref=T8238735.out -XDrawDiagnostics T8238735.java
|
||||
*/
|
||||
|
||||
class T8238735 {
|
||||
public static void main(String[] args) {
|
||||
boolean first = true;
|
||||
first = first ? false : (boolean)(() -> false) ;
|
||||
}
|
||||
}
|
2
test/langtools/tools/javac/8238735/T8238735.out
Normal file
2
test/langtools/tools/javac/8238735/T8238735.out
Normal file
@ -0,0 +1,2 @@
|
||||
T8238735.java:11:43: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf: boolean)
|
||||
1 error
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*/
|
||||
|
||||
// key: compiler.err.dc.bad.gt
|
||||
// key: compiler.note.note
|
||||
// key: compiler.note.proc.messager
|
||||
// run: backdoor
|
||||
// options: -processor DocCommentProcessor -proc:only
|
||||
|
||||
/** > */
|
||||
class BadGreaterThan { }
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7021614 8078320
|
||||
* @bug 7021614 8078320 8247788
|
||||
* @summary extend com.sun.source API to support parsing javadoc comments
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.file
|
||||
@ -93,13 +93,8 @@ DocComment[DOC_COMMENT, pos:1
|
||||
void bad_gt() { }
|
||||
/*
|
||||
DocComment[DOC_COMMENT, pos:1
|
||||
firstSentence: 3
|
||||
Text[TEXT, pos:1, abc_]
|
||||
Erroneous[ERRONEOUS, pos:5
|
||||
code: compiler.err.dc.bad.gt
|
||||
body: >
|
||||
]
|
||||
Text[TEXT, pos:6, _def]
|
||||
firstSentence: 1
|
||||
Text[TEXT, pos:1, abc_>_def]
|
||||
body: empty
|
||||
block tags: empty
|
||||
]
|
||||
@ -111,18 +106,13 @@ DocComment[DOC_COMMENT, pos:1
|
||||
void bad_chars_start();
|
||||
/*
|
||||
DocComment[DOC_COMMENT, pos:1
|
||||
firstSentence: 5
|
||||
firstSentence: 3
|
||||
Text[TEXT, pos:1, abc_]
|
||||
Erroneous[ERRONEOUS, pos:5
|
||||
code: compiler.err.dc.malformed.html
|
||||
body: <
|
||||
]
|
||||
Text[TEXT, pos:6, p_123]
|
||||
Erroneous[ERRONEOUS, pos:11
|
||||
code: compiler.err.dc.bad.gt
|
||||
body: >
|
||||
]
|
||||
Text[TEXT, pos:12, _def]
|
||||
Text[TEXT, pos:6, p_123>_def]
|
||||
body: empty
|
||||
block tags: empty
|
||||
]
|
||||
@ -134,18 +124,13 @@ DocComment[DOC_COMMENT, pos:1
|
||||
void bad_chars_end();
|
||||
/*
|
||||
DocComment[DOC_COMMENT, pos:1
|
||||
firstSentence: 5
|
||||
firstSentence: 3
|
||||
Text[TEXT, pos:1, abc_]
|
||||
Erroneous[ERRONEOUS, pos:5
|
||||
code: compiler.err.dc.malformed.html
|
||||
body: <
|
||||
]
|
||||
Text[TEXT, pos:6, /p_123]
|
||||
Erroneous[ERRONEOUS, pos:12
|
||||
code: compiler.err.dc.bad.gt
|
||||
body: >
|
||||
]
|
||||
Text[TEXT, pos:13, _def]
|
||||
Text[TEXT, pos:6, /p_123>_def]
|
||||
body: empty
|
||||
block tags: empty
|
||||
]
|
||||
|
@ -1130,6 +1130,26 @@ public class RecordCompilationTests extends CompilationTestCase {
|
||||
this.args = args;
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
record R(@A int... ints) {}
|
||||
|
||||
@java.lang.annotation.Target({
|
||||
java.lang.annotation.ElementType.TYPE_USE,
|
||||
java.lang.annotation.ElementType.RECORD_COMPONENT})
|
||||
@interface A {}
|
||||
""",
|
||||
"""
|
||||
record R(@A int... ints) {
|
||||
R(@A int... ints) {
|
||||
this.ints = ints;
|
||||
}
|
||||
}
|
||||
|
||||
@java.lang.annotation.Target({
|
||||
java.lang.annotation.ElementType.TYPE_USE,
|
||||
java.lang.annotation.ElementType.RECORD_COMPONENT})
|
||||
@interface A {}
|
||||
"""
|
||||
)) {
|
||||
assertOK(source);
|
||||
|
487
test/langtools/tools/javac/sealed/BinaryCompatibilityTests.java
Normal file
487
test/langtools/tools/javac/sealed/BinaryCompatibilityTests.java
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* 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
|
||||
* @summary test binary compatibility rules for sealed classes
|
||||
* @library /tools/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.compiler/com.sun.tools.javac.util
|
||||
* jdk.compiler/com.sun.tools.javac.code
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* @build toolbox.ToolBox toolbox.JavacTask
|
||||
* @run main BinaryCompatibilityTests
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import com.sun.tools.classfile.*;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.util.Assert;
|
||||
import toolbox.TestRunner;
|
||||
import toolbox.ToolBox;
|
||||
import toolbox.JavaTask;
|
||||
import toolbox.JavacTask;
|
||||
import toolbox.Task;
|
||||
import toolbox.Task.OutputKind;
|
||||
|
||||
import static com.sun.tools.classfile.ConstantPool.*;
|
||||
|
||||
public class BinaryCompatibilityTests extends TestRunner {
|
||||
ToolBox tb;
|
||||
|
||||
BinaryCompatibilityTests() {
|
||||
super(System.err);
|
||||
tb = new ToolBox();
|
||||
}
|
||||
|
||||
protected void runTests() throws Exception {
|
||||
runTests(m -> new Object[]{Paths.get(m.getName())});
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
BinaryCompatibilityTests t = new BinaryCompatibilityTests();
|
||||
t.runTests();
|
||||
}
|
||||
|
||||
Path[] findJavaFiles(Path... paths) throws IOException {
|
||||
return tb.findJavaFiles(paths);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompatibilityAfterMakingSuperclassSealed(Path base) throws Exception {
|
||||
// sealing a super class which was not sealed, should fail with IncompatibleClassChangeError
|
||||
testCompatibilityAfterModifyingSupertype(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public class Super {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
public sealed class Super permits Sub1 {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
|
||||
final class Sub1 extends Super {}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
class Sub extends Super {}
|
||||
""",
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompatibilityAfterMakingSuperInterfaceSealed(Path base) throws Exception {
|
||||
// sealing a super interface which was not sealed, should fail with IncompatibleClassChangeError
|
||||
testCompatibilityAfterModifyingSupertype(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public interface Super {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
public sealed interface Super permits Sub1 {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
|
||||
final class Sub1 implements Super {}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
class Sub implements Super {}
|
||||
""",
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/* 1- compiles the first version of the superclass source code along with the subclass source code
|
||||
* 2- executes the super class just to make sure that it works
|
||||
* 3- compiles the second version of the super class along with the class file of the subclass
|
||||
* 4- executes the super class and makes sure that the VM throws IncompatibleClassChangeError or not
|
||||
* depending on the shouldFail argument
|
||||
*/
|
||||
private void testCompatibilityAfterModifyingSupertype(
|
||||
Path base,
|
||||
String superClassCode1,
|
||||
String superClassCode2,
|
||||
String subClassCode,
|
||||
boolean shouldFail) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
Path pkg = src.resolve("pkg");
|
||||
Path superClass = pkg.resolve("Super");
|
||||
Path sub = pkg.resolve("Sub");
|
||||
|
||||
// super class initially not sealed
|
||||
tb.writeJavaFiles(superClass, superClassCode1);
|
||||
tb.writeJavaFiles(sub, subClassCode);
|
||||
|
||||
Path out = base.resolve("out");
|
||||
Files.createDirectories(out);
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("--enable-preview",
|
||||
"-source", Integer.toString(Runtime.version().feature()))
|
||||
.outdir(out)
|
||||
.files(findJavaFiles(pkg))
|
||||
.run();
|
||||
|
||||
// let's execute to check that it's working
|
||||
String output = new JavaTask(tb)
|
||||
.vmOptions("--enable-preview")
|
||||
.classpath(out.toString())
|
||||
.classArgs("pkg.Super")
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDOUT);
|
||||
|
||||
// let's first check that it runs wo issues
|
||||
if (!output.contains("done")) {
|
||||
throw new AssertionError("execution of Super didn't finish");
|
||||
}
|
||||
|
||||
// now lets change the super class
|
||||
tb.writeJavaFiles(superClass, superClassCode2);
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("--enable-preview",
|
||||
"-source", Integer.toString(Runtime.version().feature()))
|
||||
.classpath(out)
|
||||
.outdir(out)
|
||||
.files(findJavaFiles(superClass))
|
||||
.run();
|
||||
|
||||
if (shouldFail) {
|
||||
// let's now check that there is an IncompatibleClassChangeError
|
||||
output = new JavaTask(tb)
|
||||
.vmOptions("--enable-preview")
|
||||
.classpath(out.toString())
|
||||
.classArgs("pkg.Super")
|
||||
.run(Task.Expect.FAIL)
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDERR);
|
||||
if (!output.startsWith("Exception in thread \"main\" java.lang.IncompatibleClassChangeError")) {
|
||||
throw new AssertionError("java.lang.IncompatibleClassChangeError expected");
|
||||
}
|
||||
} else {
|
||||
new JavaTask(tb)
|
||||
.vmOptions("--enable-preview")
|
||||
.classpath(out.toString())
|
||||
.classArgs("pkg.Super")
|
||||
.run(Task.Expect.SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSealedModifierToClass(Path base) throws Exception {
|
||||
// should execute without error
|
||||
testCompatibilityAfterModifyingSupertype(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public sealed class Super permits pkg.Sub {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
public class Super {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
final class Sub extends Super {}
|
||||
""",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSealedModifierToInterface(Path base) throws Exception {
|
||||
// should execute without error
|
||||
testCompatibilityAfterModifyingSupertype(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public sealed interface Super permits pkg.Sub {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
public interface Super {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
final class Sub implements Super {}
|
||||
""",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNonSealedModifierToClass(Path base) throws Exception {
|
||||
// should execute without error
|
||||
testCompatibilityOKAfterSubclassChange(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public sealed class Super permits pkg.Sub {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
final class Sub extends Super {}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
non-sealed class Sub extends Super {}
|
||||
"""
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNonSealedModifierToInterface(Path base) throws Exception {
|
||||
// should execute without error
|
||||
testCompatibilityOKAfterSubclassChange(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public sealed interface Super permits pkg.Sub {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
final class Sub implements Super {}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
non-sealed class Sub implements Super {}
|
||||
"""
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveNonSealedModifier(Path base) throws Exception {
|
||||
// should execute without error
|
||||
testCompatibilityOKAfterSubclassChange(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public sealed class Super permits pkg.Sub {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
non-sealed class Sub extends Super {}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
final class Sub extends Super {}
|
||||
"""
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveNonSealedModifierFromInterface(Path base) throws Exception {
|
||||
// should execute without error
|
||||
testCompatibilityOKAfterSubclassChange(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public sealed interface Super permits pkg.Sub {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub sub = new pkg.Sub();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
non-sealed class Sub implements Super {}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
final class Sub implements Super {}
|
||||
"""
|
||||
);
|
||||
}
|
||||
|
||||
/* 1- compiles the the superclass source code along with the first version of the subclass source code
|
||||
* 2- executes the super class just to make sure that it works
|
||||
* 3- compiles the second version of the subclass along with the class file of the superclass
|
||||
* 4- executes the super class and makes sure that it executes successfully
|
||||
*/
|
||||
private void testCompatibilityOKAfterSubclassChange(
|
||||
Path base,
|
||||
String superClassCode,
|
||||
String subClassCode1,
|
||||
String subClassCode2) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
Path pkg = src.resolve("pkg");
|
||||
Path superClass = pkg.resolve("Super");
|
||||
Path sub = pkg.resolve("Sub");
|
||||
|
||||
// super class initially sealed
|
||||
tb.writeJavaFiles(superClass, superClassCode);
|
||||
|
||||
tb.writeJavaFiles(sub, subClassCode1);
|
||||
|
||||
Path out = base.resolve("out");
|
||||
|
||||
Files.createDirectories(out);
|
||||
|
||||
new JavacTask(tb)
|
||||
.outdir(out)
|
||||
.options("--enable-preview",
|
||||
"-source", Integer.toString(Runtime.version().feature()))
|
||||
.files(findJavaFiles(pkg))
|
||||
.run();
|
||||
|
||||
// let's execute to check that it's working
|
||||
String output = new JavaTask(tb)
|
||||
.classpath(out.toString())
|
||||
.vmOptions("--enable-preview")
|
||||
.classArgs("pkg.Super")
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDOUT);
|
||||
|
||||
// let's first check that it runs wo issues
|
||||
if (!output.contains("done")) {
|
||||
throw new AssertionError("execution of Super didn't finish");
|
||||
}
|
||||
|
||||
// now lets remove the non-sealed modifier from class Sub
|
||||
tb.writeJavaFiles(sub, subClassCode2);
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("--enable-preview",
|
||||
"-source", Integer.toString(Runtime.version().feature()))
|
||||
.classpath(out)
|
||||
.outdir(out)
|
||||
.files(findJavaFiles(sub))
|
||||
.run();
|
||||
|
||||
// should execute without issues
|
||||
output = new JavaTask(tb)
|
||||
.vmOptions("--enable-preview")
|
||||
.classpath(out.toString())
|
||||
.classArgs("pkg.Super")
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDOUT);
|
||||
// let's first check that it runs wo issues
|
||||
if (!output.contains("done")) {
|
||||
throw new AssertionError("execution of Super didn't finish");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterChangingPermitsClause(Path base) throws Exception {
|
||||
// the VM will throw IncompatibleClassChangeError
|
||||
testCompatibilityAfterModifyingSupertype(
|
||||
base,
|
||||
"""
|
||||
package pkg;
|
||||
public sealed class Super permits pkg.Sub1, Sub2 {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub1 sub = new pkg.Sub1();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
|
||||
final class Sub2 extends Super {}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
public sealed class Super permits Sub2 {
|
||||
public static void main(String... args) {
|
||||
pkg.Sub1 sub = new pkg.Sub1();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
|
||||
final class Sub2 extends Super {}
|
||||
""",
|
||||
"""
|
||||
package pkg;
|
||||
final class Sub1 extends Super {}
|
||||
""",
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user