# HG changeset patch # User mcimadamore # Date 1304089588 -3600 # Node ID dc3d9ef880a1d0d5b5c587d34a13d10ac787ff3b # Parent 1092b67b3cadaec3b2c099747e35ab363390b4b9 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 diff -r 1092b67b3cad -r dc3d9ef880a1 src/share/classes/com/sun/tools/javac/comp/Annotate.java --- a/src/share/classes/com/sun/tools/javac/comp/Annotate.java Fri Apr 29 16:05:56 2011 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/Annotate.java Fri Apr 29 16:06:28 2011 +0100 @@ -168,11 +168,11 @@ } JCIdent left = (JCIdent)assign.lhs; Symbol method = rs.resolveQualifiedMethod(left.pos(), - env, - a.type, - left.name, - List.nil(), - null); + env, + a.type, + left.name, + List.nil(), + null); left.sym = method; left.type = method.type; if (method.owner != a.type.tsym) @@ -190,6 +190,15 @@ Attribute enterAttributeValue(Type expected, JCExpression tree, Env 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()) diff -r 1092b67b3cad -r dc3d9ef880a1 src/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Apr 29 16:05:56 2011 +0100 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Apr 29 16:06:28 2011 +0100 @@ -1609,18 +1609,31 @@ // 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); } diff -r 1092b67b3cad -r dc3d9ef880a1 src/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Apr 29 16:05:56 2011 +0100 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Apr 29 16:06:28 2011 +0100 @@ -762,9 +762,6 @@ 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.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\ diff -r 1092b67b3cad -r dc3d9ef880a1 test/tools/javac/annotations/6550655/T6550655.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/annotations/6550655/T6550655.java Fri Apr 29 16:06:28 2011 +0100 @@ -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 { + + 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 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; +} diff -r 1092b67b3cad -r dc3d9ef880a1 test/tools/javac/diags/examples.not-yet.txt --- a/test/tools/javac/diags/examples.not-yet.txt Fri Apr 29 16:05:56 2011 +0100 +++ b/test/tools/javac/diags/examples.not-yet.txt Fri Apr 29 16:06:28 2011 +0100 @@ -41,7 +41,6 @@ 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.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