test/tools/javac/7003595/T7003595.java

Mon, 26 Oct 2015 13:23:30 -0700

author
asaha
date
Mon, 26 Oct 2015 13:23:30 -0700
changeset 2999
683b3e7e05a7
parent 0
959103a6100f
permissions
-rw-r--r--

Added tag jdk8u76-b00 for changeset 10ffafaf5340

     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 7003595
    27  * @summary IncompatibleClassChangeError with unreferenced local class with subclass
    28  */
    30 import com.sun.source.util.JavacTask;
    31 import com.sun.tools.classfile.Attribute;
    32 import com.sun.tools.classfile.ClassFile;
    33 import com.sun.tools.classfile.InnerClasses_attribute;
    34 import com.sun.tools.classfile.ConstantPool.*;
    35 import com.sun.tools.javac.api.JavacTool;
    37 import java.io.File;
    38 import java.net.URI;
    39 import java.util.Arrays;
    40 import java.util.ArrayList;
    41 import javax.tools.JavaCompiler;
    42 import javax.tools.JavaFileObject;
    43 import javax.tools.SimpleJavaFileObject;
    44 import javax.tools.StandardJavaFileManager;
    45 import javax.tools.ToolProvider;
    48 public class T7003595 {
    50     /** global decls ***/
    52     // Create a single file manager and reuse it for each compile to save time.
    53     static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
    55     //statistics
    56     static int checkCount = 0;
    58     enum ClassKind {
    59         NESTED("static class #N { #B }", "$", true),
    60         INNER("class #N { #B }", "$", false),
    61         LOCAL_REF("void test() { class #N { #B }; new #N(); }", "$1", false),
    62         LOCAL_NOREF("void test() { class #N { #B }; }", "$1", false),
    63         ANON("void test() { new Object() { #B }; }", "$1", false),
    64         NONE("", "", false);
    66         String memberInnerStr;
    67         String sep;
    68         boolean staticAllowed;
    70         private ClassKind(String memberInnerStr, String sep, boolean staticAllowed) {
    71             this.memberInnerStr = memberInnerStr;
    72             this.sep = sep;
    73             this.staticAllowed = staticAllowed;
    74         }
    76         String getSource(String className, String outerName, String nested) {
    77             return memberInnerStr.replaceAll("#O", outerName).
    78                     replaceAll("#N", className).replaceAll("#B", nested);
    79         }
    81         static String getClassfileName(String[] names, ClassKind[] outerKinds, int pos) {
    82             System.out.println(" pos = " + pos + " kind = " + outerKinds[pos] + " sep = " + outerKinds[pos].sep);
    83             String name = outerKinds[pos] != ANON ?
    84                     names[pos] : "";
    85             if (pos == 0) {
    86                 return "Test" + outerKinds[pos].sep + name;
    87             } else {
    88                 String outerStr = getClassfileName(names, outerKinds, pos - 1);
    89                 return outerStr + outerKinds[pos].sep + name;
    90             }
    91         }
    93         boolean isAllowed(ClassKind nestedKind) {
    94             return nestedKind != NESTED ||
    95                     staticAllowed;
    96         }
    97     }
    99     enum LocalInnerClass {
   100         LOCAL_REF("class L {}; new L();", "Test$1L"),
   101         LOCAL_NOREF("class L {};", "Test$1L"),
   102         ANON("new Object() {};", "Test$1"),
   103         NONE("", "");
   105         String localInnerStr;
   106         String canonicalInnerStr;
   108         private LocalInnerClass(String localInnerStr, String canonicalInnerStr) {
   109             this.localInnerStr = localInnerStr;
   110             this.canonicalInnerStr = canonicalInnerStr;
   111         }
   112     }
   114     public static void main(String... args) throws Exception {
   115         for (ClassKind ck1 : ClassKind.values()) {
   116             String cname1 = "C1";
   117             for (ClassKind ck2 : ClassKind.values()) {
   118                 if (!ck1.isAllowed(ck2)) continue;
   119                 String cname2 = "C2";
   120                 for (ClassKind ck3 : ClassKind.values()) {
   121                     if (!ck2.isAllowed(ck3)) continue;
   122                     String cname3 = "C3";
   123                     new T7003595(new ClassKind[] {ck1, ck2, ck3}, new String[] { cname1, cname2, cname3 }).compileAndCheck();
   124                 }
   125             }
   126         }
   128         System.out.println("Total checks made: " + checkCount);
   129     }
   131     /** instance decls **/
   133     ClassKind[] cks;
   134     String[] cnames;
   136     T7003595(ClassKind[] cks, String[] cnames) {
   137         this.cks = cks;
   138         this.cnames = cnames;
   139     }
   141     void compileAndCheck() throws Exception {
   142         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
   143         JavaSource source = new JavaSource();
   144         JavacTask ct = (JavacTask)tool.getTask(null, fm, null,
   145                 null, null, Arrays.asList(source));
   146         ct.call();
   147         verifyBytecode(source);
   148     }
   150     void verifyBytecode(JavaSource source) {
   151         for (int i = 0; i < 3 ; i ++) {
   152             if (cks[i] == ClassKind.NONE) break;
   153             checkCount++;
   154             String filename = cks[i].getClassfileName(cnames, cks, i);
   155             File compiledTest = new File(filename + ".class");
   156             try {
   157                 ClassFile cf = ClassFile.read(compiledTest);
   158                 if (cf == null) {
   159                     throw new Error("Classfile not found: " + filename);
   160                 }
   162                 InnerClasses_attribute innerClasses = (InnerClasses_attribute)cf.getAttribute(Attribute.InnerClasses);
   164                 ArrayList<String> foundInnerSig = new ArrayList<>();
   165                 if (innerClasses != null) {
   166                     for (InnerClasses_attribute.Info info : innerClasses.classes) {
   167                         String foundSig = info.getInnerClassInfo(cf.constant_pool).getName();
   168                         foundInnerSig.add(foundSig);
   169                     }
   170                 }
   172                 ArrayList<String> expectedInnerSig = new ArrayList<>();
   173                 //add inner class (if any)
   174                 if (i < 2 && cks[i + 1] != ClassKind.NONE) {
   175                     expectedInnerSig.add(cks[i + 1].getClassfileName(cnames, cks, i + 1));
   176                 }
   177                 //add inner classes
   178                 for (int j = 0 ; j != i + 1 && j < 3; j++) {
   179                     expectedInnerSig.add(cks[j].getClassfileName(cnames, cks, j));
   180                 }
   182                 if (expectedInnerSig.size() != foundInnerSig.size()) {
   183                     throw new Error("InnerClasses attribute for " + cnames[i] + " has wrong size\n" +
   184                                     "expected " + expectedInnerSig.size() + "\n" +
   185                                     "found " + innerClasses.number_of_classes + "\n" +
   186                                     source);
   187                 }
   189                 for (String foundSig : foundInnerSig) {
   190                     if (!expectedInnerSig.contains(foundSig)) {
   191                         throw new Error("InnerClasses attribute for " + cnames[i] + " has unexpected signature: " +
   192                                 foundSig + "\n" + source + "\n" + expectedInnerSig);
   193                     }
   194                 }
   196                 for (String expectedSig : expectedInnerSig) {
   197                     if (!foundInnerSig.contains(expectedSig)) {
   198                         throw new Error("InnerClasses attribute for " + cnames[i] + " does not contain expected signature: " +
   199                                     expectedSig + "\n" + source);
   200                     }
   201                 }
   202             } catch (Exception e) {
   203                 e.printStackTrace();
   204                 throw new Error("error reading " + compiledTest +": " + e);
   205             }
   206         }
   207     }
   209     class JavaSource extends SimpleJavaFileObject {
   211         static final String source_template = "class Test { #C }";
   213         String source;
   215         public JavaSource() {
   216             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   217             String c3 = cks[2].getSource(cnames[2], cnames[1], "");
   218             String c2 = cks[1].getSource(cnames[1], cnames[0], c3);
   219             String c1 = cks[0].getSource(cnames[0], "Test", c2);
   220             source = source_template.replace("#C", c1);
   221         }
   223         @Override
   224         public String toString() {
   225             return source;
   226         }
   228         @Override
   229         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   230             return source;
   231         }
   232     }
   233 }

mercurial