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

Fri, 29 Apr 2011 16:06:28 +0100

author
mcimadamore
date
Fri, 29 Apr 2011 16:06:28 +0100
changeset 992
dc3d9ef880a1
parent 991
1092b67b3cad
child 993
4caf17560ae0

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

src/share/classes/com/sun/tools/javac/comp/Annotate.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/ClassReader.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/resources/compiler.properties file | annotate | diff | comparison | revisions
test/tools/javac/annotations/6550655/T6550655.java file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples.not-yet.txt file | annotate | diff | comparison | revisions
     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

mercurial