changeset 48750:616e1f150582 condy-folding

check that method type shape matches with refKind
author vromero
date Wed, 17 Jan 2018 20:16:42 -0500
parents 6961c7cb5e90
children d8b0bfe9ba63
files src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/util/Constables.java test/langtools/tools/javac/specialConstantFolding/checkMethodTypeShape/MethodTypeNegTest.java test/langtools/tools/javac/specialConstantFolding/checkMethodTypeShape/MethodTypeNegTest.out
diffstat 4 files changed, 145 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jan 17 16:19:11 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jan 17 20:16:42 2018 -0500
@@ -3207,6 +3207,14 @@
     while trying to invoke method \"{0}\" of class \"{1}\"\n\
     with error message: \"{2}\"
 
+# 0: type, 1: string
+compiler.err.bad.method.type.shape=\
+    shape of method type: {0} does not match to reference kind: {1}
+
+# 0: type
+compiler.err.bad.method.type.shape.arg.with.type.void=\
+    shape of method type: {0} is incorrect, no argument can have type void
+
 # 0: symbol
 compiler.warn.class.not.found=\
     could not find class file for class: {0}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Constables.java	Wed Jan 17 16:19:11 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Constables.java	Wed Jan 17 20:16:42 2018 -0500
@@ -418,7 +418,71 @@
         }
     }
 
