import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / classfmt / MethodInfo.java
index c9255be..7a27b96 100644 (file)
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.classfmt;
 
+import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants;
 import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 
 public class MethodInfo extends ClassFileStruct implements IBinaryMethod, AttributeNamesConstants, Comparable {
-       private char[][] exceptionNames;
-       private int[] constantPoolOffsets;
-       private boolean isDeprecated;
-       private boolean isSynthetic;
+       static private final char[][] noException = CharOperation.NO_CHAR_CHAR;
        private int accessFlags;
+       private int attributeBytes;
+       private int[] constantPoolOffsets;
+       private char[] descriptor;
+       private char[][] exceptionNames;
        private char[] name;
        private char[] signature;
-       private int attributeBytes;
-       static private final char[][] noException = CharOperation.NO_CHAR_CHAR;
+       private int signatureUtf8Offset;
+       private long tagBits;   
+       
 /**
  * @param classFileBytes byte[]
  * @param offsets int[]
@@ -35,11 +40,108 @@ public MethodInfo (byte classFileBytes[], int offsets[], int offset) {
        accessFlags = -1;
        int attributesCount = u2At(6);
        int readOffset = 8;
+       this.signatureUtf8Offset = -1;
        for (int i = 0; i < attributesCount; i++) {
+               // check the name of each attribute
+               int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
+               char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+               if (attributeName.length > 0) {
+                       switch(attributeName[0]) {
+                               case 'S' :
+                                       if (CharOperation.equals(AttributeNamesConstants.SignatureName, attributeName)) {
+                                               this.signatureUtf8Offset = constantPoolOffsets[u2At(readOffset + 6)] - structOffset;
+                                       }
+                                       break;
+                               case 'R' :
+                                       if (CharOperation.equals(attributeName, RuntimeVisibleAnnotationsName)) {
+                                               decodeStandardAnnotations(readOffset);
+                                       }
+                       }
+               }
                readOffset += (6 + u4At(readOffset + 2));
        }
        attributeBytes = readOffset;
 }
+public int compareTo(Object o) {
+       if (!(o instanceof MethodInfo)) {
+               throw new ClassCastException();
+       }
+
+       MethodInfo otherMethod = (MethodInfo) o;
+       int result = new String(this.getSelector()).compareTo(new String(otherMethod.getSelector()));
+       if (result != 0) return result;
+       return new String(this.getMethodDescriptor()).compareTo(new String(otherMethod.getMethodDescriptor()));
+}
+private int decodeAnnotation(int offset) {
+       int readOffset = offset;
+       int utf8Offset = this.constantPoolOffsets[u2At(offset)] - structOffset;
+       char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+       typeName = Signature.toCharArray(typeName);
+       CharOperation.replace(typeName, '/', '.');
+       char[][] qualifiedTypeName = CharOperation.splitOn('.', typeName);
+       int numberOfPairs = u2At(offset + 2);
+       readOffset += 4;
+       if (qualifiedTypeName.length == 3) {
+               char[] lastPart = qualifiedTypeName[2];
+               if (lastPart[0] == 'D') {
+                       if (CharOperation.equals(qualifiedTypeName, TypeConstants.JAVA_LANG_DEPRECATED)) {
+                               this.tagBits |= TagBits.AnnotationDeprecated;
+                               return readOffset;              
+                       }
+               }
+       }
+       for (int i = 0; i < numberOfPairs; i++) {
+               readOffset += 2;
+               readOffset = decodeElementValue(readOffset);
+       }
+       return readOffset;
+}
+private int decodeElementValue(int offset) {
+       int readOffset = offset;
+       int tag = u1At(readOffset);
+       readOffset++;
+       switch(tag) {
+               case 'B' :
+               case 'C' :
+               case 'D' :
+               case 'F' :
+               case 'I' :
+               case 'J' :
+               case 'S' :
+               case 'Z' :
+               case 's' :
+                       readOffset += 2;
+                       break;
+               case 'e' :
+                       readOffset += 4;
+                       break;
+               case 'c' :
+                       readOffset += 2;
+                       break;
+               case '@' :
+                       readOffset += decodeAnnotation(readOffset);
+                       break;
+               case '[' :
+                       int numberOfValues = u2At(readOffset);
+                       readOffset += 2;
+                       for (int i = 0; i < numberOfValues; i++) {
+                               readOffset = decodeElementValue(readOffset);
+                       }
+                       break;
+       }
+       return readOffset;
+}
+/**
+ * @param offset the offset is located at the beginning of the runtime visible 
+ * annotation attribute.
+ */
+private void decodeStandardAnnotations(int offset) {
+       int numberOfAnnotations = u2At(offset + 6);
+       int readOffset = offset + 8;
+       for (int i = 0; i < numberOfAnnotations; i++) {
+               readOffset = decodeAnnotation(readOffset);
+       }
+}
 /**
  * @see org.eclipse.jdt.internal.compiler.env.IGenericMethod#getArgumentNames()
  */
@@ -60,6 +162,16 @@ public char[][] getExceptionTypeNames() {
        }
        return exceptionNames;
 }
