Skip to content

Commit 3500150

Browse files
committed
8373094: javac may fail because of unattributed break in a loop
Reviewed-by: vromero
1 parent 7da9153 commit 3500150

File tree

2 files changed

+167
-7
lines changed

2 files changed

+167
-7
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5634,12 +5634,16 @@ private void attribClassBody(Env<AttrContext> env, ClassSymbol c) {
56345634
chk.validateRepeatable(c, repeatable, cbPos);
56355635
}
56365636
} else {
5637-
// Check that all extended classes and interfaces
5638-
// are compatible (i.e. no two define methods with same arguments
5639-
// yet different return types). (JLS 8.4.8.3)
5640-
chk.checkCompatibleSupertypes(tree.pos(), c.type);
5641-
chk.checkDefaultMethodClashes(tree.pos(), c.type);
5642-
chk.checkPotentiallyAmbiguousOverloads(tree, c.type);
5637+
try {
5638+
// Check that all extended classes and interfaces
5639+
// are compatible (i.e. no two define methods with same arguments
5640+
// yet different return types). (JLS 8.4.8.3)
5641+
chk.checkCompatibleSupertypes(tree.pos(), c.type);
5642+
chk.checkDefaultMethodClashes(tree.pos(), c.type);
5643+
chk.checkPotentiallyAmbiguousOverloads(tree, c.type);
5644+
} catch (CompletionFailure cf) {
5645+
chk.completionError(tree.pos(), cf);
5646+
}
56435647
}
56445648

56455649
// Check that class does not import the same parameterized interface

test/langtools/tools/javac/recovery/AttrRecovery.java

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336
26+
* @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 8373094
2727
* @summary Verify error recovery w.r.t. Attr
2828
* @library /tools/lib
2929
* @modules jdk.compiler/com.sun.tools.javac.api
@@ -32,20 +32,25 @@
3232
* @run main AttrRecovery
3333
*/
3434

