Path: blob/master/test/langtools/tools/javac/7003595/T7003595.java
41152 views
/*1* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 700359526* @summary IncompatibleClassChangeError with unreferenced local class with subclass27* @modules jdk.jdeps/com.sun.tools.classfile28* jdk.compiler/com.sun.tools.javac.api29* jdk.compiler/com.sun.tools.javac.file30*/3132import com.sun.source.util.JavacTask;33import com.sun.tools.classfile.Attribute;34import com.sun.tools.classfile.ClassFile;35import com.sun.tools.classfile.InnerClasses_attribute;36import com.sun.tools.classfile.ConstantPool.*;37import com.sun.tools.javac.api.JavacTool;3839import java.io.File;40import java.net.URI;41import java.util.Arrays;42import java.util.ArrayList;43import javax.tools.JavaCompiler;44import javax.tools.JavaFileObject;45import javax.tools.SimpleJavaFileObject;46import javax.tools.StandardJavaFileManager;47import javax.tools.ToolProvider;484950public class T7003595 {5152/** global decls ***/5354//statistics55static int checkCount = 0;5657enum ClassKind {58NESTED("static class #N { #B }", "$", true),59INNER("class #N { #B }", "$", false),60LOCAL_REF("void test() { class #N { #B }; new #N(); }", "$1", false),61LOCAL_NOREF("void test() { class #N { #B }; }", "$1", false),62ANON("void test() { new Object() { #B }; }", "$1", false),63NONE("", "", false);6465String memberInnerStr;66String sep;67boolean staticAllowed;6869private ClassKind(String memberInnerStr, String sep, boolean staticAllowed) {70this.memberInnerStr = memberInnerStr;71this.sep = sep;72this.staticAllowed = staticAllowed;73}7475String getSource(String className, String outerName, String nested) {76return memberInnerStr.replaceAll("#O", outerName).77replaceAll("#N", className).replaceAll("#B", nested);78}7980static String getClassfileName(String[] names, ClassKind[] outerKinds, int pos) {81System.out.println(" pos = " + pos + " kind = " + outerKinds[pos] + " sep = " + outerKinds[pos].sep);82String name = outerKinds[pos] != ANON ?83names[pos] : "";84if (pos == 0) {85return "Test" + outerKinds[pos].sep + name;86} else {87String outerStr = getClassfileName(names, outerKinds, pos - 1);88return outerStr + outerKinds[pos].sep + name;89}90}9192boolean isAllowed(ClassKind nestedKind) {93return nestedKind != NESTED ||94staticAllowed;95}96}9798enum LocalInnerClass {99LOCAL_REF("class L {}; new L();", "Test$1L"),100LOCAL_NOREF("class L {};", "Test$1L"),101ANON("new Object() {};", "Test$1"),102NONE("", "");103104String localInnerStr;105String canonicalInnerStr;106107private LocalInnerClass(String localInnerStr, String canonicalInnerStr) {108this.localInnerStr = localInnerStr;109this.canonicalInnerStr = canonicalInnerStr;110}111}112113public static void main(String... args) throws Exception {114// Create a single file manager and reuse it for each compile to save time.115try (StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null)) {116for (ClassKind ck1 : ClassKind.values()) {117String cname1 = "C1";118for (ClassKind ck2 : ClassKind.values()) {119if (!ck1.isAllowed(ck2)) continue;120String cname2 = "C2";121for (ClassKind ck3 : ClassKind.values()) {122if (!ck2.isAllowed(ck3)) continue;123String cname3 = "C3";124new T7003595(fm, new ClassKind[] {ck1, ck2, ck3}, new String[] { cname1, cname2, cname3 }).compileAndCheck();125}126}127}128}129130System.out.println("Total checks made: " + checkCount);131}132133/** instance decls **/134135ClassKind[] cks;136String[] cnames;137StandardJavaFileManager fm;138139T7003595(StandardJavaFileManager fm, ClassKind[] cks, String[] cnames) {140this.fm = fm;141this.cks = cks;142this.cnames = cnames;143}144145void compileAndCheck() throws Exception {146final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();147JavaSource source = new JavaSource();148JavacTask ct = (JavacTask)tool.getTask(null, fm, null,149null, null, Arrays.asList(source));150ct.call();151verifyBytecode(source);152}153154void verifyBytecode(JavaSource source) {155for (int i = 0; i < 3 ; i ++) {156if (cks[i] == ClassKind.NONE) break;157checkCount++;158String filename = cks[i].getClassfileName(cnames, cks, i);159File compiledTest = new File(filename + ".class");160try {161ClassFile cf = ClassFile.read(compiledTest);162if (cf == null) {163throw new Error("Classfile not found: " + filename);164}165166InnerClasses_attribute innerClasses = (InnerClasses_attribute)cf.getAttribute(Attribute.InnerClasses);167168ArrayList<String> foundInnerSig = new ArrayList<>();169if (innerClasses != null) {170for (InnerClasses_attribute.Info info : innerClasses.classes) {171String foundSig = info.getInnerClassInfo(cf.constant_pool).getName();172foundInnerSig.add(foundSig);173}174}175176ArrayList<String> expectedInnerSig = new ArrayList<>();177//add inner class (if any)178if (i < 2 && cks[i + 1] != ClassKind.NONE) {179expectedInnerSig.add(cks[i + 1].getClassfileName(cnames, cks, i + 1));180}181//add inner classes182for (int j = 0 ; j != i + 1 && j < 3; j++) {183expectedInnerSig.add(cks[j].getClassfileName(cnames, cks, j));184}185186if (expectedInnerSig.size() != foundInnerSig.size()) {187throw new Error("InnerClasses attribute for " + cnames[i] + " has wrong size\n" +188"expected " + expectedInnerSig.size() + "\n" +189"found " + innerClasses.number_of_classes + "\n" +190source);191}192193for (String foundSig : foundInnerSig) {194if (!expectedInnerSig.contains(foundSig)) {195throw new Error("InnerClasses attribute for " + cnames[i] + " has unexpected signature: " +196foundSig + "\n" + source + "\n" + expectedInnerSig);197}198}199200for (String expectedSig : expectedInnerSig) {201if (!foundInnerSig.contains(expectedSig)) {202throw new Error("InnerClasses attribute for " + cnames[i] + " does not contain expected signature: " +203expectedSig + "\n" + source);204}205}206} catch (Exception e) {207e.printStackTrace();208throw new Error("error reading " + compiledTest +": " + e);209}210}211}212213class JavaSource extends SimpleJavaFileObject {214215static final String source_template = "class Test { #C }";216217String source;218219public JavaSource() {220super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);221String c3 = cks[2].getSource(cnames[2], cnames[1], "");222String c2 = cks[1].getSource(cnames[1], cnames[0], c3);223String c1 = cks[0].getSource(cnames[0], "Test", c2);224source = source_template.replace("#C", c1);225}226227@Override228public String toString() {229return source;230}231232@Override233public CharSequence getCharContent(boolean ignoreEncodingErrors) {234return source;235}236}237}238239240