+    String refKindToString(int refKind) {
+        switch (refKind) {
+            case ClassFile.REF_newInvokeSpecial :
+                return "REF_newInvokeSpecial";
+            case ClassFile.REF_invokeVirtual:
+                return "REF_invokeVirtual";
+            case ClassFile.REF_invokeStatic:
+                return "REF_invokeStatic";
+            case ClassFile.REF_invokeSpecial:
+                return "REF_invokeSpecial";
+            case ClassFile.REF_invokeInterface:
+                return "REF_invokeInterface";
+            case ClassFile.REF_putField:
+                return "REF_putField";
+            case ClassFile.REF_putStatic:
+                return "REF_putStatic";
+            case ClassFile.REF_getField:
+                return "REF_getField";
+            case ClassFile.REF_getStatic:
+                return "REF_getStatic";
+            default:
+                throw new AssertionError("invalid refKind value " + refKind);
+        }
+    }
+
+    boolean checkMethodTypeShape(JCTree tree, int refKind, MethodType methodType) {
+        boolean error;
+        switch (refKind) {
+            case ClassFile.REF_newInvokeSpecial :
+                error = !methodType.restype.hasTag(TypeTag.VOID);
+                break;
+            case ClassFile.REF_invokeVirtual:
+            case ClassFile.REF_invokeStatic:
+            case ClassFile.REF_invokeSpecial:
+            case ClassFile.REF_invokeInterface:
+                error = false;
+                break;
+            case ClassFile.REF_putField:
+                error = methodType.argtypes.size() != 2 || !methodType.restype.hasTag(TypeTag.VOID);
+                break;
+            case ClassFile.REF_putStatic:
+                error = methodType.argtypes.size() != 1 || !methodType.restype.hasTag(TypeTag.VOID);
+                break;
+            case ClassFile.REF_getField:
+                error = methodType.argtypes.size() != 1 || methodType.restype.hasTag(TypeTag.VOID);
+                break;
+            case ClassFile.REF_getStatic:
+                error = methodType.argtypes.size() > 0 || methodType.restype.hasTag(TypeTag.VOID);
+                break;
+            default:
+                throw new AssertionError("invalid refKind value " + refKind);
+        }
+        if (error) {
+            log.error(tree, Errors.BadMethodTypeShape(methodType, refKindToString(refKind)));
+        }
+        if (methodType.argtypes.stream().filter(t -> t.hasTag(TypeTag.VOID)).findAny().isPresent()) {
+            log.error(tree, Errors.BadMethodTypeShapeArgWithTypeVoid(methodType));
+        }
+        return !error;
+    }
+
     private Symbol getReferenceSymbol(JCTree tree, int refKind, Symbol owner, String name, MethodType methodType) {
+        if (!checkMethodTypeShape(tree, refKind, methodType)) {
+            return syms.noSymbol;
+        }
         long flags = refKind == ClassFile.REF_getStatic ||
                 refKind == ClassFile.REF_putStatic ||
                 refKind == ClassFile.REF_invokeStatic ? STATIC : 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/specialConstantFolding/checkMethodTypeShape/MethodTypeNegTest.java	Wed Jan 17 20:16:42 2018 -0500
@@ -0,0 +1,51 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary check that method type's shape matches the reference kind
+ * @compile/fail/ref=MethodTypeNegTest.out -XDdoConstantFold -Werror -XDrawDiagnostics MethodTypeNegTest.java
+ */
+
+import java.lang.invoke.MethodHandle;
+import java.lang.sym.ClassRef;
+import java.lang.sym.MethodHandleRef;
+import java.lang.sym.SymbolicRefs;
+
+import static java.lang.invoke.Intrinsics.ldc;
+import static java.lang.sym.MethodHandleRef.Kind.*;
+
+public class MethodTypeNegTest {
+    private static final ClassRef CR_THIS = ClassRef.of("MethodTypeNegTest");
+
+    void test() {
+        // for setters result must be void...
+        MethodHandleRef r1 = MethodHandleRef.of(MethodHandleRef.Kind.SETTER, CR_THIS, "nonexistent", SymbolicRefs.CR_int);
+        MethodHandle mh1 = ldc(r1);
+        MethodHandleRef r2 = MethodHandleRef.of(MethodHandleRef.Kind.STATIC_SETTER, CR_THIS, "nonexistent", SymbolicRefs.CR_int);
+        MethodHandle mh2 = ldc(r2);
+
+        // ...and static setters should have only one argument and instance setters two
+        MethodHandleRef r3 = MethodHandleRef.of(MethodHandleRef.Kind.SETTER, CR_THIS, "nonexistent", SymbolicRefs.CR_void, SymbolicRefs.CR_int);
+        MethodHandle mh3 = ldc(r3);
+        MethodHandleRef r4 = MethodHandleRef.of(MethodHandleRef.Kind.STATIC_SETTER, CR_THIS, "nonexistent", SymbolicRefs.CR_void, SymbolicRefs.CR_int, SymbolicRefs.CR_int);
+        MethodHandle mh4 = ldc(r4);
+
+        // for constructors result type must be void
+        MethodHandleRef r5 = MethodHandleRef.of(MethodHandleRef.Kind.CONSTRUCTOR, CR_THIS, "", SymbolicRefs.CR_int);
+        MethodHandle mh5 = ldc(r5);
+
+        // for getters result must be different from void...
+        MethodHandleRef r6 = MethodHandleRef.of(MethodHandleRef.Kind.GETTER, CR_THIS, "nonexistent", SymbolicRefs.CR_void);
+        MethodHandle mh6 = ldc(r6);
+        MethodHandleRef r7 = MethodHandleRef.of(MethodHandleRef.Kind.STATIC_GETTER, CR_THIS, "nonexistent", SymbolicRefs.CR_void);
+        MethodHandle mh7 = ldc(r7);
+
+        // ...and instance setters should have only one argument, static ones none
+        MethodHandleRef r8 = MethodHandleRef.of(MethodHandleRef.Kind.GETTER, CR_THIS, "nonexistent", SymbolicRefs.CR_int, SymbolicRefs.CR_int, SymbolicRefs.CR_int);
+        MethodHandle mh8 = ldc(r8);
+        MethodHandleRef r9 = MethodHandleRef.of(MethodHandleRef.Kind.STATIC_GETTER, CR_THIS, "nonexistent", SymbolicRefs.CR_int, SymbolicRefs.CR_int, SymbolicRefs.CR_int);
+        MethodHandle mh9 = ldc(r9);
+
+        // no argument can be void
+        MethodHandleRef r10 = MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, CR_THIS, "nonexistent", SymbolicRefs.CR_int, SymbolicRefs.CR_void);
+        MethodHandle mh10 = ldc(r10);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/specialConstantFolding/checkMethodTypeShape/MethodTypeNegTest.out	Wed Jan 17 20:16:42 2018 -0500
@@ -0,0 +1,22 @@
+MethodTypeNegTest.java:21:31: compiler.err.bad.method.type.shape: ()int, REF_putField
+MethodTypeNegTest.java:21:31: compiler.warn.member.not.found.at.class: nonexistent, class,
+MethodTypeNegTest.java:23:31: compiler.err.bad.method.type.shape: ()int, REF_putStatic
+MethodTypeNegTest.java:23:31: compiler.warn.member.not.found.at.class: nonexistent, class,
+MethodTypeNegTest.java:27:31: compiler.err.bad.method.type.shape: (int)void, REF_putField
+MethodTypeNegTest.java:27:31: compiler.warn.member.not.found.at.class: nonexistent, class,
+MethodTypeNegTest.java:29:31: compiler.err.bad.method.type.shape: (int,int)void, REF_putStatic
+MethodTypeNegTest.java:29:31: compiler.warn.member.not.found.at.class: nonexistent, class,
+MethodTypeNegTest.java:33:31: compiler.err.bad.method.type.shape: ()int, REF_newInvokeSpecial
+MethodTypeNegTest.java:33:31: compiler.warn.member.not.found.at.class: <init>, class,
+MethodTypeNegTest.java:37:31: compiler.err.bad.method.type.shape: ()void, REF_getField
+MethodTypeNegTest.java:37:31: compiler.warn.member.not.found.at.class: nonexistent, class,
+MethodTypeNegTest.java:39:31: compiler.err.bad.method.type.shape: ()void, REF_getStatic
+MethodTypeNegTest.java:39:31: compiler.warn.member.not.found.at.class: nonexistent, class,
+MethodTypeNegTest.java:43:31: compiler.err.bad.method.type.shape: (int,int)int, REF_getField
+MethodTypeNegTest.java:43:31: compiler.warn.member.not.found.at.class: nonexistent, class,
+MethodTypeNegTest.java:45:31: compiler.err.bad.method.type.shape: (int,int)int, REF_getStatic
+MethodTypeNegTest.java:45:31: compiler.warn.member.not.found.at.class: nonexistent, class,
+MethodTypeNegTest.java:49:32: compiler.err.bad.method.type.shape.arg.with.type.void: (void)int
+MethodTypeNegTest.java:49:32: compiler.warn.member.not.found.at.class: nonexistent, class, MethodTypeNegTest
+10 errors
+10 warnings