6695379: Copy method annotations and parameter annotations to synthetic bridge methods
authorvromero
Sat, 01 Jun 2013 22:09:18 +0100
changeset 18000 5d29ce00a7a2
parent 17999 42ae6fe53718
child 18001 e6193c14cc7e
child 18002 bf9d876d0c6a
6695379: Copy method annotations and parameter annotations to synthetic bridge methods Reviewed-by: mcimadamore
langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
langtools/test/tools/javac/6889255/T6889255.java
langtools/test/tools/javac/MethodParameters/ClassFileVisitor.java
langtools/test/tools/javac/MethodParameters/ReflectionVisitor.java
langtools/test/tools/javac/MethodParameters/Tester.java
langtools/test/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Sat Jun 01 21:57:56 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Sat Jun 01 22:09:18 2013 +0100
@@ -258,6 +258,14 @@
                                                meth.name,
                                                bridgeType,
                                                origin);
+        /* once JDK-6996415 is solved it should be checked if this approach can
+         * be applied to method addOverrideBridgesIfNeeded
+         */
+        bridge.params = createBridgeParams(impl, bridge, bridgeType);
+        if (impl.annotations != null) {
+            bridge.annotations.setAttributes(impl.annotations);
+        }
+
         if (!hypothetical) {
             JCMethodDecl md = make.MethodDef(bridge, null);
 
@@ -292,6 +300,28 @@
         overridden.put(bridge, meth);
     }
 
+    private List<VarSymbol> createBridgeParams(MethodSymbol impl, MethodSymbol bridge,
+            Type bridgeType) {
+        List<VarSymbol> bridgeParams = null;
+        if (impl.params != null) {
+            bridgeParams = List.nil();
+            List<VarSymbol> implParams = impl.params;
+            Type.MethodType mType = (Type.MethodType)bridgeType;
+            List<Type> argTypes = mType.argtypes;
+            while (implParams.nonEmpty() && argTypes.nonEmpty()) {
+                VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC,
+                        implParams.head.name, argTypes.head, bridge);
+                if (implParams.head.annotations != null) {
+                    param.annotations.setAttributes(implParams.head.annotations);
+                }
+                bridgeParams = bridgeParams.append(param);
+                implParams = implParams.tail;
+                argTypes = argTypes.tail;
+            }
+        }
+        return bridgeParams;
+    }
+
     /** Add bridge if given symbol is a non-private, non-static member
      *  of the given class, which is either defined in the class or non-final
      *  inherited, and one of the two following conditions holds:
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Sat Jun 01 21:57:56 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Sat Jun 01 22:09:18 2013 +0100
@@ -31,7 +31,6 @@
 import java.util.Set;
 import java.util.HashSet;
 
-import javax.lang.model.type.TypeKind;
 import javax.tools.JavaFileManager;
 import javax.tools.FileObject;
 import javax.tools.JavaFileObject;
@@ -39,9 +38,6 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Attribute.TypeCompound;
-import static com.sun.tools.javac.code.BoundKind.EXTENDS;
-import static com.sun.tools.javac.code.BoundKind.SUPER;
-import static com.sun.tools.javac.code.BoundKind.UNBOUND;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.Types.UniqueType;
@@ -674,13 +670,15 @@
     int writeParameterAttrs(MethodSymbol m) {
         boolean hasVisible = false;
         boolean hasInvisible = false;
-        if (m.params != null) for (VarSymbol s : m.params) {
-            for (Attribute.Compound a : s.getRawAttributes()) {
-                switch (types.getRetention(a)) {
-                case SOURCE: break;
-                case CLASS: hasInvisible = true; break;
-                case RUNTIME: hasVisible = true; break;
-                default: ;// /* fail soft */ throw new AssertionError(vis);
+        if (m.params != null) {
+            for (VarSymbol s : m.params) {
+                for (Attribute.Compound a : s.getRawAttributes()) {
+                    switch (types.getRetention(a)) {
+                    case SOURCE: break;
+                    case CLASS: hasInvisible = true; break;
+                    case RUNTIME: hasVisible = true; break;
+                    default: ;// /* fail soft */ throw new AssertionError(vis);
+                    }
                 }
             }
         }
--- a/langtools/test/tools/javac/6889255/T6889255.java	Sat Jun 01 21:57:56 2013 +0100
+++ b/langtools/test/tools/javac/6889255/T6889255.java	Sat Jun 01 22:09:18 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -429,9 +429,9 @@
         // -- no Code attribute for the LocalVariableTable attribute
         if ((v.owner.flags() & Flags.ABSTRACT) != 0)
             return "arg" + (i - 1);
-        // bridge methods use xN
+        // bridge methods use argN. No LVT for them anymore
         if ((v.owner.flags() & Flags.BRIDGE) != 0)
-            return "x" + (i - 1);
+            return "arg" + (i - 1);
 
         // The rest of this method assumes the local conventions in the test program
         Type t = v.type;
--- a/langtools/test/tools/javac/MethodParameters/ClassFileVisitor.java	Sat Jun 01 21:57:56 2013 +0100
+++ b/langtools/test/tools/javac/MethodParameters/ClassFileVisitor.java	Sat Jun 01 22:09:18 2013 +0100
@@ -21,10 +21,8 @@
  * questions.
  */
 
