From 270a2da99775fd24fbccbc03c7de40d6ac4fa843 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 4 Dec 2025 17:03:57 +0100 Subject: [PATCH 1/2] 8373094: javac may fail because of unattributed break in a loop --- .../com/sun/tools/javac/comp/Attr.java | 16 +- .../tools/javac/recovery/AttrRecovery.java | 152 +++++++++++++++++- 2 files changed, 161 insertions(+), 7 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 3f72ada94e8d3..cc21113882f69 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5634,12 +5634,16 @@ private void attribClassBody(Env env, ClassSymbol c) { chk.validateRepeatable(c, repeatable, cbPos); } } else { - // Check that all extended classes and interfaces - // are compatible (i.e. no two define methods with same arguments - // yet different return types). (JLS 8.4.8.3) - chk.checkCompatibleSupertypes(tree.pos(), c.type); - chk.checkDefaultMethodClashes(tree.pos(), c.type); - chk.checkPotentiallyAmbiguousOverloads(tree, c.type); + try { + // Check that all extended classes and interfaces + // are compatible (i.e. no two define methods with same arguments + // yet different return types). (JLS 8.4.8.3) + chk.checkCompatibleSupertypes(tree.pos(), c.type); + chk.checkDefaultMethodClashes(tree.pos(), c.type); + chk.checkPotentiallyAmbiguousOverloads(tree, c.type); + } catch (CompletionFailure cf) { + chk.completionError(tree.pos(), cf); + } } // Check that class does not import the same parameterized interface diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 9a37ce60654aa..391cae85b2313 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 8373094 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -32,8 +32,11 @@ * @run main AttrRecovery */ +import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.MemberReferenceTree; +import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.MethodTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; @@ -41,11 +44,13 @@ import com.sun.source.util.Trees; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.lang.model.element.Element; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; @@ -495,4 +500,149 @@ private void verifyElement() { } } } + + @Test //JDK-8373094 + public void testSensibleAttribution() throws Exception { + Path curPath = Path.of("."); + Path lib = curPath.resolve("lib"); + Path classes = lib.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .outdir(classes) + .sources(""" + package test; + public class Intermediate extends Base {} + """, + """ + package test; + public class Base { + public void t(Missing m) {} + } + """, + """ + package test; + public class Missing { + } + """) + .run() + .writeAll(); + + Files.delete(classes.resolve("test").resolve("Missing.class")); + + record TestCase(String code, List options, String... expectedErrors) {} + TestCase[] testCases = new TestCase[] { + new TestCase(""" + package test; + public class Test extends Intermediate { + private void test() { + int i = 0; + System.err.println(i); + } + } + """, + List.of(), + "Test.java:2:8: compiler.err.cant.access: test.Missing, (compiler.misc.class.file.not.found: test.Missing)", + "1 error"), + new TestCase(""" + package test; + public class Test extends Intermediate { + private void test() { + int i = 0; + System.err.println(i); + } + } + """, + List.of("-XDshould-stop.at=FLOW"), + "Test.java:2:8: compiler.err.cant.access: test.Missing, (compiler.misc.class.file.not.found: test.Missing)", + "1 error"), + }; + + for (TestCase tc : testCases) { + List attributes = new ArrayList<>(); + List actual = new JavacTask(tb) + .options(Stream.concat(List.of("-XDrawDiagnostics", "-XDdev").stream(), + tc.options.stream()).toList()) + .classpath(classes) + .sources(tc.code()) + .outdir(curPath) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + boolean check; + + @Override + public Void visitMethod(MethodTree node, Void p) { + if (node.getName().contentEquals("test")) { + check = true; + try { + return super.visitMethod(node, p); + } finally { + check = false; + } + } + + return super.visitMethod(node, p); + } + + @Override + public Void visitMethodInvocation(MethodInvocationTree node, Void p) { + if (!node.toString().contains("super")) { + verifyElement(); + } + return super.visitMethodInvocation(node, p); + } + + @Override + public Void visitIdentifier(IdentifierTree node, Void p) { + verifyElement(); + return super.visitIdentifier(node, p); + } + + @Override + public Void visitMemberSelect(MemberSelectTree node, Void p) { + verifyElement(); + return super.visitMemberSelect(node, p); + } + + private void verifyElement() { + if (!check) { + return ; + } + + Element el = trees.getElement(getCurrentPath()); + if (el == null) { + error("Unattributed tree: " + getCurrentPath().getLeaf()); + } else { + attributes.add(el.toString()); + } + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expectedErrors = List.of(tc.expectedErrors); + + if (!Objects.equals(actual, expectedErrors)) { + error("Expected: " + expectedErrors + ", but got: " + actual); + } + + List expectedAttributes = + List.of("println(int)", "println(int)", "err", "java.lang.System", "i"); + + if (!Objects.equals(attributes, expectedAttributes)) { + error("Expected: " + expectedAttributes + ", but got: " + attributes); + } + } + } + } From fd60a0f4026ee20b2b53c6cae3b3577a7b67a196 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 5 Dec 2025 17:22:24 +0100 Subject: [PATCH 2/2] Improving test. --- test/langtools/tools/javac/recovery/AttrRecovery.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 391cae85b2313..ac1455e71d74c 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -537,6 +537,9 @@ public class Test extends Intermediate { private void test() { int i = 0; System.err.println(i); + while (true) { + break; + } } } """, @@ -549,6 +552,9 @@ public class Test extends Intermediate { private void test() { int i = 0; System.err.println(i); + while (true) { + break; + } } } """,