+public char[] getGenericSignature() {
+       if (this.signatureUtf8Offset != -1) {
+               if (this.signature == null) {
+                       // decode the signature
+                       this.signature = utf8At(this.signatureUtf8Offset + 3, u2At(this.signatureUtf8Offset + 1));
+               }
+               return this.signature;
+       }
+       return null;
+}
 /**
  * Answer the receiver's method descriptor which describes the parameter &
  * return types as specified in section 4.3.3 of the Java 2 VM spec.
@@ -70,12 +182,12 @@ public char[][] getExceptionTypeNames() {
  * @return char[]
  */
 public char[] getMethodDescriptor() {
-       if (signature == null) {
+       if (descriptor == null) {
                // read the name
                int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset;
-               signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+               descriptor = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
        }
-       return signature;
+       return descriptor;
 }
 /**
  * Answer an int whose bits are set according the access constants
@@ -84,18 +196,12 @@ public char[] getMethodDescriptor() {
  * @return int
  */
 public int getModifiers() {
-       if (accessFlags == -1) {
+       if (this.accessFlags == -1) {
                // compute the accessflag. Don't forget the deprecated attribute
-               accessFlags = u2At(0);
-               readDeprecatedAndSyntheticAttributes();
-               if (isDeprecated) {
-                       accessFlags |= AccDeprecated;
-               }
-               if (isSynthetic) {
-                       accessFlags |= AccSynthetic;
-               }
+               this.accessFlags = u2At(0);
+               readModifierRelatedAttributes();
        }
-       return accessFlags;
+       return this.accessFlags;
 }
 /**
  * Answer the name of the method.
@@ -111,6 +217,21 @@ public char[] getSelector() {
        }
        return name;
 }
+public long getTagBits() {
+       return this.tagBits;
+}
+/**
+ * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos
+ * will be therefore fully initialized and we can get rid of the bytes.
+ */
+void initialize() {
+       getModifiers();
+       getSelector();
+       getMethodDescriptor();
+       getExceptionTypeNames();
+       getGenericSignature();
+       reset();
+}
 /**
  * Answer true if the method is a class initializer, false otherwise.
  * @return boolean
@@ -134,20 +255,6 @@ public boolean isConstructor() {
 public boolean isSynthetic() {
        return (getModifiers() & AccSynthetic) != 0;
 }
-private void readDeprecatedAndSyntheticAttributes() {
-       int attributesCount = u2At(6);
-       int readOffset = 8;
-       for (int i = 0; i < attributesCount; i++) {
-               int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
-               char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
-               if (CharOperation.equals(attributeName, DeprecatedName)) {
-                       isDeprecated = true;
-               } else if (CharOperation.equals(attributeName, SyntheticName)) {
-                       isSynthetic = true;
-               }
-               readOffset += (6 + u4At(readOffset + 2));
-       }
-}
 private void readExceptionAttributes() {
        int attributesCount = u2At(6);
        int readOffset = 8;
@@ -180,6 +287,36 @@ private void readExceptionAttributes() {
                exceptionNames = noException;
        }
 }
+private void readModifierRelatedAttributes() {
+       int attributesCount = u2At(6);
+       int readOffset = 8;
+       for (int i = 0; i < attributesCount; i++) {
+               int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
+               char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+               // test added for obfuscated .class file. See 79772
+               if (attributeName.length != 0) {
+                       switch(attributeName[0]) {
+                               case 'D' :
+                                       if (CharOperation.equals(attributeName, DeprecatedName))
+                                               this.accessFlags |= AccDeprecated;
+                                       break;
+                               case 'S' :
+                                       if (CharOperation.equals(attributeName, SyntheticName))
+                                               this.accessFlags |= AccSynthetic;
+                                       break;
+                               case 'A' :
+                                       if (CharOperation.equals(attributeName, AnnotationDefaultName))
+                                               this.accessFlags |= AccAnnotationDefault;
+                                       break;
+                       }
+               }
+               readOffset += (6 + u4At(readOffset + 2));
+       }
+}
+protected void reset() {
+       this.constantPoolOffsets = null;
+       super.reset();
+}
 /**
  * Answer the size of the receiver in bytes.
  * 
@@ -190,6 +327,9 @@ public int sizeInBytes() {
 }
 public String toString() {
        int modifiers = getModifiers();
+       char[] desc = getGenericSignature();
+       if (desc == null)
+               desc = getMethodDescriptor();
        StringBuffer buffer = new StringBuffer(this.getClass().getName());
        return buffer
                .append("{") //$NON-NLS-1$
@@ -201,36 +341,10 @@ public String toString() {
                                + ((modifiers & 0x0008) == 0x000008 ? "static " : "") //$NON-NLS-1$ //$NON-NLS-2$
                                + ((modifiers & 0x0010) == 0x0010 ? "final " : "") //$NON-NLS-1$ //$NON-NLS-2$
                                + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "") //$NON-NLS-1$ //$NON-NLS-2$
-                               + ((modifiers & 0x0080) == 0x0080 ? "transient " : "")) //$NON-NLS-1$ //$NON-NLS-2$
+                               + ((modifiers & 0x0080) == 0x0080 ? "varargs " : "")) //$NON-NLS-1$ //$NON-NLS-2$
                .append(getSelector())
-               .append(getMethodDescriptor())
+               .append(desc)
                .append("}") //$NON-NLS-1$
                .toString(); 
 }
-public int compareTo(Object o) {
-       if (!(o instanceof MethodInfo)) {
-               throw new ClassCastException();
-       }
-
-       MethodInfo otherMethod = (MethodInfo) o;
-       int result = new String(this.getSelector()).compareTo(new String(otherMethod.getSelector()));
-       if (result != 0) return result;
-       return new String(this.getMethodDescriptor()).compareTo(new String(otherMethod.getMethodDescriptor()));
-}
-
-/**
- * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos
- * will be therefore fully initialized and we can get rid of the bytes.
- */
-void initialize() {
-       getModifiers();
-       getSelector();
-       getMethodDescriptor();
-       getExceptionTypeNames();
-       reset();
-}
-protected void reset() {
-       this.constantPoolOffsets = null;
-       super.reset();
-}
 }