Fri, 29 Apr 2011 16:06:28 +0100
6550655: com.sun.tools.javac.code.Symbol$CompletionFailure
Summary: Accessing a non-existing enum constant from an annotation whose class is available results in an internal error
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Annotate.java Fri Apr 29 16:05:56 2011 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Annotate.java Fri Apr 29 16:06:28 2011 +0100 1.3 @@ -168,11 +168,11 @@ 1.4 } 1.5 JCIdent left = (JCIdent)assign.lhs; 1.6 Symbol method = rs.resolveQualifiedMethod(left.pos(), 1.7 - env, 1.8 - a.type, 1.9 - left.name, 1.10 - List.<Type>nil(), 1.11 - null); 1.12 + env, 1.13 + a.type, 1.14 + left.name, 1.15 + List.<Type>nil(), 1.16 + null); 1.17 left.sym = method; 1.18 left.type = method.type; 1.19 if (method.owner != a.type.tsym) 1.20 @@ -190,6 +190,15 @@ 1.21 Attribute enterAttributeValue(Type expected, 1.22 JCExpression tree, 1.23 Env<AttrContext> env) { 1.24 + //first, try completing the attribution value sym - if a completion 1.25 + //error is thrown, we should recover gracefully, and display an 1.26 + //ordinary resolution diagnostic. 1.27 + try { 1.28 + expected.tsym.complete(); 1.29 + } catch(CompletionFailure e) { 1.30 + log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym); 1.31 + return new Attribute.Error(expected); 1.32 + } 1.33 if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) { 1.34 Type result = attr.attribExpr(tree, env, expected); 1.35 if (result.isErroneous())
2.1 --- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Apr 29 16:05:56 2011 +0100 2.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Apr 29 16:06:28 2011 +0100 2.3 @@ -1609,18 +1609,31 @@ 2.4 // type.tsym.flatName() should == proxy.enumFlatName 2.5 TypeSymbol enumTypeSym = proxy.enumType.tsym; 2.6 VarSymbol enumerator = null; 2.7 - for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator); 2.8 - e.scope != null; 2.9 - e = e.next()) { 2.10 - if (e.sym.kind == VAR) { 2.11 - enumerator = (VarSymbol)e.sym; 2.12 - break; 2.13 + CompletionFailure failure = null; 2.14 + try { 2.15 + for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator); 2.16 + e.scope != null; 2.17 + e = e.next()) { 2.18 + if (e.sym.kind == VAR) { 2.19 + enumerator = (VarSymbol)e.sym; 2.20 + break; 2.21 + } 2.22 } 2.23 } 2.24 + catch (CompletionFailure ex) { 2.25 + failure = ex; 2.26 + } 2.27 if (enumerator == null) { 2.28 - log.error("unknown.enum.constant", 2.29 - currentClassFile, enumTypeSym, proxy.enumerator); 2.30 - result = new Attribute.Error(enumTypeSym.type); 2.31 + if (failure != null) { 2.32 + log.warning("unknown.enum.constant.reason", 2.33 + currentClassFile, enumTypeSym, proxy.enumerator, 2.34 + failure.getDiagnostic()); 2.35 + } else { 2.36 + log.warning("unknown.enum.constant", 2.37 + currentClassFile, enumTypeSym, proxy.enumerator); 2.38 + } 2.39 + result = new Attribute.Enum(enumTypeSym.type, 2.40 + new VarSymbol(0, proxy.enumerator, syms.botType, enumTypeSym)); 2.41 } else { 2.42 result = new Attribute.Enum(enumTypeSym.type, enumerator); 2.43 }
3.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Apr 29 16:05:56 2011 +0100 3.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Apr 29 16:06:28 2011 +0100 3.3 @@ -762,9 +762,6 @@ 3.4 compiler.err.unclosed.str.lit=\ 3.5 unclosed string literal 3.6 3.7 -compiler.err.unknown.enum.constant=\ 3.8 - in class file {0}: unknown enum constant {1}.{2} 3.9 - 3.10 # 0: name 3.11 compiler.err.unsupported.encoding=\ 3.12 unsupported encoding: {0} 3.13 @@ -1307,6 +1304,15 @@ 3.14 compiler.warn.annotation.method.not.found.reason=\ 3.15 Cannot find annotation method ''{1}()'' in type ''{0}'': {2} 3.16 3.17 +# 0: symbol, 1: name 3.18 +compiler.warn.unknown.enum.constant=\ 3.19 + unknown enum constant {1}.{2} 3.20 + 3.21 +# 0: symbol, 1: name, 2: message segment 3.22 +compiler.warn.unknown.enum.constant.reason=\ 3.23 + unknown enum constant {1}.{2}\n\ 3.24 + reason: {3} 3.25 + 3.26 # 0: type, 1: type 3.27 compiler.warn.raw.class.use=\ 3.28 found raw type: {0}\n\
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/tools/javac/annotations/6550655/T6550655.java Fri Apr 29 16:06:28 2011 +0100 4.3 @@ -0,0 +1,191 @@ 4.4 +/* 4.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. 4.11 + * 4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.15 + * version 2 for more details (a copy is included in the LICENSE file that 4.16 + * accompanied this code). 4.17 + * 4.18 + * You should have received a copy of the GNU General Public License version 4.19 + * 2 along with this work; if not, write to the Free Software Foundation, 4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.21 + * 4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.23 + * or visit www.oracle.com if you need additional information or have any 4.24 + * questions. 4.25 + */ 4.26 + 4.27 +/** 4.28 + * @test 4.29 + * @bug 6550655 4.30 + * @summary javac crashes when compiling against an annotated class 4.31 + */ 4.32 + 4.33 +import java.io.File; 4.34 +import java.net.URI; 4.35 +import java.util.Arrays; 4.36 + 4.37 +import javax.tools.Diagnostic; 4.38 +import javax.tools.DiagnosticListener; 4.39 +import javax.tools.JavaCompiler; 4.40 +import javax.tools.JavaCompiler.CompilationTask; 4.41 +import javax.tools.JavaFileObject; 4.42 +import javax.tools.SimpleJavaFileObject; 4.43 +import javax.tools.ToolProvider; 4.44 + 4.45 +public class T6550655 { 4.46 + 4.47 + JavaCompiler javacTool; 4.48 + File testDir; 4.49 + TestKind testKind; 4.50 + EnumActionKind actionKind; 4.51 + 4.52 + String testSource = "enum E { NORTH, SOUTH, WEST, EAST; }\n" + 4.53 + "@I(val = E.NORTH)class A {}\n" + 4.54 + "@interface I { E val(); }"; 4.55 + 4.56 + T6550655(JavaCompiler javacTool, File testDir, TestKind testKind, EnumActionKind actionKind) { 4.57 + this.javacTool = javacTool; 4.58 + this.testDir = testDir; 4.59 + this.testKind = testKind; 4.60 + this.actionKind = actionKind; 4.61 + } 4.62 + 4.63 + void test() { 4.64 + testDir.mkdirs(); 4.65 + compile(null, new JavaSource("Test.java", testSource)); 4.66 + actionKind.doAction(this); 4.67 + compile(new DiagnosticChecker(), testKind.source); 4.68 + } 4.69 + 4.70 + void compile(DiagnosticChecker dc, JavaSource... sources) { 4.71 + try { 4.72 + CompilationTask ct = javacTool.getTask(null, null, dc, 4.73 + Arrays.asList("-d", testDir.getAbsolutePath(), "-cp", testDir.getAbsolutePath()), 4.74 + null, Arrays.asList(sources)); 4.75 + ct.call(); 4.76 + } 4.77 + catch (Exception e) { 4.78 + error("Internal compilation error"); 4.79 + } 4.80 + } 4.81 + 4.82 + void replaceEnum(String newSource) { 4.83 + compile(null, new JavaSource("Replace.java", newSource)); 4.84 + }; 4.85 + 4.86 + void removeEnum() { 4.87 + File enumClass = new File(testDir, "E.class"); 4.88 + if (!enumClass.exists()) { 4.89 + error("Expected file E.class does not exists in folder " + testDir); 4.90 + } 4.91 + enumClass.delete(); 4.92 + }; 4.93 + 4.94 + void error(String msg) { 4.95 + System.err.println(msg); 4.96 + nerrors++; 4.97 + } 4.98 + 4.99 + class DiagnosticChecker implements DiagnosticListener<JavaFileObject> { 4.100 + 4.101 + String[][] expectedKeys = new String[][] { 4.102 + // DIRECT, INDIRECT 4.103 + {/*REPLACE1*/ "compiler.err.cant.resolve.location" , "compiler.warn.unknown.enum.constant" }, 4.104 + {/*REPLACE2*/ "compiler.err.cant.resolve.location.args", "compiler.warn.annotation.method.not.found" }, 4.105 + {/*REMOVE*/ "compiler.err.cant.resolve" , "compiler.warn.unknown.enum.constant.reason" } }; 4.106 + 4.107 + String keyToIgnore = "compiler.err.attribute.value.must.be.constant"; 4.108 + 4.109 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 4.110 + String expectedCode = expectedKeys[actionKind.ordinal()][testKind.ordinal()]; 4.111 + if (!diagnostic.getCode().equals(keyToIgnore) && 4.112 + !diagnostic.getCode().equals(expectedCode)) { 4.113 + error("Unexpected diagnostic" + 4.114 + "\nfound " + diagnostic.getCode() + 4.115 + "\nexpected " + expectedCode + 4.116 + "\ntestKind " + testKind + 4.117 + "\nactionKind " + actionKind); 4.118 + } 4.119 + } 4.120 + } 4.121 + 4.122 + //global declarations 4.123 + 4.124 + enum EnumActionKind { 4.125 + REPLACE1("enum E { SOUTH, WEST, EAST; }") { 4.126 + @Override 4.127 + void doAction(T6550655 test) { 4.128 + test.replaceEnum(optionalSource); 4.129 + } 4.130 + }, 4.131 + REPLACE2("@interface I { E valNew() default E.EAST; }") { 4.132 + @Override 4.133 + void doAction(T6550655 test) { 4.134 + test.replaceEnum(optionalSource); 4.135 + } 4.136 + }, 4.137 + REMOVE(null) { 4.138 + @Override 4.139 + void doAction(T6550655 test) { test.removeEnum(); } 4.140 + }; 4.141 + 4.142 + String optionalSource; 4.143 + 4.144 + private EnumActionKind(String optionalSource) { 4.145 + this.optionalSource = optionalSource; 4.146 + } 4.147 + 4.148 + abstract void doAction(T6550655 test); 4.149 + } 4.150 + 4.151 + enum TestKind { 4.152 + DIRECT("@I(val = E.NORTH)class C1 {}"), 4.153 + INDIRECT("class C2 { A a; }"); 4.154 + 4.155 + JavaSource source; 4.156 + 4.157 + private TestKind(final String code) { 4.158 + this.source = new JavaSource("Test.java", code); 4.159 + } 4.160 + } 4.161 + 4.162 + public static void main(String[] args) throws Exception { 4.163 + String SCRATCH_DIR = System.getProperty("user.dir"); 4.164 + JavaCompiler javacTool = ToolProvider.getSystemJavaCompiler(); 4.165 + int n = 0; 4.166 + for (TestKind testKind : TestKind.values()) { 4.167 + for (EnumActionKind actionKind : EnumActionKind.values()) { 4.168 + File testDir = new File(SCRATCH_DIR, "test"+n); 4.169 + new T6550655(javacTool, testDir, testKind, actionKind).test(); 4.170 + n++; 4.171 + } 4.172 + } 4.173 + if (nerrors > 0) { 4.174 + throw new AssertionError("Some errors have been detected"); 4.175 + } 4.176 + } 4.177 + 4.178 + static class JavaSource extends SimpleJavaFileObject { 4.179 + 4.180 + String source; 4.181 + 4.182 + public JavaSource(String filename, String source) { 4.183 + super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); 4.184 + this.source = source; 4.185 + } 4.186 + 4.187 + @Override 4.188 + public CharSequence getCharContent(boolean ignoreEncodingErrors) { 4.189 + return source; 4.190 + } 4.191 + } 4.192 + 4.193 + static int nerrors = 0; 4.194 +}
5.1 --- a/test/tools/javac/diags/examples.not-yet.txt Fri Apr 29 16:05:56 2011 +0100 5.2 +++ b/test/tools/javac/diags/examples.not-yet.txt Fri Apr 29 16:06:28 2011 +0100 5.3 @@ -41,7 +41,6 @@ 5.4 compiler.err.type.var.more.than.once.in.result # UNUSED 5.5 compiler.err.undetermined.type 5.6 compiler.err.unexpected.type 5.7 -compiler.err.unknown.enum.constant # in bad class file 5.8 compiler.err.unsupported.cross.fp.lit # Scanner: host system dependent 5.9 compiler.err.wrong.target.for.polymorphic.signature.definition # Transitional 292 5.10 compiler.misc.assignment.from.super-bound 5.11 @@ -112,3 +111,5 @@ 5.12 compiler.warn.unchecked.assign # DEAD, replaced by compiler.misc.unchecked.assign 5.13 compiler.warn.unchecked.cast.to.type # DEAD, replaced by compiler.misc.unchecked.cast.to.type 5.14 compiler.warn.unexpected.archive.file # Paths: zip file with unknown extn 5.15 +compiler.warn.unknown.enum.constant # in bad class file 5.16 +compiler.warn.unknown.enum.constant.reason # in bad class file