Fri, 24 Apr 2020 03:58:51 +0100
Merge
1 /*
2 * Copyright (c) 2011, 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 */
24 /*
25 * @test
26 * @bug 7079713
27 * @summary javac hangs when compiling a class that references a cyclically inherited class
28 * @run main TestCircularClassfile
29 */
31 import java.io.*;
32 import java.net.URI;
33 import java.util.Arrays;
34 import javax.tools.JavaCompiler;
35 import javax.tools.JavaFileObject;
36 import javax.tools.SimpleJavaFileObject;
37 import javax.tools.StandardJavaFileManager;
38 import javax.tools.StandardLocation;
39 import javax.tools.ToolProvider;
41 import com.sun.source.util.JavacTask;
43 public class TestCircularClassfile {
45 enum SourceKind {
46 A_EXTENDS_B("class B {} class A extends B { void m() {} }"),
47 B_EXTENDS_A("class A { void m() {} } class B extends A {}");
49 String sourceStr;
51 private SourceKind(String sourceStr) {
52 this.sourceStr = sourceStr;
53 }
55 SimpleJavaFileObject getSource() {
56 return new SimpleJavaFileObject(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE) {
57 @Override
58 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
59 return sourceStr;
60 }
61 };
62 }
63 }
65 enum TestKind {
66 REPLACE_A("A.class"),
67 REPLACE_B("B.class");
69 String targetClass;
71 private TestKind(String targetClass) {
72 this.targetClass = targetClass;
73 }
74 }
76 enum ClientKind {
77 METHOD_CALL1("A a = null; a.m();"),
78 METHOD_CALL2("B b = null; b.m();"),
79 CONSTR_CALL1("new A();"),
80 CONSTR_CALL2("new B();"),
81 ASSIGN1("A a = null; B b = a;"),
82 ASSIGN2("B b = null; A a = b;");
84 String mainMethod;
86 private ClientKind(String mainMethod) {
87 this.mainMethod = mainMethod;
88 }
90 SimpleJavaFileObject getSource() {
91 return new SimpleJavaFileObject(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE) {
92 @Override
93 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
94 return "class Test { public static void main(String[] args) { #M } }"
95 .replace("#M", mainMethod);
96 }
97 };
98 }
99 }
101 public static void main(String... args) throws Exception {
102 JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
103 StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
104 int count = 0;
105 for (SourceKind sk1 : SourceKind.values()) {
106 for (SourceKind sk2 : SourceKind.values()) {
107 for (TestKind tk : TestKind.values()) {
108 for (ClientKind ck : ClientKind.values()) {
109 new TestCircularClassfile("sub_"+count++, sk1, sk2, tk, ck).check(comp, fm);
110 }
111 }
112 }
113 }
114 }
116 static String workDir = System.getProperty("user.dir");
118 String destPath;
119 SourceKind sk1;
120 SourceKind sk2;
121 TestKind tk;
122 ClientKind ck;
124 TestCircularClassfile(String destPath, SourceKind sk1, SourceKind sk2, TestKind tk, ClientKind ck) {
125 this.destPath = destPath;
126 this.sk1 = sk1;
127 this.sk2 = sk2;
128 this.tk = tk;
129 this.ck = ck;
130 }
132 void check(JavaCompiler comp, StandardJavaFileManager fm) throws Exception {
133 //step 1: compile first source code in the test subfolder
134 File destDir = new File(workDir, destPath); destDir.mkdir();
135 //output dir must be set explicitly as we are sharing the fm (see bug 7026941)
136 fm.setLocation(javax.tools.StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir));
137 JavacTask ct = (JavacTask)comp.getTask(null, fm, null,
138 null, null, Arrays.asList(sk1.getSource()));
139 ct.generate();
141 //step 2: compile second source code in a temp folder
142 File tmpDir = new File(destDir, "tmp"); tmpDir.mkdir();
143 //output dir must be set explicitly as we are sharing the fm (see bug 7026941)
144 fm.setLocation(javax.tools.StandardLocation.CLASS_OUTPUT, Arrays.asList(tmpDir));
145 ct = (JavacTask)comp.getTask(null, fm, null,
146 null, null, Arrays.asList(sk2.getSource()));
147 ct.generate();
149 //step 3: move a classfile from the temp folder to the test subfolder
150 File fileToMove = new File(tmpDir, tk.targetClass);
151 File target = new File(destDir, tk.targetClass);
152 target.delete();
153 boolean success = fileToMove.renameTo(target);
155 if (!success) {
156 throw new AssertionError("error when moving file " + tk.targetClass);
157 }
159 //step 4: compile the client class against the classes in the test subfolder
160 //input/output dir must be set explicitly as we are sharing the fm (see bug 7026941)
161 fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir));
162 fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(destDir));
163 ct = (JavacTask)comp.getTask(null, fm, null,
164 null, null, Arrays.asList(ck.getSource()));
166 ct.generate();
167 }
168 }