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:
parent
7fb85c5cef
commit
ea2c9e0af0
langtools
src/share/classes/com/sun/tools/javac
test/tools/javac
@ -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\
|
||||
|
191
langtools/test/tools/javac/annotations/6550655/T6550655.java
Normal file
191
langtools/test/tools/javac/annotations/6550655/T6550655.java
Normal file
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user