8343540: Report preview error for inherited effectively-preview methods

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2024-12-04 09:47:40 +00:00
parent 994504c3e1
commit 56d315da48
3 changed files with 449 additions and 19 deletions

View File

@ -4728,7 +4728,7 @@ public class Attr extends JCTree.Visitor {
chk.checkDeprecated(tree.pos(), env.info.scope.owner, sym);
chk.checkSunAPI(tree.pos(), sym);
chk.checkProfile(tree.pos(), sym);
chk.checkPreview(tree.pos(), env.info.scope.owner, sym);
chk.checkPreview(tree.pos(), env.info.scope.owner, site, sym);
}
if (pt.isErroneous()) {

View File

@ -1845,7 +1845,8 @@ public class Check {
}
if (shouldCheckPreview(m, other, origin)) {
checkPreview(tree.pos(), m, other);
checkPreview(TreeInfo.diagnosticPositionFor(m, tree),
m, origin.type, other);
}
Type mt = types.memberType(origin.type, m);
@ -1925,7 +1926,8 @@ public class Check {
private boolean shouldCheckPreview(MethodSymbol m, MethodSymbol other, ClassSymbol origin) {
if (m.owner != origin ||
//performance - only do the expensive checks when the overridden method is a Preview API:
(other.flags() & PREVIEW_API) == 0) {
((other.flags() & PREVIEW_API) == 0 &&
(other.owner.flags() & PREVIEW_API) == 0)) {
return false;
}
@ -3828,8 +3830,29 @@ public class Check {
}
void checkPreview(DiagnosticPosition pos, Symbol other, Symbol s) {
if ((s.flags() & PREVIEW_API) != 0 && !preview.participatesInPreview(syms, other, s) && !disablePreviewCheck) {
if ((s.flags() & PREVIEW_REFLECTIVE) == 0) {
checkPreview(pos, other, Type.noType, s);
}
void checkPreview(DiagnosticPosition pos, Symbol other, Type site, Symbol s) {
boolean sIsPreview;
Symbol previewSymbol;
if ((s.flags() & PREVIEW_API) != 0) {
sIsPreview = true;
previewSymbol= s;
} else if ((s.kind == Kind.MTH || s.kind == Kind.VAR) &&
site.tsym != null &&
(site.tsym.flags() & PREVIEW_API) == 0 &&
(s.owner.flags() & PREVIEW_API) != 0) {
//calling a method, or using a field, whose owner is a preview, but
//using a site that is not a preview. Also produce an error or warning:
sIsPreview = true;
previewSymbol = s.owner;
} else {
sIsPreview = false;
previewSymbol = null;
}
if (sIsPreview && !preview.participatesInPreview(syms, other, s) && !disablePreviewCheck) {
if ((previewSymbol.flags() & PREVIEW_REFLECTIVE) == 0) {
if (!preview.isEnabled()) {
log.error(pos, Errors.IsPreview(s));
} else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 8282823
* @bug 8282823 8343540
* @library /tools/lib
* @enablePreview
* @modules
@ -229,13 +229,13 @@ public class PreviewTest extends TestRunner {
.getOutputLines(Task.OutputKind.DIRECT);
List<String> expected =
List.of("IUseIntf2P.java:3:8: compiler.err.is.preview: test()",
"IUseIntfDef2P.java:3:8: compiler.err.is.preview: test()",
List.of("IUseIntf2P.java:4:25: compiler.err.is.preview: test()",
"IUseIntfDef2P.java:4:25: compiler.err.is.preview: test()",
"UseClass2P.java:4:17: compiler.err.is.preview: test()",
"UseIntf2P.java:3:8: compiler.err.is.preview: test()",
"UseIntfDef2P.java:3:8: compiler.err.is.preview: test()",
"UseIntf2P.java:4:17: compiler.err.is.preview: test()",
"UseIntfDef2P.java:4:17: compiler.err.is.preview: test()",
"UseSubClass12P.java:3:17: compiler.err.is.preview: test()",
"UseSubIntfDef12P.java:2:8: compiler.err.is.preview: test()",
"UseSubIntfDef12P.java:3:17: compiler.err.is.preview: test()",
"7 errors");
if (!log.equals(expected))
@ -257,13 +257,13 @@ public class PreviewTest extends TestRunner {
.getOutputLines(Task.OutputKind.DIRECT);
expected =
List.of("IUseIntf2P.java:3:8: compiler.warn.is.preview: test()",
"IUseIntfDef2P.java:3:8: compiler.warn.is.preview: test()",
List.of("IUseIntf2P.java:4:25: compiler.warn.is.preview: test()",
"IUseIntfDef2P.java:4:25: compiler.warn.is.preview: test()",
"UseClass2P.java:4:17: compiler.warn.is.preview: test()",
"UseIntf2P.java:3:8: compiler.warn.is.preview: test()",
"UseIntfDef2P.java:3:8: compiler.warn.is.preview: test()",
"UseIntf2P.java:4:17: compiler.warn.is.preview: test()",
"UseIntfDef2P.java:4:17: compiler.warn.is.preview: test()",
"UseSubClass12P.java:3:17: compiler.warn.is.preview: test()",
"UseSubIntfDef12P.java:2:8: compiler.warn.is.preview: test()",
"UseSubIntfDef12P.java:3:17: compiler.warn.is.preview: test()",
"7 warnings");
if (!log.equals(expected))
@ -392,7 +392,7 @@ public class PreviewTest extends TestRunner {
.getOutputLines(Task.OutputKind.DIRECT);
List<String> expected =
List.of("AbstractP.java:3:17: compiler.err.is.preview: test()",
List.of("AbstractP.java:4:26: compiler.err.is.preview: test()",
"ReabstractP.java:4:26: compiler.err.is.preview: test()",
"2 errors");
@ -415,7 +415,7 @@ public class PreviewTest extends TestRunner {
.getOutputLines(Task.OutputKind.DIRECT);
expected =
List.of("AbstractP.java:3:17: compiler.warn.is.preview: test()",
List.of("AbstractP.java:4:26: compiler.warn.is.preview: test()",
"ReabstractP.java:4:26: compiler.warn.is.preview: test()",
"2 warnings");
@ -463,6 +463,413 @@ public class PreviewTest extends TestRunner {
}
}
@Test //JDK-8343540:
public void nonPreviewImplementsPreview(Path base) throws Exception {
Path apiSrc = base.resolve("api-src");
tb.writeJavaFiles(apiSrc,
"""
package preview.api;
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST)
public interface Preview {
public static final int FIELD = 0;
public default void test() {}
}
""",
"""
package preview.api;
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST,
reflective=true)
public interface ReflectivePreview {
public default void test() {}
}
""",
"""
package preview.api;
public interface NonPreviewIntf extends Preview {
}
""",
"""
package preview.api;
public class NonPreview implements Preview {
}
""",
"""
package preview.api;
public class ReflectiveNonPreview implements ReflectivePreview {
}
""");
Path apiClasses = base.resolve("api-classes");
new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(apiClasses)
.options("--patch-module", "java.base=" + apiSrc.toString(),
"-Werror")
.files(tb.findJavaFiles(apiSrc))
.run()
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
Path testSrc = base.resolve("test-src");
tb.writeJavaFiles(testSrc,
"""
package test;
import preview.api.NonPreview;
import preview.api.NonPreviewIntf;
import preview.api.Preview;
import preview.api.ReflectiveNonPreview;
public class Test {
public void test(NonPreview np,
Produce<? extends NonPreview> prod) {
np.test();
acceptRunnable(np::test);
accept(NonPreview::test);
prod.produce().test();
acceptRunnable(prod.produce()::test);
int i = np.FIELD;
}
public <T1 extends NonPreview,
T2 extends Test & NonPreviewIntf,
T3 extends T2> void test(T1 t1, T2 t2, T3 t3) {
t1.test();
t2.test();
t3.test();
}
public void test(ReflectiveNonPreview np) {
np.test();
}
public void test(Preview p) {
p.test();
acceptRunnable(p::test);
accept(Preview::test);
}
private static class ExtendsNonPreview extends NonPreview {
public void test() {} //error/warning here:
}
private static class ImplementsPreview implements Preview {
//no error/warning (already was on Preview after implements)
public void test() {}
}
private static class ImplicitReceiver extends NonPreview {
public void g() {
test(); //implicit this - error/warning
int i = FIELD; //implicit this - error/warning
}
}
private void acceptRunnable(Runnable r) {}
private void accept(Accept<NonPreview> accept) {}
interface Accept<T> {
public void accept(T t);
}
interface Produce<T> {
public T produce();
}
}
""");
Path testClasses = base.resolve("test-classes");
List<String> log = new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(testClasses)
.options("--patch-module", "java.base=" + apiClasses.toString(),
"--add-exports", "java.base/preview.api=ALL-UNNAMED",
"-XDrawDiagnostics")
.files(tb.findJavaFiles(testSrc))
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
List<String> expected =
List.of("Test.java:4:19: compiler.err.is.preview: preview.api.Preview",
"Test.java:26:22: compiler.err.is.preview: preview.api.Preview",
"Test.java:34:55: compiler.err.is.preview: preview.api.Preview",
"Test.java:9:11: compiler.err.is.preview: test()",
"Test.java:10:24: compiler.err.is.preview: test()",
"Test.java:11:16: compiler.err.is.preview: test()",
"Test.java:12:23: compiler.err.is.preview: test()",
"Test.java:13:24: compiler.err.is.preview: test()",
"Test.java:14:19: compiler.err.is.preview: FIELD",
"Test.java:19:11: compiler.err.is.preview: test()",
"Test.java:20:11: compiler.err.is.preview: test()",
"Test.java:21:11: compiler.err.is.preview: test()",
"Test.java:24:11: compiler.warn.is.preview.reflective: test()",
"Test.java:29:16: compiler.err.is.preview: preview.api.Preview",
"Test.java:32:21: compiler.err.is.preview: test()",
"Test.java:36:21: compiler.err.is.preview: test()",
"Test.java:40:13: compiler.err.is.preview: test()",
"Test.java:41:21: compiler.err.is.preview: FIELD",
"17 errors",
"1 warning");
if (!log.equals(expected))
throw new Exception("expected output not found" + log);
}
@Test //JDK-8343540:
public void nonPreviewImplementsPreview2(Path base) throws Exception {
Path apiSrc = base.resolve("api-src");
tb.writeJavaFiles(apiSrc,
"""
package preview.api;
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST)
public interface Preview {
public default void test() {}
}
""",
"""
package preview.api;
public interface NonPreviewIntf extends Preview {
public default void test() {}
}
""",
"""
package preview.api;
public class NonPreview implements Preview {
public void test() {}
}
""");
Path apiClasses = base.resolve("api-classes");
new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(apiClasses)
.options("--patch-module", "java.base=" + apiSrc.toString(),
"-Werror")
.files(tb.findJavaFiles(apiSrc))
.run()
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
Path testSrc = base.resolve("test-src");
tb.writeJavaFiles(testSrc,
"""
package test;
import preview.api.NonPreview;
import preview.api.NonPreviewIntf;
public class Test {
public void test(NonPreview np1,
NonPreviewIntf np2) {
np1.test();
np2.test();
}
}
""");
Path testClasses = base.resolve("test-classes");
List<String> log = new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(testClasses)
.options("--patch-module", "java.base=" + apiClasses.toString(),
"--add-exports", "java.base/preview.api=ALL-UNNAMED",
"-XDrawDiagnostics")
.files(tb.findJavaFiles(testSrc))
.run(Task.Expect.SUCCESS)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
}
@Test //JDK-8343540:
public void nonPreviewImplementsPreview3(Path base) throws Exception {
Path apiSrc = base.resolve("api-src");
tb.writeJavaFiles(apiSrc,
"""
package preview.api;
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST)
public class Preview {
public int field;
public static void test() {}
}
""",
"""
package preview.api;
public class NonPreview extends Preview {
}
""");
Path apiClasses = base.resolve("api-classes");
new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(apiClasses)
.options("--patch-module", "java.base=" + apiSrc.toString(),
"-Werror")
.files(tb.findJavaFiles(apiSrc))
.run()
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
Path testSrc = base.resolve("test-src");
tb.writeJavaFiles(testSrc,
"""
package test;
import preview.api.NonPreview;
import preview.api.Preview;
public class Test {
public void test(NonPreview np, Preview p) {
NonPreview.test();
Preview.test();
int i1 = np.field;
int i2 = p.field;
}
}
""");
Path testClasses = base.resolve("test-classes");
List<String> log = new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(testClasses)
.options("--patch-module", "java.base=" + apiClasses.toString(),
"--add-exports", "java.base/preview.api=ALL-UNNAMED",
"-XDrawDiagnostics")
.files(tb.findJavaFiles(testSrc))
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
List<String> expected =
List.of("Test.java:3:19: compiler.err.is.preview: preview.api.Preview",
"Test.java:5:37: compiler.err.is.preview: preview.api.Preview",
"Test.java:6:19: compiler.err.is.preview: test()",
"Test.java:7:9: compiler.err.is.preview: preview.api.Preview",
"Test.java:8:20: compiler.err.is.preview: field",
"5 errors");
if (!log.equals(expected))
throw new Exception("expected output not found" + log);
}
@Test //JDK-8343540:
public void nonPreviewImplementsPreview4(Path base) throws Exception {
Path apiSrc = base.resolve("api-src");
tb.writeJavaFiles(apiSrc,
"""
package preview.api;
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST)
public class Preview {
public int field;
public static void test() {}
}
""",
"""
package preview.api;
public class NonPreview extends Preview {
public int field;
public static void test() {}
}
""");
Path apiClasses = base.resolve("api-classes");
new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(apiClasses)
.options("--patch-module", "java.base=" + apiSrc.toString(),
"-Werror")
.files(tb.findJavaFiles(apiSrc))
.run()
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
Path testSrc = base.resolve("test-src");
tb.writeJavaFiles(testSrc,
"""
package test;
import preview.api.NonPreview;
import preview.api.Preview;
public class Test {
public void test(NonPreview np, Preview p) {
NonPreview.test();
Preview.test();
int i1 = np.field;
int i2 = p.field;
}
}
""");
Path testClasses = base.resolve("test-classes");
List<String> log = new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(testClasses)
.options("--patch-module", "java.base=" + apiClasses.toString(),
"--add-exports", "java.base/preview.api=ALL-UNNAMED",
"-XDrawDiagnostics")
.files(tb.findJavaFiles(testSrc))
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
List<String> expected =
List.of("Test.java:3:19: compiler.err.is.preview: preview.api.Preview",
"Test.java:5:37: compiler.err.is.preview: preview.api.Preview",
"Test.java:7:9: compiler.err.is.preview: preview.api.Preview",
"3 errors");
if (!log.equals(expected))
throw new Exception("expected output not found" + log);
}
@Test //JDK-8343540:
public void nonPreviewImplementsPreview5(Path base) throws Exception {
Path apiSrc = base.resolve("api-src");
tb.writeJavaFiles(apiSrc,
"""
package preview.api;
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST)
public interface Preview {
public static final int CONST1 = 0;
public static final int CONST2 = 0;
}
""",
"""
package preview.api;
public interface NonPreviewIntf extends Preview {
public static final int CONST2 = 0;
}
""",
"""
package preview.api;
public class NonPreview implements Preview {
public static final int CONST2 = 0;
}
""");
Path apiClasses = base.resolve("api-classes");
new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(apiClasses)
.options("--patch-module", "java.base=" + apiSrc.toString(),
"-Werror")
.files(tb.findJavaFiles(apiSrc))
.run()
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
Path testSrc = base.resolve("test-src");
tb.writeJavaFiles(testSrc,
"""
package test;
import preview.api.NonPreview;
import preview.api.NonPreviewIntf;
import preview.api.Preview;
public class Test {
public void test() {
int i1 = NonPreview.CONST1;
int i2 = NonPreviewIntf.CONST1;
int i3 = Preview.CONST1;
int i4 = NonPreview.CONST2;
int i5 = NonPreviewIntf.CONST2;
int i6 = Preview.CONST2;
}
}
""");
Path testClasses = base.resolve("test-classes");
List<String> log = new JavacTask(tb, Task.Mode.CMDLINE)
.outdir(testClasses)
.options("--patch-module", "java.base=" + apiClasses.toString(),
"--add-exports", "java.base/preview.api=ALL-UNNAMED",
"-XDrawDiagnostics")
.files(tb.findJavaFiles(testSrc))
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
List<String> expected =
List.of("Test.java:4:19: compiler.err.is.preview: preview.api.Preview",
"Test.java:7:28: compiler.err.is.preview: CONST1",
"Test.java:8:32: compiler.err.is.preview: CONST1",
"Test.java:9:18: compiler.err.is.preview: preview.api.Preview",
"Test.java:12:18: compiler.err.is.preview: preview.api.Preview",
"5 errors");
if (!log.equals(expected))
throw new Exception("expected output not found" + log);
}
private int verifyPreviewClassfiles(Path directory) throws Exception {
Path[] classfiles = tb.findFiles("class", directory);