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 7101822
27 * @summary static import fails to resolve interfaces on nested enums via import statements
28 * @modules jdk.compiler
29 */
30
31import com.sun.source.util.JavacTask;
32import java.net.URI;
33import java.util.Arrays;
34import javax.tools.Diagnostic;
35import javax.tools.JavaCompiler;
36import javax.tools.JavaFileObject;
37import javax.tools.SimpleJavaFileObject;
38import javax.tools.StandardJavaFileManager;
39import javax.tools.ToolProvider;
40
41public class TestLazyImportScope {
42
43    static int checkCount = 0;
44
45    enum ImportOrder {
46        NORMAL("import a.C.D;\n" +
47               "#I"),
48        REVERSE("#I\n" +
49               "import a.C.D;");
50
51        String importLayout;
52
53        ImportOrder(String importLayout) {
54            this.importLayout = importLayout;
55        }
56
57        String getImportString(ImportKind ik) {
58            return importLayout.replaceAll("#I", ik.importStr);
59        }
60    }
61
62    enum ImportKind {
63        NAMED("import a.A.B.E;"),
64        ON_DEMAND("import a.A.B.*;"),
65        STATIC_NAMED_TYPE("import static a.A.B.E;"),
66        STATIC_NAMED_MEMBER("import static a.A.B.bm;"),
67        STATIC_ON_DEMAND("import static a.A.B.*;");
68
69        String importStr;
70
71        private ImportKind(String importStr) {
72            this.importStr = importStr;
73        }
74    }
75
76    enum TypeRefKind {
77        NONE(""),
78        E("E e = null;"),
79        F("F f = null;"),
80        BOTH("E e = null; F f = null;");
81
82        String typeRefStr;
83
84        private TypeRefKind(String typeRefStr) {
85            this.typeRefStr = typeRefStr;
86        }
87
88        boolean isImported(ImportKind ik) {
89            switch (ik) {
90                case NAMED:
91                case STATIC_NAMED_TYPE: return this == NONE || this == E;
92                case ON_DEMAND:
93                case STATIC_ON_DEMAND: return true;
94                default: return this == NONE;
95            }
96        }
97    }
98
99    enum MemberRefKind {
100        NONE(""),
101        FIELD("Object o = bf;"),
102        METHOD("bm();"),
103        BOTH("Object o = bf; bm();");
104
105        String memberRefStr;
106
107        private MemberRefKind(String memberRefStr) {
108            this.memberRefStr = memberRefStr;
109        }
110
111        boolean isImported(ImportKind ik) {
112            switch (ik) {
113                case STATIC_NAMED_MEMBER: return this == NONE || this == METHOD;
114                case STATIC_ON_DEMAND: return true;
115                default: return this == NONE;
116            }
117        }
118    }
119
120    public static void main(String... args) throws Exception {
121
122        //create default shared JavaCompiler - reused across multiple compilations
123        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
124        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
125
126        for (ImportOrder ord : ImportOrder.values()) {
127            for (ImportKind ik : ImportKind.values()) {
128                for (TypeRefKind tk : TypeRefKind.values()) {
129                    for (MemberRefKind mk : MemberRefKind.values()) {
130                        new TestLazyImportScope(ord, ik, tk, mk).run(comp, fm);
131                    }
132                }
133            }
134        }
135        System.out.println("Total check executed: " + checkCount);
136    }
137
138    ImportOrder ord;
139    ImportKind ik;
140    TypeRefKind tk;
141    MemberRefKind mk;
142    JavaSource source;
143    DiagnosticChecker diagChecker;
144
145    TestLazyImportScope(ImportOrder ord, ImportKind ik, TypeRefKind tk, MemberRefKind mk) {
146        this.ord = ord;
147        this.ik = ik;
148        this.tk = tk;
149        this.mk = mk;
150        this.source = new JavaSource();
151        this.diagChecker = new DiagnosticChecker();
152    }
153
154    class JavaSource extends SimpleJavaFileObject {
155
156        String bodyTemplate = "package a;\n" +
157                              "#I\n" +
158                              "class A {\n" +
159                              "   static class B extends D {\n" +
160                              "      static class E { }\n" +
161                              "      static class F { }\n" +
162                              "      static Object bf;\n" +
163                              "      static void bm() { }\n" +
164                              "   }\n" +
165                              "}\n" +
166                              "class C {\n" +
167                              "   static class D { }\n" +
168                              "}\n" +
169                              "class Test {\n" +
170                              "   void test() {\n" +
171                              "      #T\n" +
172                              "      #M\n" +
173                              "   }\n" +
174                              "}";
175
176        String source;
177
178        public JavaSource() {
179            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
180            source = bodyTemplate.replaceAll("#I", ord.getImportString(ik))
181                    .replaceAll("#T", tk.typeRefStr)
182                    .replaceAll("#M", mk.memberRefStr);
183        }
184
185        @Override
186        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
187            return source;
188        }
189    }
190
191    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
192        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
193                null, null, Arrays.asList(source));
194        try {
195            ct.analyze();
196        } catch (Throwable ex) {
197            throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true));
198        }
199        check();
200    }
201
202    void check() {
203        checkCount++;
204
205        boolean errorExpected = !tk.isImported(ik) || !mk.isImported(ik);
206
207        if (errorExpected != diagChecker.errorFound) {
208            throw new Error("invalid diagnostics for source:\n" +
209                source.getCharContent(true) +
210                "\nFound error: " + diagChecker.errorFound +
211                "\nExpected error: " + errorExpected);
212        }
213    }
214
215    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
216
217        boolean errorFound;
218
219        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
220            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
221                errorFound = true;
222            }
223        }
224    }
225}
226