7199823: javac generates inner class that can't be verified
authorvromero
Sun, 03 Feb 2013 02:31:30 +0000
changeset 15565 040a54631aad
parent 15564 6d8db91563a7
child 15566 2c686ad681f5
7199823: javac generates inner class that can't be verified Reviewed-by: jjg, mcimadamore
langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
langtools/test/tools/javac/7199823/InnerClassCannotBeVerified.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java	Sat Feb 02 21:04:56 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java	Sun Feb 03 02:31:30 2013 +0000
@@ -570,10 +570,19 @@
      *  @param flags    The class symbol's flags
      *  @param owner    The class symbol's owner
      */
-    ClassSymbol makeEmptyClass(long flags, ClassSymbol owner) {
+    JCClassDecl makeEmptyClass(long flags, ClassSymbol owner) {
+        return makeEmptyClass(flags, owner, null, true);
+    }
+
+    JCClassDecl makeEmptyClass(long flags, ClassSymbol owner, Name flatname,
+            boolean addToDefs) {
         // Create class symbol.
         ClassSymbol c = reader.defineClass(names.empty, owner);
-        c.flatname = chk.localClassName(c);
+        if (flatname != null) {
+            c.flatname = flatname;
+        } else {
+            c.flatname = chk.localClassName(c);
+        }
         c.sourcefile = owner.sourcefile;
         c.completer = null;
         c.members_field = new Scope(c);
@@ -597,9 +606,8 @@
         cdef.type = c.type;
 
         // Append class definition tree to owner's definitions.
-        odef.defs = odef.defs.prepend(cdef);
-
-        return c;
+        if (addToDefs) odef.defs = odef.defs.prepend(cdef);
+        return cdef;
     }
 
 /**************************************************************************
@@ -706,7 +714,7 @@
      * and synthethise a class (with makeEmptyClass) if one is not available.
      * However, there is a small possibility that an existing class will not
      * be generated as expected if it is inside a conditional with a constant
-     * expression. If that is found to be the case, create an empty class here.
+     * expression. If that is found to be the case, create an empty class tree here.
      */
     private void checkAccessConstructorTags() {
         for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
@@ -714,14 +722,10 @@
             if (isTranslatedClassAvailable(c))
                 continue;
             // Create class definition tree.
-            JCClassDecl cdef = make.ClassDef(
-                make.Modifiers(STATIC | SYNTHETIC), names.empty,
-                List.<JCTypeParameter>nil(),
-                null, List.<JCExpression>nil(), List.<JCTree>nil());
-            cdef.sym = c;
-            cdef.type = c.type;
-            // add it to the list of classes to be generated
-            translated.append(cdef);
+            JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
+                    c.outermostClass(), c.flatname, false);
+            swapAccessConstructorTag(c, cdec.sym);
+            translated.append(cdec);
         }
     }
     // where
@@ -735,6 +739,19 @@
         return false;
     }
 
+    void swapAccessConstructorTag(ClassSymbol oldCTag, ClassSymbol newCTag) {
+        for (MethodSymbol methodSymbol : accessConstrs.values()) {
+            Assert.check(methodSymbol.type.hasTag(METHOD));
+            MethodType oldMethodType =
+                    (MethodType)methodSymbol.type;
+            if (oldMethodType.argtypes.head.tsym == oldCTag)
+                methodSymbol.type =
+                    types.createMethodTypeWithParameters(oldMethodType,
+                        oldMethodType.getParameterTypes().tail
+                            .prepend(newCTag.erasure(types)));
+        }
+    }
+
 /**************************************************************************
  * Access methods
  *************************************************************************/
@@ -1211,7 +1228,7 @@
                                          "1");
         ClassSymbol ctag = chk.compiled.get(flatname);
         if (ctag == null)
-            ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass);
+            ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
         // keep a record of all tags, to verify that all are generated as required
         accessConstrTags = accessConstrTags.prepend(ctag);
         return ctag;
@@ -1778,7 +1795,7 @@
             if (e.sym.kind == TYP &&
                 e.sym.name == names.empty &&
                 (e.sym.flags() & INTERFACE) == 0) return (ClassSymbol) e.sym;
-        return makeEmptyClass(STATIC | SYNTHETIC, clazz);
+        return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
     }
 
     /** Return symbol for "class$" method. If there is no method definition
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/7199823/InnerClassCannotBeVerified.java	Sun Feb 03 02:31:30 2013 +0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7199823
+ * @summary javac generates inner class that can't be verified
+ * @run main InnerClassCannotBeVerified
+ */
+
+import java.util.Arrays;
+import javax.tools.JavaFileObject;
+import java.net.URI;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+import javax.tools.JavaCompiler;
+import com.sun.source.util.JavacTask;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import java.io.File;
+import java.io.IOException;
+
+public class InnerClassCannotBeVerified {
+
+    private static final String errorMessage =
+            "Compile error while compiling the following source:\n";
+
+    public static void main(String... args) throws Exception {
+        new InnerClassCannotBeVerified().run();
+    }
+
+    void run() throws Exception {
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        JavaSource source = new JavaSource();
+        JavacTask ct = (JavacTask)comp.getTask(null, null, null,
+                null, null, Arrays.asList(source));
+        try {
+            if (!ct.call()) {
+                throw new AssertionError(errorMessage +
+                        source.getCharContent(true));
+            }
+        } catch (Throwable ex) {
+            throw new AssertionError(errorMessage +
+                    source.getCharContent(true));
+        }
+        check();
+    }
+
+    private void check() throws IOException, ConstantPoolException {
+        File file = new File("Test$1.class");
+        ClassFile classFile = ClassFile.read(file);
+        boolean inheritsFromObject =
+                classFile.getSuperclassName().equals("java/lang/Object");
+        boolean implementsNoInterface = classFile.interfaces.length == 0;
+        boolean noMethods = classFile.methods.length == 0;
+        if (!(inheritsFromObject &&
+              implementsNoInterface &&
+              noMethods)) {
+            throw new AssertionError("The inner classes reused as " +
+                    "access constructor tag for this code must be empty");
+        }
+    }
+
+    class JavaSource extends SimpleJavaFileObject {
+
+        String internalSource =
+                              "public class Test {\n" +
+                              "    private static class Foo {}\n" +
+                              "    public static void main(String[] args){ \n" +
+                              "        new Foo();\n" +
+                              "        if(false) {\n" +
+                              "            new Runnable() {\n" +
+                              "                @Override\n" +
+                              "                public void run() {\n" +
+                              "                    System.out.println();\n" +
+                              "                }\n" +
+                              "            }.run();\n" +
+                              "        }\n" +
+                              "   }\n" +
+                              "}";
+        public JavaSource() {
+            super(URI.create("Test.java"), JavaFileObject.Kind.SOURCE);
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return internalSource;
+        }
+    }
+}