1 /*
2  * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /**
25  * @test
26  * @bug     6550655
27  * @summary javac crashes when compiling against an annotated class
28  * @modules java.compiler
29  *          jdk.compiler
30  */
31 
32 import java.io.File;
33 import java.net.URI;
34 import java.util.Arrays;
35 
36 import javax.tools.Diagnostic;
37 import javax.tools.DiagnosticListener;
38 import javax.tools.JavaCompiler;
39 import javax.tools.JavaCompiler.CompilationTask;
40 import javax.tools.JavaFileObject;
41 import javax.tools.SimpleJavaFileObject;
42 import javax.tools.ToolProvider;
43 
44 public class T6550655 {
45 
46     JavaCompiler javacTool;
47     File testDir;
48     TestKind testKind;
49     EnumActionKind actionKind;
50 
51     String testSource = "enum E { NORTH, SOUTH, WEST, EAST; }\n" +
52                         "@I(val = E.NORTH)class A {}\n" +
53                         "@interface I { E val(); }";
54 
T6550655(JavaCompiler javacTool, File testDir, TestKind testKind, EnumActionKind actionKind)55     T6550655(JavaCompiler javacTool, File testDir, TestKind testKind, EnumActionKind actionKind) {
56         this.javacTool = javacTool;
57         this.testDir = testDir;
58         this.testKind = testKind;
59         this.actionKind = actionKind;
60     }
61 
test()62     void test() {
63         testDir.mkdirs();
64         compile(null, new JavaSource("Test.java", testSource));
65         actionKind.doAction(this);
66         compile(new DiagnosticChecker(), testKind.source);
67     }
68 
compile(DiagnosticChecker dc, JavaSource... sources)69     void compile(DiagnosticChecker dc, JavaSource... sources) {
70         try {
71             CompilationTask ct = javacTool.getTask(null, null, dc,
72                     Arrays.asList("-d", testDir.getAbsolutePath(), "-cp", testDir.getAbsolutePath()),
73                     null, Arrays.asList(sources));
74             ct.call();
75         }
76         catch (Exception e) {
77             error("Internal compilation error");
78         }
79     }
80 
replaceEnum(String newSource)81     void replaceEnum(String newSource) {
82         compile(null, new JavaSource("Replace.java", newSource));
83     };
84 
removeEnum()85     void removeEnum() {
86         File enumClass = new File(testDir, "E.class");
87         if (!enumClass.exists()) {
88             error("Expected file E.class does not exists in folder " + testDir);
89         }
90         enumClass.delete();
91     };
92 
error(String msg)93     void error(String msg) {
94         System.err.println(msg);
95         nerrors++;
96     }
97 
98     class DiagnosticChecker implements DiagnosticListener<JavaFileObject> {
99 
100         String[][] expectedKeys = new String[][] {
101          //             DIRECT,                                         INDIRECT
102         {/*REPLACE1*/   "compiler.err.cant.resolve.location"     ,      "compiler.warn.unknown.enum.constant" },
103         {/*REPLACE2*/   "compiler.err.cant.resolve.location.args",      "compiler.warn.annotation.method.not.found" },
104         {/*REMOVE*/     "compiler.err.cant.resolve"              ,      "compiler.warn.unknown.enum.constant.reason" } };
105 
106         String keyToIgnore = "compiler.err.attribute.value.must.be.constant";
107 
report(Diagnostic<? extends JavaFileObject> diagnostic)108         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
109             String expectedCode = expectedKeys[actionKind.ordinal()][testKind.ordinal()];
110             if (!diagnostic.getCode().equals(keyToIgnore) &&
111                     !diagnostic.getCode().equals(expectedCode)) {
112                 error("Unexpected diagnostic" +
113                       "\nfound " + diagnostic.getCode() +
114                       "\nexpected " + expectedCode +
115                       "\ntestKind " + testKind +
116                       "\nactionKind " + actionKind);
117             }
118         }
119     }
120 
121     //global declarations
122 
123     enum EnumActionKind {
124         REPLACE1("enum E { SOUTH, WEST, EAST; }") {
125             @Override
doAction(T6550655 test)126             void doAction(T6550655 test) {
127                 test.replaceEnum(optionalSource);
128             }
129         },
130         REPLACE2("@interface I { E valNew() default E.EAST; }") {
131             @Override
doAction(T6550655 test)132             void doAction(T6550655 test) {
133                 test.replaceEnum(optionalSource);
134             }
135         },
REMOVE(null)136         REMOVE(null) {
137             @Override
138             void doAction(T6550655 test) { test.removeEnum(); }
139         };
140 
141         String optionalSource;
142 
EnumActionKind(String optionalSource)143         private EnumActionKind(String optionalSource) {
144             this.optionalSource = optionalSource;
145         }
146 
doAction(T6550655 test)147         abstract void doAction(T6550655 test);
148     }
149 
150     enum TestKind {
151         DIRECT("@I(val = E.NORTH)class C1 {}"),
152         INDIRECT("class C2 { A a; }");
153 
154         JavaSource source;
155 
TestKind(final String code)156         private TestKind(final String code) {
157             this.source = new JavaSource("Test.java", code);
158         }
159     }
160 
main(String[] args)161     public static void main(String[] args) throws Exception {
162         String SCRATCH_DIR = System.getProperty("user.dir");
163         JavaCompiler javacTool = ToolProvider.getSystemJavaCompiler();
164         int n = 0;
165         for (TestKind testKind : TestKind.values()) {
166             for (EnumActionKind actionKind : EnumActionKind.values()) {
167                 File testDir = new File(SCRATCH_DIR, "test"+n);
168                 new T6550655(javacTool, testDir, testKind, actionKind).test();
169                 n++;
170             }
171         }
172         if (nerrors > 0) {
173             throw new AssertionError("Some errors have been detected");
174         }
175     }
176 
177     static class JavaSource extends SimpleJavaFileObject {
178 
179         String source;
180 
JavaSource(String filename, String source)181         public JavaSource(String filename, String source) {
182             super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
183             this.source = source;
184         }
185 
186         @Override
getCharContent(boolean ignoreEncodingErrors)187         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
188             return source;
189         }
190     }
191 
192     static int nerrors = 0;
193 }
194