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     7046348
27  * @summary Regression: javac complains of missing classfile for a seemingly unrelated interface
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 import java.util.List;
36 
37 import javax.tools.Diagnostic;
38 import javax.tools.DiagnosticListener;
39 import javax.tools.JavaCompiler;
40 import javax.tools.JavaCompiler.CompilationTask;
41 import javax.tools.JavaFileObject;
42 import javax.tools.SimpleJavaFileObject;
43 import javax.tools.ToolProvider;
44 
45 public class EagerInterfaceCompletionTest {
46 
47     JavaCompiler javacTool;
48     File testDir;
49     VersionKind versionKind;
50     HierarchyKind hierarchyKind;
51     TestKind testKind;
52     ActionKind actionKind;
53 
EagerInterfaceCompletionTest(JavaCompiler javacTool, File testDir, VersionKind versionKind, HierarchyKind hierarchyKind, TestKind testKind, ActionKind actionKind)54     EagerInterfaceCompletionTest(JavaCompiler javacTool, File testDir, VersionKind versionKind,
55             HierarchyKind hierarchyKind, TestKind testKind, ActionKind actionKind) {
56         this.javacTool = javacTool;
57         this.versionKind = versionKind;
58         this.hierarchyKind = hierarchyKind;
59         this.testDir = testDir;
60         this.testKind = testKind;
61         this.actionKind = actionKind;
62     }
63 
test()64     void test() {
65         testDir.mkdirs();
66         compile(null, hierarchyKind.source);
67         actionKind.doAction(this);
68         DiagnosticChecker dc = new DiagnosticChecker();
69         compile(dc, testKind.source);
70         if (testKind.completionFailure(versionKind, actionKind, hierarchyKind) != dc.errorFound) {
71             if (dc.errorFound) {
72                 error("Unexpected completion failure" +
73                       "\nhierarhcyKind " + hierarchyKind +
74                       "\ntestKind " + testKind +
75                       "\nactionKind " + actionKind);
76             } else {
77                 error("Missing completion failure " +
78                           "\nhierarhcyKind " + hierarchyKind +
79                           "\ntestKind " + testKind +
80                           "\nactionKind " + actionKind);
81             }
82         }
83     }
84 
compile(DiagnosticChecker dc, JavaSource... sources)85     void compile(DiagnosticChecker dc, JavaSource... sources) {
86         try {
87             CompilationTask ct = javacTool.getTask(null, null, dc,
88                     Arrays.asList("-d", testDir.getAbsolutePath(), "-cp",
89                     testDir.getAbsolutePath(), versionKind.optsArr[0], versionKind.optsArr[1]),
90                     null, Arrays.asList(sources));
91             ct.call();
92         }
93         catch (Exception e) {
94             e.printStackTrace();
95             error("Internal compilation error");
96         }
97     }
98 
removeClass(String classToRemoveStr)99     void removeClass(String classToRemoveStr) {
100         File classToRemove = new File(testDir, classToRemoveStr);
101         if (!classToRemove.exists()) {
102             error("Expected file " + classToRemove + " does not exists in folder " + testDir);
103         }
104         classToRemove.delete();
105     };
106 
error(String msg)107     void error(String msg) {
108         System.err.println(msg);
109         nerrors++;
110     }
111 
112     class DiagnosticChecker implements DiagnosticListener<JavaFileObject> {
113 
114         boolean errorFound = false;
115 
report(Diagnostic<? extends JavaFileObject> diagnostic)116         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
117             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
118                 errorFound = true;
119             }
120         }
121     }
122 
123     //global declarations
124 
125     enum VersionKind {
126         PRE_LAMBDA("-source", "7"),
127         LAMBDA("-source", "8");
128 
129         String[] optsArr;
130 
VersionKind(String... optsArr)131         VersionKind(String... optsArr) {
132             this.optsArr = optsArr;
133         }
134     }
135 
136     enum HierarchyKind {
137         INTERFACE("interface A { boolean f = false; void m(); }\n" +
138                   "class B implements A { public void m() {} }"),
139         CLASS("class A { boolean f; void m() {} }\n" +
140               "class B extends A { void m() {} }"),
141         ABSTRACT_CLASS("abstract class A { boolean f; abstract void m(); }\n" +
142                        "class B extends A { void m() {} }");
143 
144         JavaSource source;
145 
HierarchyKind(String code)146         private HierarchyKind(String code) {
147             this.source = new JavaSource("Test1.java", code);
148         }
149     }
150 
151     enum ActionKind {
152         REMOVE_A("A.class"),
153         REMOVE_B("B.class");
154 
155         String classFile;
156 
ActionKind(String classFile)157         private ActionKind(String classFile) {
158             this.classFile = classFile;
159         }
160 
doAction(EagerInterfaceCompletionTest test)161         void doAction(EagerInterfaceCompletionTest test) {
162             test.removeClass(classFile);
163         };
164     }
165 
166     enum TestKind {
167         ACCESS_ONLY("class C { B b; }"),
168         SUPER("class C extends B {}"),
169         METHOD("class C { void test(B b) { b.m(); } }"),
170         FIELD("class C { void test(B b) { boolean b2 = b.f; } }"),
171         CONSTR("class C { void test() { new B(); } }");
172 
173         JavaSource source;
174 
TestKind(final String code)175         private TestKind(final String code) {
176             this.source = new JavaSource("Test2.java", code);
177         }
178 
completionFailure(VersionKind vk, ActionKind ak, HierarchyKind hk)179         boolean completionFailure(VersionKind vk, ActionKind ak, HierarchyKind hk) {
180             switch (this) {
181                 case ACCESS_ONLY:
182                 case CONSTR: return ak == ActionKind.REMOVE_B;
183                 case FIELD:
184                 case SUPER: return true;
185                 case METHOD: return hk != HierarchyKind.INTERFACE || ak == ActionKind.REMOVE_B ||
186                         (hk == HierarchyKind.INTERFACE && ak == ActionKind.REMOVE_A);
187                 default: throw new AssertionError("Unexpected test kind " + this);
188             }
189         }
190     }
191 
main(String[] args)192     public static void main(String[] args) throws Exception {
193         String SCRATCH_DIR = System.getProperty("user.dir");
194         JavaCompiler javacTool = ToolProvider.getSystemJavaCompiler();
195         int n = 0;
196         for (VersionKind versionKind : VersionKind.values()) {
197             for (HierarchyKind hierarchyKind : HierarchyKind.values()) {
198                 for (TestKind testKind : TestKind.values()) {
199                     for (ActionKind actionKind : ActionKind.values()) {
200                         File testDir = new File(SCRATCH_DIR, "test"+n);
201                         new EagerInterfaceCompletionTest(javacTool, testDir, versionKind,
202                                 hierarchyKind, testKind, actionKind).test();
203                         n++;
204                     }
205                 }
206             }
207         }
208         if (nerrors > 0) {
209             throw new AssertionError("Some errors have been detected");
210         }
211     }
212 
213     static class JavaSource extends SimpleJavaFileObject {
214 
215         String source;
216 
JavaSource(String filename, String source)217         public JavaSource(String filename, String source) {
218             super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
219             this.source = source;
220         }
221 
222         @Override
getCharContent(boolean ignoreEncodingErrors)223         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
224             return source;
225         }
226     }
227 
228     static int nerrors = 0;
229 }
230