1 /* 2 * Copyright (c) 2010, 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 6863465 27 * @summary javac doesn't detect circular subclass dependencies via qualified names 28 * @run main TestCircularClassfile 29 */ 30 31 import java.io.*; 32 import java.net.URI; 33 import java.util.Arrays; 34 import javax.tools.Diagnostic; 35 import javax.tools.DiagnosticListener; 36 import javax.tools.JavaCompiler; 37 import javax.tools.JavaFileObject; 38 import javax.tools.SimpleJavaFileObject; 39 import javax.tools.ToolProvider; 40 41 import com.sun.source.util.JavacTask; 42 import java.util.EnumSet; 43 44 public class TestCircularClassfile { 45 46 enum ClassName { 47 A("A"), 48 B("B"), 49 C("C"), 50 OBJECT("Object"); 51 52 String name; 53 ClassName(String name)54 ClassName(String name) { 55 this.name = name; 56 } 57 } 58 59 static class JavaSource extends SimpleJavaFileObject { 60 61 final static String sourceStub = "class #C extends #S {}"; 62 63 String source; 64 JavaSource(ClassName clazz, ClassName sup)65 public JavaSource(ClassName clazz, ClassName sup) { 66 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 67 source = sourceStub.replace("#C", clazz.name).replace("#S", sup.name); 68 } 69 70 @Override getCharContent(boolean ignoreEncodingErrors)71 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 72 return source; 73 } 74 } 75 main(String... args)76 public static void main(String... args) throws Exception { 77 int count = 0; 78 for (ClassName clazz : EnumSet.of(ClassName.A, ClassName.B, ClassName.C)) { 79 for (ClassName sup : EnumSet.of(ClassName.A, ClassName.B, ClassName.C)) { 80 if (sup.ordinal() < clazz.ordinal()) continue; 81 check("sub_"+count++, clazz, sup); 82 } 83 } 84 } 85 86 static JavaSource[] initialSources = new JavaSource[] { 87 new JavaSource(ClassName.A, ClassName.OBJECT), 88 new JavaSource(ClassName.B, ClassName.A), 89 new JavaSource(ClassName.C, ClassName.B) 90 }; 91 92 static String workDir = System.getProperty("user.dir"); 93 check(String destPath, ClassName clazz, ClassName sup)94 static void check(String destPath, ClassName clazz, ClassName sup) throws Exception { 95 File destDir = new File(workDir, destPath); destDir.mkdir(); 96 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 97 JavacTask ct = (JavacTask)tool.getTask(null, null, null, 98 Arrays.asList("-d", destPath), null, Arrays.asList(initialSources)); 99 ct.generate(); 100 File fileToRemove = new File(destPath, clazz.name + ".class"); 101 fileToRemove.delete(); 102 JavaSource newSource = new JavaSource(clazz, sup); 103 DiagnosticChecker checker = new DiagnosticChecker(); 104 ct = (JavacTask)tool.getTask(null, null, checker, 105 Arrays.asList("-cp", destPath), null, Arrays.asList(newSource)); 106 ct.analyze(); 107 if (!checker.errorFound) { 108 throw new AssertionError(newSource.source); 109 } 110 } 111 112 static 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 diagnostic.getCode().equals("compiler.err.cyclic.inheritance")) { 119 errorFound = true; 120 } 121 } 122 } 123 } 124