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
32import java.io.File;
33import java.net.URI;
34import java.util.Arrays;
35
36import javax.tools.Diagnostic;
37import javax.tools.DiagnosticListener;
38import javax.tools.JavaCompiler;
39import javax.tools.JavaCompiler.CompilationTask;
40import javax.tools.JavaFileObject;
41import javax.tools.SimpleJavaFileObject;
42import javax.tools.ToolProvider;
43
44public 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
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
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
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
81    void replaceEnum(String newSource) {
82        compile(null, new JavaSource("Replace.java", newSource));
83    };
84
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
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
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
126            void doAction(T6550655 test) {
127                test.replaceEnum(optionalSource);
128            }
129        },
130        REPLACE2("@interface I { E valNew() default E.EAST; }") {
131            @Override
132            void doAction(T6550655 test) {
133                test.replaceEnum(optionalSource);
134            }
135        },
136        REMOVE(null) {
137            @Override
138            void doAction(T6550655 test) { test.removeEnum(); }
139        };
140
141        String optionalSource;
142
143        private EnumActionKind(String optionalSource) {
144            this.optionalSource = optionalSource;
145        }
146
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
156        private TestKind(final String code) {
157            this.source = new JavaSource("Test.java", code);
158        }
159    }
160
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
181        public JavaSource(String filename, String source) {
182            super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
183            this.source = source;
184        }
185
186        @Override
187        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
188            return source;
189        }
190    }
191
192    static int nerrors = 0;
193}
194