+import java.io.*;
 import com.sun.tools.classfile.*;
-import java.io.*;
-import javax.lang.model.element.*;
-import java.util.*;
 
 /**
  * The {@code ClassFileVisitor} reads a class file using the
@@ -150,6 +148,7 @@
         public int mNumParams;
         public boolean mSynthetic;
         public boolean mIsConstructor;
+        public boolean mIsBridge;
         public String prefix;
 
         void visitMethod(Method method, StringBuilder sb) throws Exception {
@@ -162,6 +161,7 @@
             mSynthetic = method.access_flags.is(AccessFlags.ACC_SYNTHETIC);
             mIsConstructor = mName.equals("<init>");
             prefix = cname + "." + mName + "() - ";
+            mIsBridge = method.access_flags.is(AccessFlags.ACC_BRIDGE);
 
             sb.append(cname).append(".").append(mName).append("(");
 
@@ -320,6 +320,12 @@
             } else if (isEnum && mNumParams == 1 && index == 0 && mName.equals("valueOf")) {
                 expect = "name";
                 allowMandated = true;
+            } else if (mIsBridge) {
+                allowSynthetic = true;
+                /*  you can't expect an special name for bridges' parameters.
+                 *  The name of the original parameters are now copied.
+                 */
+                expect = null;
             }
             if (mandated) sb.append("!");
             if (synthetic) sb.append("!!");
--- a/langtools/test/tools/javac/MethodParameters/ReflectionVisitor.java	Sat Jun 01 21:57:56 2013 +0100
+++ b/langtools/test/tools/javac/MethodParameters/ReflectionVisitor.java	Sat Jun 01 22:09:18 2013 +0100
@@ -22,8 +22,6 @@
  */
 
 import java.io.*;
-import java.util.*;
-import java.net.*;
 import java.lang.reflect.*;
 
 /**
@@ -250,7 +248,7 @@
                 String expect =  m.isSynthetic() ? ("arg" + i) : ((++c) + param);
                 param = p.getName();
                 sb.append(sep).append(param);
-                if (!expect.equals(param)) {
+                if (!m.isBridge() && !expect.equals(param)) {
                     error(prefix + "param[" + i + "]='"
                           + param + "' expected '" + expect + "'");
                     break;
--- a/langtools/test/tools/javac/MethodParameters/Tester.java	Sat Jun 01 21:57:56 2013 +0100
+++ b/langtools/test/tools/javac/MethodParameters/Tester.java	Sat Jun 01 22:09:18 2013 +0100
@@ -22,7 +22,6 @@
  */
 
 import java.io.*;
-import java.util.*;
 import java.lang.reflect.Constructor;
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java	Sat Jun 01 22:09:18 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 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 6695379
+ * @summary Copy method annotations and parameter annotations to synthetic
+ * bridge methods
+ * @run main AnnotationsAreNotCopiedToBridgeMethodsTest
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.io.BufferedInputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import com.sun.tools.classfile.AccessFlags;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.Attributes;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Method;
+import com.sun.tools.javac.util.Assert;
+
+public class AnnotationsAreNotCopiedToBridgeMethodsTest {
+
+    public static void main(String[] args) throws Exception {
+        new AnnotationsAreNotCopiedToBridgeMethodsTest().run();
+    }
+
+    void run() throws Exception {
+        checkClassFile(Paths.get(System.getProperty("test.classes"),
+                this.getClass().getSimpleName() + "$CovariantReturnType.class"));
+        checkClassFile(Paths.get(System.getProperty("test.classes"),
+                this.getClass().getSimpleName() +
+                "$CovariantReturnType$VisibilityChange.class"));
+    }
+
+    void checkClassFile(final Path cfilePath) throws Exception {
+        ClassFile classFile = ClassFile.read(
+                new BufferedInputStream(Files.newInputStream(cfilePath)));
+        for (Method method : classFile.methods) {
+            if (method.access_flags.is(AccessFlags.ACC_BRIDGE)) {
+                checkForAttr(method.attributes,
+                        "Annotations hasn't been copied to bridge method",
+                        Attribute.RuntimeVisibleAnnotations,
+                        Attribute.RuntimeVisibleParameterAnnotations);
+            }
+        }
+    }
+
+    void checkForAttr(Attributes attrs, String errorMsg, String... attrNames) {
+        for (String attrName : attrNames) {
+            Assert.checkNonNull(attrs.get(attrName), errorMsg);
+        }
+    }
+
+    @Target(value = {ElementType.PARAMETER})
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface ParamAnnotation {}
+
+    @Target(value = {ElementType.METHOD})
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface MethodAnnotation {}
+
+    abstract class T<A,B> {
+        B m(A a){return null;}
+    }
+
+    class CovariantReturnType extends T<Integer, Integer> {
+        @MethodAnnotation
+        Integer m(@ParamAnnotation Integer i) {
+            return i;
+        }
+
+        public class VisibilityChange extends CovariantReturnType {}
+
+    }
+
+}