Fixing a new bug: Considering parameters with Type and Type array, e.g., T and T[].
[jpf-core.git] / src / main / gov / nasa / jpf / jvm / JVMClassInfo.java
index 3cd1214..9c3159a 100644 (file)
 
 package gov.nasa.jpf.jvm;
 
-import gov.nasa.jpf.Config;
-import gov.nasa.jpf.util.Misc;
-import gov.nasa.jpf.util.StringSetMatcher;
-import gov.nasa.jpf.vm.*;
-
 import java.lang.reflect.Modifier;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.LinkedList;
+
+import gov.nasa.jpf.Config;
+import gov.nasa.jpf.util.Misc;
+import gov.nasa.jpf.util.StringSetMatcher;
+import gov.nasa.jpf.vm.AbstractTypeAnnotationInfo;
+import gov.nasa.jpf.vm.AnnotationInfo;
+import gov.nasa.jpf.vm.BootstrapMethodInfo;
+import gov.nasa.jpf.vm.BytecodeAnnotationInfo;
+import gov.nasa.jpf.vm.BytecodeTypeParameterAnnotationInfo;
+import gov.nasa.jpf.vm.ClassInfo;
+import gov.nasa.jpf.vm.ClassInfoException;
+import gov.nasa.jpf.vm.ClassLoaderInfo;
+import gov.nasa.jpf.vm.ClassParseException;
+import gov.nasa.jpf.vm.DirectCallStackFrame;
+import gov.nasa.jpf.vm.ExceptionHandler;
+import gov.nasa.jpf.vm.ExceptionParameterAnnotationInfo;
+import gov.nasa.jpf.vm.FieldInfo;
+import gov.nasa.jpf.vm.FormalParameterAnnotationInfo;
+import gov.nasa.jpf.vm.GenericSignatureHolder;
+import gov.nasa.jpf.vm.InfoObject;
+import gov.nasa.jpf.vm.LocalVarInfo;
+import gov.nasa.jpf.vm.MethodInfo;
+import gov.nasa.jpf.vm.NativeMethodInfo;
+import gov.nasa.jpf.vm.StackFrame;
+import gov.nasa.jpf.vm.SuperTypeAnnotationInfo;
+import gov.nasa.jpf.vm.ThreadInfo;
+import gov.nasa.jpf.vm.ThrowsAnnotationInfo;
+import gov.nasa.jpf.vm.TypeAnnotationInfo;
+import gov.nasa.jpf.vm.TypeParameterAnnotationInfo;
+import gov.nasa.jpf.vm.TypeParameterBoundAnnotationInfo;
+import gov.nasa.jpf.vm.Types;
+import gov.nasa.jpf.vm.VariableAnnotationInfo;
 
 /**
  * a ClassInfo that was created from a Java classfile
@@ -88,10 +116,12 @@ public class JVMClassInfo extends ClassInfo {
     }
     
     @Override
-    public void setBootstrapMethod (ClassFile cf, Object tag, int idx, int refKind, String cls, String mth, String descriptor, int[] cpArgs) {    
-   
+    public void setBootstrapMethod (ClassFile cf, Object tag, int idx, int refKind, String cls, String mth, String descriptor, int[] cpArgs) {
+
+      // TODO: Fix for Groovy's model-checking
+      // TODO: Probably a bug here since cpArgs could be of length 1 sometimes!
       int lambdaRefKind = cf.mhRefTypeAt(cpArgs[1]);
-      
+
       int mrefIdx = cf.mhMethodRefIndexAt(cpArgs[1]);
       String clsName = cf.methodClassNameAt(mrefIdx).replace('/', '.');
       ClassInfo eclosingLambdaCls;
@@ -388,8 +418,12 @@ public class JVMClassInfo extends ClassInfo {
     //--- annotations
     protected AnnotationInfo[] annotations;
     protected AnnotationInfo curAi;
+    protected LinkedList<AnnotationInfo> annotationStack;
+    protected LinkedList<Object[]> valuesStack;
     protected AnnotationInfo[][] parameterAnnotations;
     protected Object[] values;
+    // true if we need to filter null annotations
+    private boolean compactAnnotationArray = false;
 
     //--- declaration annotations
     
@@ -401,16 +435,57 @@ public class JVMClassInfo extends ClassInfo {
     @Override
     public void setAnnotation (ClassFile cf, Object tag, int annotationIndex, String annotationType) {
       if (tag instanceof InfoObject) {
-        curAi = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
-        annotations[annotationIndex] = curAi;
+        if(annotationIndex == -1) {
+          if(annotationStack == null) {
+            assert valuesStack == null;
+            valuesStack = new LinkedList<>();
+            annotationStack = new LinkedList<>();
+          }
+          annotationStack.addFirst(curAi);
+          valuesStack.addFirst(values);
+        }
+        try { 
+          curAi = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
+          if(annotationIndex != -1) {
+            annotations[annotationIndex] = curAi;
+          }
+        } catch(ClassInfoException cie) {
+          // if we can't parse a field, we're sunk, throw and tank the reflective call
+          if(annotationIndex == -1) {
+            throw cie;
+          }
+          compactAnnotationArray = true;
+          annotations[annotationIndex] = null;
+          // skip this annotation
+          throw new SkipAnnotation();
+        }
       }
     }
     
     @Override
     public void setAnnotationsDone (ClassFile cf, Object tag) {
       if (tag instanceof InfoObject) {
-        ((InfoObject) tag).addAnnotations(annotations);
+        AnnotationInfo[] toSet;
+        if(compactAnnotationArray) {
+          int nAnnot = 0;
+          for(AnnotationInfo ai : annotations) {
+            if(ai != null) {
+              nAnnot++;
+            }
+          }
+          toSet = new AnnotationInfo[nAnnot];
+          int idx = 0;
+          for(AnnotationInfo ai : annotations) {
+            if(ai != null) {
+              toSet[idx++] = ai;
+            }
+          }
+        } else {
+          toSet = annotations;
+        }
+        ((InfoObject) tag).addAnnotations(toSet);
       }
+      compactAnnotationArray = false;
     }
 
     @Override
@@ -426,8 +501,14 @@ public class JVMClassInfo extends ClassInfo {
 
     @Override
     public void setParameterAnnotation (ClassFile cf, Object tag, int annotationIndex, String annotationType) {
-      curAi = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
-      annotations[annotationIndex] = curAi;
+      try {
+        curAi = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
+        annotations[annotationIndex] = curAi;
+      } catch(ClassInfoException cie) {
+        compactAnnotationArray = true;
+        annotations[annotationIndex] = null;
+        throw new SkipAnnotation();
+      }
     }
 
     @Override
@@ -533,7 +614,9 @@ public class JVMClassInfo extends ClassInfo {
     public void setAnnotationValueCount (ClassFile cf, Object tag, int annotationIndex, int nValuePairs) {
       // if we have values, we need to clone the defined annotation so that we can overwrite entries
       curAi = curAi.cloneForOverriddenValues();
-      annotations[annotationIndex] = curAi;
+      if(annotationIndex != -1) {
+        annotations[annotationIndex] = curAi;
+      }
     }
     
     @Override
@@ -545,6 +628,19 @@ public class JVMClassInfo extends ClassInfo {
         curAi.setClonedEntryValue(elementName, val);
       }
     }
+    
+    @Override
+    public void setAnnotationFieldValue(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, int arrayIndex) {
+      assert annotationStack.size() > 0;
+      AnnotationInfo ai = curAi;
+      values = valuesStack.pop();
+      curAi = annotationStack.pop();
+      if(arrayIndex >= 0) {
+        values[arrayIndex] = ai;
+      } else {
+        curAi.setClonedEntryValue(elementName, ai);
+      }
+    }
 
     @Override
     public void setStringAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex,