8247334: Trees.getScope crashes for annotated local records

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2020-06-12 13:38:06 +02:00
parent 56d333c538
commit 19c5bfe42f
2 changed files with 82 additions and 8 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac/comp
test/langtools/tools/javac/api

@ -995,11 +995,13 @@ public class TypeEnter implements Completer {
ClassSymbol sym = tree.sym;
ClassType ct = (ClassType)sym.type;
JCTree defaultConstructor = null;
// Add default constructor if needed.
DefaultConstructorHelper helper = getDefaultConstructorHelper(env);
if (helper != null) {
JCTree constrDef = defaultConstructor(make.at(tree.pos), helper);
tree.defs = tree.defs.prepend(constrDef);
defaultConstructor = defaultConstructor(make.at(tree.pos), helper);
tree.defs = tree.defs.prepend(defaultConstructor);
}
if (!sym.isRecord()) {
enterThisAndSuper(sym, env);
@ -1011,7 +1013,7 @@ public class TypeEnter implements Completer {
}
}
finishClass(tree, env);
finishClass(tree, defaultConstructor, env);
if (allowTypeAnnos) {
typeAnnotations.organizeTypeAnnotationsSignatures(env, (JCClassDecl)env.tree);
@ -1052,7 +1054,7 @@ public class TypeEnter implements Completer {
/** Enter members for a class.
*/
void finishClass(JCClassDecl tree, Env<AttrContext> env) {
void finishClass(JCClassDecl tree, JCTree defaultConstructor, Env<AttrContext> env) {
if ((tree.mods.flags & Flags.ENUM) != 0 &&
!tree.sym.type.hasTag(ERROR) &&
(types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) {
@ -1063,9 +1065,7 @@ public class TypeEnter implements Completer {
if (isRecord) {
alreadyEntered = List.convert(JCTree.class, TreeInfo.recordFields(tree));
alreadyEntered = alreadyEntered.prependList(tree.defs.stream()
.filter(t -> TreeInfo.isConstructor(t) &&
((JCMethodDecl)t).sym != null &&
(((JCMethodDecl)t).sym.flags_field & Flags.GENERATEDCONSTR) == 0).collect(List.collector()));
.filter(t -> TreeInfo.isConstructor(t) && t != defaultConstructor).collect(List.collector()));
}
List<JCTree> defsToEnter = isRecord ?
tree.defs.diff(alreadyEntered) : tree.defs;

@ -23,7 +23,7 @@
/*
* @test
* @bug 8205418 8207229 8207230 8230847 8245786
* @bug 8205418 8207229 8207230 8230847 8245786 8247334
* @summary Test the outcomes from Trees.getScope
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.comp
@ -42,6 +42,7 @@ import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
@ -80,6 +81,7 @@ public class TestGetScopeResult {
new TestGetScopeResult().testAnnotationsLazy();
new TestGetScopeResult().testCircular();
new TestGetScopeResult().testRecord();
new TestGetScopeResult().testLocalRecordAnnotation();
}
public void run() throws IOException {
@ -562,6 +564,78 @@ public class TestGetScopeResult {
}
}
void testLocalRecordAnnotation() throws IOException {
JavacTool c = JavacTool.create();
try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) {
class Variant {
final String code;
final List<List<String>> expectedScopeContent;
public Variant(String code, List<List<String>> expectedScopeContent) {
this.code = code;
this.expectedScopeContent = expectedScopeContent;
}
}
Variant[] variants = new Variant[] {
new Variant("""
class Test {
void t() {
record R(@Annotation int i) {
void stop () {}
}
}
}
@interface Annotation {}
""",
List.of(
List.of("super:java.lang.Object", "this:Test"),
List.of("super:java.lang.Object", "this:Test")
)),
new Variant("""
record Test(@Annotation int i) {}
@interface Annotation {}
""",
List.of(
List.of("i:int", "super:java.lang.Record", "this:Test"),
List.of("super:java.lang.Record", "this:Test")
))
};
for (Variant currentVariant : variants) {
class MyFileObject extends SimpleJavaFileObject {
MyFileObject() {
super(URI.create("myfo:///Test.java"), SOURCE);
}
@Override
public String getCharContent(boolean ignoreEncodingErrors) {
return currentVariant.code;
}
}
Context ctx = new Context();
TestAnalyzer.preRegister(ctx);
List<String> options = List.of("--enable-preview",
"-source", System.getProperty("java.specification.version"));
JavacTask t = (JavacTask) c.getTask(null, fm, null, options, null,
List.of(new MyFileObject()), ctx);
CompilationUnitTree cut = t.parse().iterator().next();
t.analyze();
List<List<String>> actual = new ArrayList<>();
new TreePathScanner<Void, Void>() {
@Override
public Void visitAnnotation(AnnotationTree node, Void p) {
Scope scope = Trees.instance(t).getScope(getCurrentPath());
actual.add(dumpScope(scope));
return super.visitAnnotation(node, p);
}
}.scan(cut, null);
if (!currentVariant.expectedScopeContent.equals(actual)) {
throw new AssertionError("Unexpected Scope content: " + actual);
}
}
}
}
private List<String> dumpScope(Scope scope) {
List<String> content = new ArrayList<>();
while (scope.getEnclosingClass() != null) {