35+
import com.sun.source.tree.IdentifierTree;
3536
import com.sun.source.tree.MemberReferenceTree;
37+
import com.sun.source.tree.MemberSelectTree;
3638
import com.sun.source.tree.MethodInvocationTree;
39+
import com.sun.source.tree.MethodTree;
3740
import com.sun.source.tree.VariableTree;
3841
import com.sun.source.util.TaskEvent;
3942
import com.sun.source.util.TaskListener;
4043
import com.sun.source.util.TreePathScanner;
4144
import com.sun.source.util.Trees;
4245
import java.nio.file.Files;
4346
import java.nio.file.Path;
47+
import java.util.ArrayList;
4448
import java.util.IdentityHashMap;
4549
import java.util.List;
4650
import java.util.Map;
4751
import java.util.Objects;
4852
import java.util.stream.Collectors;
53+
import java.util.stream.Stream;
4954
import javax.lang.model.element.Element;
5055
import javax.lang.model.element.VariableElement;
5156
import javax.lang.model.type.DeclaredType;
@@ -495,4 +500,155 @@ private void verifyElement() {
495500
}
496501
}
497502
}
503+
504+
@Test //JDK-8373094
505+
public void testSensibleAttribution() throws Exception {
506+
Path curPath = Path.of(".");
507+
Path lib = curPath.resolve("lib");
508+
Path classes = lib.resolve("classes");
509+
Files.createDirectories(classes);
510+
new JavacTask(tb)
511+
.outdir(classes)
512+
.sources("""
513+
package test;
514+
public class Intermediate<T> extends Base<T> {}
515+
""",
516+
"""
517+
package test;
518+
public class Base<T> {
519+
public void t(Missing<T> m) {}
520+
}
521+
""",
522+
"""
523+
package test;
524+
public class Missing<T> {
525+
}
526+
""")
527+
.run()
528+
.writeAll();
529+
530+
Files.delete(classes.resolve("test").resolve("Missing.class"));
531+
532+
record TestCase(String code, List<String> options, String... expectedErrors) {}
533+
TestCase[] testCases = new TestCase[] {
534+
new TestCase("""
535+
package test;
536+
public class Test extends Intermediate<String> {
537+
private void test() {
538+
int i = 0;
539+
System.err.println(i);
540+
while (true) {
541+
break;
542+
}
543+
}
544+
}
545+
""",
546+
List.of(),
547+
"Test.java:2:8: compiler.err.cant.access: test.Missing, (compiler.misc.class.file.not.found: test.Missing)",
548+
"1 error"),
549+
new TestCase("""
550+
package test;
551+
public class Test extends Intermediate<String> {
552+
private void test() {
553+
int i = 0;
554+
System.err.println(i);
555+
while (true) {
556+
break;
557+
}
558+
}
559+
}
560+
""",
561+
List.of("-XDshould-stop.at=FLOW"),
562+
"Test.java:2:8: compiler.err.cant.access: test.Missing, (compiler.misc.class.file.not.found: test.Missing)",
563+
"1 error"),
564+
};
565+
566+
for (TestCase tc : testCases) {
567+
List<String> attributes = new ArrayList<>();
568+
List<String> actual = new JavacTask(tb)
569+
.options(Stream.concat(List.of("-XDrawDiagnostics", "-XDdev").stream(),
570+
tc.options.stream()).toList())
571+
.classpath(classes)
572+
.sources(tc.code())
573+
.outdir(curPath)
574+
.callback(task -> {
575+
task.addTaskListener(new TaskListener() {
576+
@Override
577+
public void finished(TaskEvent e) {
578+
if (e.getKind() != TaskEvent.Kind.ANALYZE) {
579+
return ;
580+
}
581+
Trees trees = Trees.instance(task);
582+
new TreePathScanner<Void, Void>() {
583+
boolean check;
584+
585+
@Override
586+
public Void visitMethod(MethodTree node, Void p) {
587+
if (node.getName().contentEquals("test")) {
588+
check = true;
589+
try {
590+
return super.visitMethod(node, p);
591+
} finally {
592+
check = false;
593+
}
594+
}
595+
596+
return super.visitMethod(node, p);
597+
}
598+
599+
@Override
600+
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
601+
if (!node.toString().contains("super")) {
602+
verifyElement();
603+
}
604+
return super.visitMethodInvocation(node, p);
605+
}
606+
607+
@Override
608+
public Void visitIdentifier(IdentifierTree node, Void p) {
609+
verifyElement();
610+
return super.visitIdentifier(node, p);
611+
}
612+
613+
@Override
614+
public Void visitMemberSelect(MemberSelectTree node, Void p) {
615+
verifyElement();
616+
return super.visitMemberSelect(node, p);
617+
}
618+
619+
private void verifyElement() {
620+
if (!check) {
621+
return ;
622+
}
623+
624+
Element el = trees.getElement(getCurrentPath());
625+
if (el == null) {
626+
error("Unattributed tree: " + getCurrentPath().getLeaf());
627+
} else {
628+
attributes.add(el.toString());
629+
}
630+
}
631+
}.scan(e.getCompilationUnit(), null);
632+
}
633+
});
634+
})
635+
.run(Expect.FAIL)
636+
.writeAll()
637+
.getOutputLines(OutputKind.DIRECT);
638+
639+
List<String> expectedErrors = List.of(tc.expectedErrors);
640+
641+
if (!Objects.equals(actual, expectedErrors)) {
642+
error("Expected: " + expectedErrors + ", but got: " + actual);
643+
}
644+
645+
List<String> expectedAttributes =
646+
List.of("println(int)", "println(int)", "err", "java.lang.System", "i");
647+
648+
if (!Objects.equals(attributes, expectedAttributes)) {
649+
error("Expected: " + expectedAttributes + ", but got: " + attributes);
650+
}
651+
}
652+
}
653+
498654
}

0 commit comments

Comments
 (0)