mcimadamore@1072: /* mcimadamore@1072: * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. mcimadamore@1072: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. mcimadamore@1072: * mcimadamore@1072: * This code is free software; you can redistribute it and/or modify it mcimadamore@1072: * under the terms of the GNU General Public License version 2 only, as mcimadamore@1072: * published by the Free Software Foundation. mcimadamore@1072: * mcimadamore@1072: * This code is distributed in the hope that it will be useful, but WITHOUT mcimadamore@1072: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or mcimadamore@1072: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License mcimadamore@1072: * version 2 for more details (a copy is included in the LICENSE file that mcimadamore@1072: * accompanied this code). mcimadamore@1072: * mcimadamore@1072: * You should have received a copy of the GNU General Public License version mcimadamore@1072: * 2 along with this work; if not, write to the Free Software Foundation, mcimadamore@1072: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. mcimadamore@1072: * mcimadamore@1072: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA mcimadamore@1072: * or visit www.oracle.com if you need additional information or have any mcimadamore@1072: * questions. mcimadamore@1072: */ mcimadamore@1072: mcimadamore@1072: /* mcimadamore@1072: * @test mcimadamore@1072: * @bug 7079713 mcimadamore@1072: * @summary javac hangs when compiling a class that references a cyclically inherited class mcimadamore@1072: * @run main TestCircularClassfile mcimadamore@1072: */ mcimadamore@1072: mcimadamore@1072: import java.io.*; mcimadamore@1072: import java.net.URI; mcimadamore@1072: import java.util.Arrays; mcimadamore@1072: import javax.tools.JavaCompiler; mcimadamore@1072: import javax.tools.JavaFileObject; mcimadamore@1072: import javax.tools.SimpleJavaFileObject; mcimadamore@1072: import javax.tools.StandardJavaFileManager; mcimadamore@1072: import javax.tools.StandardLocation; mcimadamore@1072: import javax.tools.ToolProvider; mcimadamore@1072: mcimadamore@1072: import com.sun.source.util.JavacTask; mcimadamore@1072: mcimadamore@1072: public class TestCircularClassfile { mcimadamore@1072: mcimadamore@1072: enum SourceKind { mcimadamore@1072: A_EXTENDS_B("class B {} class A extends B { void m() {} }"), mcimadamore@1072: B_EXTENDS_A("class A { void m() {} } class B extends A {}"); mcimadamore@1072: mcimadamore@1072: String sourceStr; mcimadamore@1072: mcimadamore@1072: private SourceKind(String sourceStr) { mcimadamore@1072: this.sourceStr = sourceStr; mcimadamore@1072: } mcimadamore@1072: mcimadamore@1072: SimpleJavaFileObject getSource() { mcimadamore@1072: return new SimpleJavaFileObject(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE) { mcimadamore@1072: @Override mcimadamore@1072: public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { mcimadamore@1072: return sourceStr; mcimadamore@1072: } mcimadamore@1072: }; mcimadamore@1072: } mcimadamore@1072: } mcimadamore@1072: mcimadamore@1072: enum TestKind { mcimadamore@1072: REPLACE_A("A.class"), mcimadamore@1072: REPLACE_B("B.class"); mcimadamore@1072: mcimadamore@1072: String targetClass; mcimadamore@1072: mcimadamore@1072: private TestKind(String targetClass) { mcimadamore@1072: this.targetClass = targetClass; mcimadamore@1072: } mcimadamore@1072: } mcimadamore@1072: mcimadamore@1072: enum ClientKind { mcimadamore@1072: METHOD_CALL1("A a = null; a.m();"), mcimadamore@1072: METHOD_CALL2("B b = null; b.m();"), mcimadamore@1072: CONSTR_CALL1("new A();"), mcimadamore@1072: CONSTR_CALL2("new B();"), mcimadamore@1072: ASSIGN1("A a = null; B b = a;"), mcimadamore@1072: ASSIGN2("B b = null; A a = b;"); mcimadamore@1072: mcimadamore@1072: String mainMethod; mcimadamore@1072: mcimadamore@1072: private ClientKind(String mainMethod) { mcimadamore@1072: this.mainMethod = mainMethod; mcimadamore@1072: } mcimadamore@1072: mcimadamore@1072: SimpleJavaFileObject getSource() { mcimadamore@1072: return new SimpleJavaFileObject(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE) { mcimadamore@1072: @Override mcimadamore@1072: public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { mcimadamore@1072: return "class Test { public static void main(String[] args) { #M } }" mcimadamore@1072: .replace("#M", mainMethod); mcimadamore@1072: } mcimadamore@1072: }; mcimadamore@1072: } mcimadamore@1072: } mcimadamore@1072: mcimadamore@1072: public static void main(String... args) throws Exception { mcimadamore@1072: JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); mcimadamore@1072: StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); mcimadamore@1072: int count = 0; mcimadamore@1072: for (SourceKind sk1 : SourceKind.values()) { mcimadamore@1072: for (SourceKind sk2 : SourceKind.values()) { mcimadamore@1072: for (TestKind tk : TestKind.values()) { mcimadamore@1072: for (ClientKind ck : ClientKind.values()) { mcimadamore@1072: new TestCircularClassfile("sub_"+count++, sk1, sk2, tk, ck).check(comp, fm); mcimadamore@1072: } mcimadamore@1072: } mcimadamore@1072: } mcimadamore@1072: } mcimadamore@1072: } mcimadamore@1072: mcimadamore@1072: static String workDir = System.getProperty("user.dir"); mcimadamore@1072: mcimadamore@1072: String destPath; mcimadamore@1072: SourceKind sk1; mcimadamore@1072: SourceKind sk2; mcimadamore@1072: TestKind tk; mcimadamore@1072: ClientKind ck; mcimadamore@1072: mcimadamore@1072: TestCircularClassfile(String destPath, SourceKind sk1, SourceKind sk2, TestKind tk, ClientKind ck) { mcimadamore@1072: this.destPath = destPath; mcimadamore@1072: this.sk1 = sk1; mcimadamore@1072: this.sk2 = sk2; mcimadamore@1072: this.tk = tk; mcimadamore@1072: this.ck = ck; mcimadamore@1072: } mcimadamore@1072: mcimadamore@1072: void check(JavaCompiler comp, StandardJavaFileManager fm) throws Exception { mcimadamore@1072: //step 1: compile first source code in the test subfolder mcimadamore@1072: File destDir = new File(workDir, destPath); destDir.mkdir(); mcimadamore@1072: //output dir must be set explicitly as we are sharing the fm (see bug 7026941) mcimadamore@1072: fm.setLocation(javax.tools.StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir)); mcimadamore@1072: JavacTask ct = (JavacTask)comp.getTask(null, fm, null, mcimadamore@1072: null, null, Arrays.asList(sk1.getSource())); mcimadamore@1072: ct.generate(); mcimadamore@1072: mcimadamore@1072: //step 2: compile second source code in a temp folder mcimadamore@1072: File tmpDir = new File(destDir, "tmp"); tmpDir.mkdir(); mcimadamore@1072: //output dir must be set explicitly as we are sharing the fm (see bug 7026941) mcimadamore@1072: fm.setLocation(javax.tools.StandardLocation.CLASS_OUTPUT, Arrays.asList(tmpDir)); mcimadamore@1072: ct = (JavacTask)comp.getTask(null, fm, null, mcimadamore@1072: null, null, Arrays.asList(sk2.getSource())); mcimadamore@1072: ct.generate(); mcimadamore@1072: mcimadamore@1072: //step 3: move a classfile from the temp folder to the test subfolder mcimadamore@1072: File fileToMove = new File(tmpDir, tk.targetClass); mcimadamore@1072: File target = new File(destDir, tk.targetClass); jjh@1075: target.delete(); mcimadamore@1072: boolean success = fileToMove.renameTo(target); mcimadamore@1072: mcimadamore@1072: if (!success) { mcimadamore@1072: throw new AssertionError("error when moving file " + tk.targetClass); mcimadamore@1072: } mcimadamore@1072: mcimadamore@1072: //step 4: compile the client class against the classes in the test subfolder mcimadamore@1072: //input/output dir must be set explicitly as we are sharing the fm (see bug 7026941) mcimadamore@1072: fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir)); mcimadamore@1072: fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(destDir)); mcimadamore@1072: ct = (JavacTask)comp.getTask(null, fm, null, mcimadamore@1072: null, null, Arrays.asList(ck.getSource())); mcimadamore@1072: mcimadamore@1072: ct.generate(); mcimadamore@1072: } mcimadamore@1072: }