Fixing a new bug: Considering parameters with Type and Type array, e.g., T and T[].
[jpf-core.git] / src / peers / gov / nasa / jpf / vm / JPF_java_lang_reflect_Method.java
index 66b564e1ca4b44979900cb592ab7a81e7d657cbe..05c049fa7a9138614cf748bc4777fd5f3598ba28 100644 (file)
@@ -23,6 +23,7 @@ import gov.nasa.jpf.util.MethodInfoRegistry;
 import gov.nasa.jpf.util.RunListener;
 import gov.nasa.jpf.util.RunRegistry;
 
+import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 
@@ -86,7 +87,7 @@ public class JPF_java_lang_reflect_Method extends NativePeer {
     MethodInfo mi = getMethodInfo(env, objRef);
     return mi.getModifiers();
   }
-  
+
   static int getParameterTypes( MJIEnv env, MethodInfo mi) {
     ThreadInfo ti = env.getThreadInfo();
     String[] argTypeNames = mi.getArgumentTypeNames();
@@ -108,12 +109,244 @@ public class JPF_java_lang_reflect_Method extends NativePeer {
 
     return aRef;
   }
-  
+
   @MJI
   public int getParameterTypes_____3Ljava_lang_Class_2 (MJIEnv env, int objRef){
     return getParameterTypes(env, getMethodInfo(env, objRef));
   }
-  
+
+  // TODO: Fix for Groovy's model-checking
+  private static int getGenericArrayTypeImplObj(String signature, MJIEnv env, int objRef, MethodInfo mi) {
+
+    ThreadInfo ti = env.getThreadInfo();
+    ClassLoaderInfo cli = env.getSystemClassLoaderInfo();
+    ClassInfo ci = cli.getResolvedClassInfo("sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl");
+
+    // Create a new object of type GenericArrayTypeImpl
+    int genArrRef = env.newObject(ci);
+    ElementInfo ei = env.getModifiableElementInfo(genArrRef);
+
+    // Get field information and fill out the fields
+    String clsSig = Types.getArrayClassName(signature);
+    int paramTypeRef;
+    if (Types.isParameterWithType(clsSig)) {
+      paramTypeRef = getTypeVariableImplObject(env, objRef, clsSig);
+    } else {
+      paramTypeRef = getParameterizedTypeImplObj(clsSig, env, objRef, mi);
+    }
+    ei.setReferenceField("genericComponentType", paramTypeRef);
+
+    return genArrRef;
+  }
+
+  private static int getParameterizedTypeImplObj(String signature, MJIEnv env, int objRef, MethodInfo mi) {
+
+    ThreadInfo ti = env.getThreadInfo();
+    ClassLoaderInfo cli = env.getSystemClassLoaderInfo();
+    ClassInfo ci = cli.getResolvedClassInfo("sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl");
+    // Create a new object of type ParameterizedTypeImpl
+    int paramTypeRef = env.newObject(ci);
+    ElementInfo ei = env.getModifiableElementInfo(paramTypeRef);
+    // Get field information and fill out the fields
+    // rawType field
+    String className = Types.getGenericClassName(signature);
+    ClassInfo gci = cli.getResolvedClassInfo(className);
+    if (!gci.isRegistered()) {
+        gci.registerClass(ti);
+    }
+    ei.setReferenceField("rawType", gci.getClassObjectRef());
+
+    // actualTypeArguments
+    String[] parameterizedTypes = Types.getParameterizedTypes(signature);
+    int[] types = new int[parameterizedTypes.length];
+    String classGenericSig = mi.getClassInfo().getGenericSignature();
+    String methodGenericSig = mi.getGenericSignature();
+    for(int j = 0; j < parameterizedTypes.length; j++) {
+      if (Types.isTypeParameter(parameterizedTypes[j], methodGenericSig) ||
+          Types.isTypeParameter(parameterizedTypes[j], classGenericSig)) {
+        types[j] = getTypeVariableImplObject(env, objRef, parameterizedTypes[j]);
+      } else if (Types.isWildcardType(parameterizedTypes[j])) {
+        types[j] = getWildcardTypeImplObject(env, objRef, parameterizedTypes[j], mi);
+      } else if (Types.isParameterizedType(parameterizedTypes[j])) {
+        // Recursion!
+        types[j] = getParameterizedTypeImplObj(parameterizedTypes[j], env, objRef, mi);
+      } else {
+        ClassInfo pci = cli.getResolvedClassInfo(parameterizedTypes[j]);
+        if (!pci.isRegistered()) {
+          pci.registerClass(ti);
+        }
+        types[j] = pci.getClassObjectRef();
+      }
+    }
+    int aRef = env.newObjectArray("Ljava/lang/reflect/Type;", parameterizedTypes.length);
+    // Set references for every array element
+    for (int j = 0; j < parameterizedTypes.length; j++) {
+      env.setReferenceArrayElement(aRef, j, types[j]);
+    }
+    ei.setReferenceField("actualTypeArguments", aRef);
+
+    // ownerType
+    String ownerType = Types.getOwnerClassName(signature);
+    if (ownerType != null) {
+      ClassInfo oci = ClassLoaderInfo.getCurrentResolvedClassInfo(ownerType);
+      if (!oci.isRegistered()) {
+        oci.registerClass(ti);
+      }
+      ei.setReferenceField("ownerType", oci.getClassObjectRef());
+    } else {
+      ei.setReferenceField("ownerType", MJIEnv.NULL);
+    }
+
+    return paramTypeRef;
+  }
+
+  private static int getWildcardTypeImplObject(MJIEnv env, int objRef, String wildcardType, MethodInfo mi) {
+    ThreadInfo ti = env.getThreadInfo();
+    ClassLoaderInfo cli = env.getSystemClassLoaderInfo();
+    ClassInfo ci = cli.getResolvedClassInfo("sun.reflect.generics.reflectiveObjects.WildcardTypeImpl");
+
+    int wildcardRef = env.newObject(ci);
+    ElementInfo ei = env.getModifiableElementInfo(wildcardRef);
+    // Type parameter test
+    // TODO: This test could probably be made cleaner
+    String classGenericSig = mi.getClassInfo().getGenericSignature();
+    String methodGenericSig = mi.getGenericSignature();
+    String typeParameter = Types.getTypeParameter(wildcardType);
+    int uRef = MJIEnv.NULL;
+    int lRef = MJIEnv.NULL;
+    if (Types.isTypeParameter(typeParameter, methodGenericSig) ||
+        Types.isTypeParameter(typeParameter, classGenericSig)) {
+      int tpRef = getTypeVariableImplObject(env, objRef, typeParameter);
+      if (wildcardType.startsWith("+")) {
+        // Set upperBounds
+        uRef = env.newObjectArray("Ljava/lang/reflect/Type;", 1);
+        env.setReferenceArrayElement(uRef, 0, tpRef);
+        lRef = env.newObjectArray("Ljava/lang/reflect/Type;", 0);
+      } else { // wildcardType.startsWith("-")
+        // Set lowerBounds
+        lRef = env.newObjectArray("Ljava/lang/reflect/Type;", 1);
+        env.setReferenceArrayElement(lRef, 0, tpRef);
+        uRef = env.newObjectArray("Ljava/lang/reflect/Type;", 0);
+      }
+    } else {
+
+      String actualType = Types.getWildcardType(wildcardType);
+      ClassInfo uci = cli.getResolvedClassInfo(actualType);
+      if (!uci.isRegistered()) {
+        uci.registerClass(ti);
+      }
+      if (wildcardType.startsWith("+L") || wildcardType.equals("*")) {
+        // Set upperBounds
+        uRef = env.newObjectArray("Ljava/lang/reflect/Type;", 1);
+        env.setReferenceArrayElement(uRef, 0, uci.getClassObjectRef());
+        lRef = env.newObjectArray("Ljava/lang/reflect/Type;", 0);
+      } else { // wildcardType.startsWith("-L")
+        // Set lowerBounds
+        lRef = env.newObjectArray("Ljava/lang/reflect/Type;", 1);
+        env.setReferenceArrayElement(lRef, 0, uci.getClassObjectRef());
+      }
+    }
+    ei.setReferenceField("upperBounds", uRef);
+    ei.setReferenceField("lowerBounds", lRef);
+
+    return wildcardRef;
+  }
+
+  private static int getTypeVariableImplObject(MJIEnv env, int objRef, String parameterizedType) {
+
+    ClassLoaderInfo cli = env.getSystemClassLoaderInfo();
+    ClassInfo ci = cli.getResolvedClassInfo("sun.reflect.generics.reflectiveObjects.TypeVariableImpl");
+
+    int typeVarRef = env.newObject(ci);
+    ElementInfo ei = env.getModifiableElementInfo(typeVarRef);
+    // genericDeclaration contains this java.lang.reflect.Method object
+    ei.setReferenceField("genericDeclaration", objRef);
+    ei.setReferenceField("name", env.newString(parameterizedType));
+
+    return typeVarRef;
+  }
+
+  static int getGenericParameterTypes( MJIEnv env, int objRef, MethodInfo mi) {
+    ThreadInfo ti = env.getThreadInfo();
+    String[] argTypeNames = mi.getArgumentGenericTypeNames();
+    int[] ar = new int[argTypeNames.length];
+
+    String classGenericSig = mi.getClassInfo().getGenericSignature();
+    String methodGenericSig = mi.getGenericSignature();
+    for (int i = 0; i < argTypeNames.length; i++) {
+      // Change this into just the generic class type if it is a generic class
+      if (Types.isGenericSignature(argTypeNames[i])) {
+        if (Types.isArraySignature(argTypeNames[i])) {
+          // Generic array
+          ar[i] = getGenericArrayTypeImplObj(argTypeNames[i], env, objRef, mi);
+        } else {
+          ar[i] = getParameterizedTypeImplObj(argTypeNames[i], env, objRef, mi);
+        }
+      } else if (Types.isTypeParameter(argTypeNames[i], methodGenericSig) ||
+                 Types.isTypeParameter(argTypeNames[i], classGenericSig)) {
+        if (Types.isArraySignature(argTypeNames[i])) {
+          // Generic array
+          ar[i] = getGenericArrayTypeImplObj(argTypeNames[i], env, objRef, mi);
+        } else {
+          ar[i] = getTypeVariableImplObject(env, objRef, argTypeNames[i]);
+        }
+      } else {
+        ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(argTypeNames[i]);
+        if (!ci.isRegistered()) {
+          ci.registerClass(ti);
+        }
+        ar[i] = ci.getClassObjectRef();
+      }
+    }
+    int aRef = env.newObjectArray("Ljava/lang/reflect/Type;", argTypeNames.length);
+    for (int i = 0; i < argTypeNames.length; i++) {
+      env.setReferenceArrayElement(aRef, i, ar[i]);
+    }
+    return aRef;
+  }
+
+  @MJI
+  public int getGenericParameterTypes_____3Ljava_lang_reflect_Type_2 (MJIEnv env, int objRef){
+    return getGenericParameterTypes(env, objRef, getMethodInfo(env, objRef));
+  }
+
+  @MJI
+  public int getGenericReturnType____Ljava_lang_reflect_Type_2 (MJIEnv env, int objRef){
+    MethodInfo mi = getMethodInfo(env, objRef);
+    ThreadInfo ti = env.getThreadInfo();
+
+    String genRetType = mi.getGenericReturnTypeName();
+    String classGenericSig = mi.getClassInfo().getGenericSignature();
+    String methodGenericSig = mi.getGenericSignature();
+    int retRef;
+
+    if (Types.isGenericSignature(genRetType)) {
+      if (Types.isArraySignature(genRetType)) {
+        // Generic array
+        retRef = getGenericArrayTypeImplObj(genRetType, env, objRef, mi);
+      } else {
+        retRef = getParameterizedTypeImplObj(genRetType, env, objRef, mi);
+      }
+    } else if (Types.isTypeParameter(genRetType, methodGenericSig) ||
+               Types.isTypeParameter(genRetType, classGenericSig)) {
+      if (Types.isArraySignature(genRetType)) {
+        // Generic array
+        retRef = getGenericArrayTypeImplObj(genRetType, env, objRef, mi);
+      } else {
+        retRef = getTypeVariableImplObject(env, objRef, genRetType);
+      }
+    } else {
+      ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(mi.getReturnTypeName());
+      if (!ci.isRegistered()) {
+        ci.registerClass(ti);
+      }
+      retRef = ci.getClassObjectRef();
+    }
+
+    return retRef;
+  }
+  // TODO: Fix for Groovy's model-checking
+
   int getExceptionTypes(MJIEnv env, MethodInfo mi) {
     ThreadInfo ti = env.getThreadInfo();
     String[] exceptionNames = mi.getThrownExceptionClassNames();
@@ -146,6 +379,27 @@ public class JPF_java_lang_reflect_Method extends NativePeer {
     return getExceptionTypes(env, getMethodInfo(env, objRef));
   }
   
+  @MJI
+  public int getDefaultValue____Ljava_lang_Object_2(MJIEnv env, int objRef) {
+    MethodInfo mi = getMethodInfo(env, objRef);
+    ClassInfo ci = mi.getClassInfo();
+    if(!ci.isInterface() || ci.getDirectInterfaceNames() == null || ci.getDirectInterfaceNames().length != 1 || !ci.getDirectInterfaceNames()[0].equals("java.lang.annotation.Annotation")) {
+      return MJIEnv.NULL;
+    }
+    String annotationName = ci.getName();
+    AnnotationInfo ai = ci.getClassLoaderInfo().getResolvedAnnotationInfo(annotationName);
+    Object o = ai.getValue(mi.getName());
+    if(o == null) {
+      return MJIEnv.NULL;
+    }
+    try {
+      return env.liftNativeAnnotationValue(Types.getTypeName(mi.getReturnType()), o);
+    } catch(ClinitRequired e) {
+      env.handleClinitRequest(e.getRequiredClassInfo());
+      return -1;
+    }
+  }
+  
   @MJI
   public int getReturnType____Ljava_lang_Class_2 (MJIEnv env, int objRef){
     MethodInfo mi = getMethodInfo(env, objRef);