6550655: com.sun.tools.javac.code.Symbol$CompletionFailure

Accessing a non-existing enum constant from an annotation whose class is available results in an internal error

Reviewed-by: jjg
This commit is contained in:
Maurizio Cimadamore 2011-04-29 16:06:28 +01:00
parent 7fb85c5cef
commit ea2c9e0af0
5 changed files with 238 additions and 18 deletions
langtools
src/share/classes/com/sun/tools/javac
test/tools/javac
annotations/6550655
diags

@ -168,11 +168,11 @@ public class Annotate {
}
JCIdent left = (JCIdent)assign.lhs;
Symbol method = rs.resolveQualifiedMethod(left.pos(),
env,
a.type,
left.name,
List.<Type>nil(),
null);
env,
a.type,
left.name,
List.<Type>nil(),
null);
left.sym = method;
left.type = method.type;
if (method.owner != a.type.tsym)
@ -190,6 +190,15 @@ public class Annotate {
Attribute enterAttributeValue(Type expected,
JCExpression tree,
Env<AttrContext> env) {
//first, try completing the attribution value sym - if a completion
//error is thrown, we should recover gracefully, and display an
//ordinary resolution diagnostic.
try {
expected.tsym.complete();
} catch(CompletionFailure e) {
log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
return new Attribute.Error(expected);
}
if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) {
Type result = attr.attribExpr(tree, env, expected);
if (result.isErroneous())

@ -1609,18 +1609,31 @@ public class ClassReader implements Completer {
// type.tsym.flatName() should == proxy.enumFlatName
TypeSymbol enumTypeSym = proxy.enumType.tsym;
VarSymbol enumerator = null;
for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator);
e.scope != null;
e = e.next()) {
if (e.sym.kind == VAR) {
enumerator = (VarSymbol)e.sym;
break;
CompletionFailure failure = null;
try {
for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator);
e.scope != null;
e = e.next()) {
if (e.sym.kind == VAR) {
enumerator = (VarSymbol)e.sym;
break;
}
}
}
catch (CompletionFailure ex) {
failure = ex;
}
if (enumerator == null) {
log.error("unknown.enum.constant",
currentClassFile, enumTypeSym, proxy.enumerator);
result = new Attribute.Error(enumTypeSym.type);
if (failure != null) {
log.warning("unknown.enum.constant.reason",
currentClassFile, enumTypeSym, proxy.enumerator,
failure.getDiagnostic());
} else {
log.warning("unknown.enum.constant",
currentClassFile, enumTypeSym, proxy.enumerator);
}
result = new Attribute.Enum(enumTypeSym.type,
new VarSymbol(0, proxy.enumerator, syms.botType, enumTypeSym));
} else {
result = new Attribute.Enum(enumTypeSym.type, enumerator);
}

@ -762,9 +762,6 @@ compiler.err.unclosed.comment=\
compiler.err.unclosed.str.lit=\
unclosed string literal
compiler.err.unknown.enum.constant=\
in class file {0}: unknown enum constant {1}.{2}
# 0: name
compiler.err.unsupported.encoding=\
unsupported encoding: {0}
@ -1307,6 +1304,15 @@ compiler.warn.annotation.method.not.found=\
compiler.warn.annotation.method.not.found.reason=\
Cannot find annotation method ''{1}()'' in type ''{0}'': {2}
# 0: symbol, 1: name
compiler.warn.unknown.enum.constant=\
unknown enum constant {1}.{2}
# 0: symbol, 1: name, 2: message segment
compiler.warn.unknown.enum.constant.reason=\
unknown enum constant {1}.{2}\n\
reason: {3}
# 0: type, 1: type
compiler.warn.raw.class.use=\
found raw type: {0}\n\

@ -0,0 +1,191 @@
/*
* Copyright (c) 2011, 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
* @bug 6550655
* @summary javac crashes when compiling against an annotated class
*/
import java.io.File;
import java.net.URI;
import java.util.Arrays;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
public class T6550655 {
JavaCompiler javacTool;
File testDir;
TestKind testKind;
EnumActionKind actionKind;
String testSource = "enum E { NORTH, SOUTH, WEST, EAST; }\n" +
"@I(val = E.NORTH)class A {}\n" +
"@interface I { E val(); }";
T6550655(JavaCompiler javacTool, File testDir, TestKind testKind, EnumActionKind actionKind) {
this.javacTool = javacTool;
this.testDir = testDir;
this.testKind = testKind;
this.actionKind = actionKind;
}
void test() {
testDir.mkdirs();
compile(null, new JavaSource("Test.java", testSource));
actionKind.doAction(this);
compile(new DiagnosticChecker(), testKind.source);
}
void compile(DiagnosticChecker dc, JavaSource... sources) {
try {
CompilationTask ct = javacTool.getTask(null, null, dc,
Arrays.asList("-d", testDir.getAbsolutePath(), "-cp", testDir.getAbsolutePath()),
null, Arrays.asList(sources));
ct.call();
}
catch (Exception e) {
error("Internal compilation error");
}
}
void replaceEnum(String newSource) {
compile(null, new JavaSource("Replace.java", newSource));
};
void removeEnum() {
File enumClass = new File(testDir, "E.class");
if (!enumClass.exists()) {
error("Expected file E.class does not exists in folder " + testDir);
}
enumClass.delete();
};
void error(String msg) {
System.err.println(msg);
nerrors++;
}
class DiagnosticChecker implements DiagnosticListener<JavaFileObject> {
String[][] expectedKeys = new String[][] {
// DIRECT, INDIRECT
{/*REPLACE1*/ "compiler.err.cant.resolve.location" , "compiler.warn.unknown.enum.constant" },
{/*REPLACE2*/ "compiler.err.cant.resolve.location.args", "compiler.warn.annotation.method.not.found" },
{/*REMOVE*/ "compiler.err.cant.resolve" , "compiler.warn.unknown.enum.constant.reason" } };
String keyToIgnore = "compiler.err.attribute.value.must.be.constant";
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
String expectedCode = expectedKeys[actionKind.ordinal()][testKind.ordinal()];
if (!diagnostic.getCode().equals(keyToIgnore) &&
!diagnostic.getCode().equals(expectedCode)) {
error("Unexpected diagnostic" +
"\nfound " + diagnostic.getCode() +
"\nexpected " + expectedCode +
"\ntestKind " + testKind +
"\nactionKind " + actionKind);
}
}
}
//global declarations
enum EnumActionKind {
REPLACE1("enum E { SOUTH, WEST, EAST; }") {
@Override
void doAction(T6550655 test) {
test.replaceEnum(optionalSource);
}
},
REPLACE2("@interface I { E valNew() default E.EAST; }") {
@Override
void doAction(T6550655 test) {
test.replaceEnum(optionalSource);
}
},
REMOVE(null) {
@Override
void doAction(T6550655 test) { test.removeEnum(); }
};
String optionalSource;
private EnumActionKind(String optionalSource) {
this.optionalSource = optionalSource;
}
abstract void doAction(T6550655 test);
}
enum TestKind {
DIRECT("@I(val = E.NORTH)class C1 {}"),
INDIRECT("class C2 { A a; }");
JavaSource source;
private TestKind(final String code) {
this.source = new JavaSource("Test.java", code);
}
}
public static void main(String[] args) throws Exception {
String SCRATCH_DIR = System.getProperty("user.dir");
JavaCompiler javacTool = ToolProvider.getSystemJavaCompiler();
int n = 0;
for (TestKind testKind : TestKind.values()) {
for (EnumActionKind actionKind : EnumActionKind.values()) {
File testDir = new File(SCRATCH_DIR, "test"+n);
new T6550655(javacTool, testDir, testKind, actionKind).test();
n++;
}
}
if (nerrors > 0) {
throw new AssertionError("Some errors have been detected");
}
}
static class JavaSource extends SimpleJavaFileObject {
String source;
public JavaSource(String filename, String source) {
super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
this.source = source;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return source;
}
}
static int nerrors = 0;
}

@ -41,7 +41,6 @@ compiler.err.type.var.more.than.once # UNUSED
compiler.err.type.var.more.than.once.in.result # UNUSED
compiler.err.undetermined.type
compiler.err.unexpected.type
compiler.err.unknown.enum.constant # in bad class file
compiler.err.unsupported.cross.fp.lit # Scanner: host system dependent
compiler.err.wrong.target.for.polymorphic.signature.definition # Transitional 292
compiler.misc.assignment.from.super-bound
@ -112,3 +111,5 @@ compiler.warn.proc.type.already.exists # JavacFiler: just menti
compiler.warn.unchecked.assign # DEAD, replaced by compiler.misc.unchecked.assign
compiler.warn.unchecked.cast.to.type # DEAD, replaced by compiler.misc.unchecked.cast.to.type
compiler.warn.unexpected.archive.file # Paths: zip file with unknown extn
compiler.warn.unknown.enum.constant # in bad class file
compiler.warn.unknown.enum.constant.reason # in bad class file