changeset 15049:f4186cbd8a20

@MethodSubstitution verifier checks that the type of an inserted 'this' parameter is assignable from the type in which the original method is declared
author Doug Simon <doug.simon@oracle.com>
date Wed, 09 Apr 2014 18:53:48 +0200
parents dfcb1a5a7b5a
children 90e8e3b90558
files graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/MethodSubstitutionVerifier.java
diffstat 1 files changed, 28 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/MethodSubstitutionVerifier.java	Wed Apr 09 18:52:04 2014 +0200
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/MethodSubstitutionVerifier.java	Wed Apr 09 18:53:48 2014 +0200
@@ -89,17 +89,17 @@
         }
 
         String originalName = originalName(substitutionMethod, annotation);
-        TypeMirror[] originalSignature = originalSignature(substitutionMethod, annotation);
+        TypeMirror[] originalSignature = originalSignature(originalType, substitutionMethod, annotation);
         if (originalSignature == null) {
             return;
         }
         ExecutableElement originalMethod = originalMethod(substitutionMethod, annotation, originalType, originalName, originalSignature);
         if (DEBUG && originalMethod != null) {
-            env.getMessager().printMessage(Kind.ERROR, String.format("Found original method %s in type %s.", originalMethod, findEnclosingClass(originalMethod)));
+            env.getMessager().printMessage(Kind.NOTE, String.format("Found original method %s in type %s.", originalMethod, findEnclosingClass(originalMethod)));
         }
     }
 
-    private TypeMirror[] originalSignature(ExecutableElement method, AnnotationMirror annotation) {
+    private TypeMirror[] originalSignature(TypeElement originalType, ExecutableElement method, AnnotationMirror annotation) {
         boolean isStatic = resolveAnnotationValue(Boolean.class, findAnnotationValue(annotation, ORIGINAL_IS_STATIC));
         AnnotationValue signatureValue = findAnnotationValue(annotation, ORIGINAL_SIGNATURE);
         String signatureString = resolveAnnotationValue(String.class, signatureValue);
@@ -113,7 +113,11 @@
                     env.getMessager().printMessage(Kind.ERROR, "Method signature must be a static method with the 'this' object as its first parameter", method, annotation);
                     return null;
                 } else {
-                    parameters.remove(0);
+                    TypeMirror thisParam = parameters.remove(0);
+                    if (!isSubtype(originalType.asType(), thisParam)) {
+                        Name thisName = method.getParameters().get(0).getSimpleName();
+                        env.getMessager().printMessage(Kind.ERROR, String.format("The type of %s must assignable from %s", thisName, originalType), method, annotation);
+                    }
                 }
             }
             parameters.add(0, method.getReturnType());
@@ -201,6 +205,26 @@
         return env.getTypeUtils().isSameType(original, substitution);
     }
 
+    /**
+     * Tests whether one type is a subtype of another. Any type is considered to be a subtype of
+     * itself.
+     *
+     * @param t1 the first type
+     * @param t2 the second type
+     * @return {@code true} if and only if the first type is a subtype of the second
+     */
+    private boolean isSubtype(TypeMirror t1, TypeMirror t2) {
+        TypeMirror t1Erased = t1;
+        TypeMirror t2Erased = t2;
+        if (needsErasure(t1Erased)) {
+            t1Erased = env.getTypeUtils().erasure(t1Erased);
+        }
+        if (needsErasure(t2Erased)) {
+            t2Erased = env.getTypeUtils().erasure(t2Erased);
+        }
+        return env.getTypeUtils().isSubtype(t1Erased, t2Erased);
+    }
+
     private static boolean needsErasure(TypeMirror typeMirror) {
         return typeMirror.getKind() != TypeKind.NONE && typeMirror.getKind() != TypeKind.VOID && !typeMirror.getKind().isPrimitive() && typeMirror.getKind() != TypeKind.OTHER &&
                         typeMirror.getKind() != TypeKind.NULL;