*******************************************************************************/
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.IBinaryField;
import org.eclipse.jdt.internal.compiler.impl.LongConstant;
import org.eclipse.jdt.internal.compiler.impl.ShortConstant;
import org.eclipse.jdt.internal.compiler.impl.StringConstant;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.util.Util;
public class FieldInfo extends ClassFileStruct implements AttributeNamesConstants, IBinaryField, Comparable, TypeIds {
+ private int accessFlags;
+ private int attributeBytes;
private Constant constant;
- private boolean isDeprecated;
- private boolean isSynthetic;
private int[] constantPoolOffsets;
- private int accessFlags;
+ private char[] descriptor;
private char[] name;
private char[] signature;
- private int attributeBytes;
+ private int signatureUtf8Offset;
+ private long tagBits;
private Object wrappedConstantValue;
/**
* @param classFileBytes byte[]
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 FieldInfo)) {
+ throw new ClassCastException();
+ }
+ return new String(this.getName()).compareTo(new String(((FieldInfo) o).getName()));
+}
+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);
+ }
+}
/**
* Return the constant of the field.
* Return org.eclipse.jdt.internal.compiler.impl.Constant.NotAConstant if there is none.
}
return constant;
}
+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 an int whose bits are set according the access constants
* defined by the VM spec.
* @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 field.
}
return name;
}
+public long getTagBits() {
+ return this.tagBits;
+}
/**
* Answer the resolved name of the receiver's type in the
* class file format as specified in section 4.3.2 of the Java 2 VM spec.
* @return char[]
*/
public char[] getTypeName() {
- if (signature == null) {
+ if (descriptor == null) {
// read the signature
int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset;
- signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ descriptor = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
}
- return signature;
+ return descriptor;
}
/**
* Return a wrapper that contains the constant of the field.
case T_long :
this.wrappedConstantValue = new Long(fieldConstant.longValue());
break;
- case T_String :
+ case T_JavaLangString :
this.wrappedConstantValue = fieldConstant.stringValue();
}
}
return getConstant() != Constant.NotAConstant;
}
/**
+ * 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();
+ getName();
+ getConstant();
+ getTypeName();
+ getGenericSignature();
+ reset();
+}
+/**
* Return true if the field is a synthetic field, false otherwise.
* @return boolean
*/
constant = Constant.NotAConstant;
}
}
-private void readDeprecatedAndSyntheticAttributes() {
+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));
- if (CharOperation.equals(attributeName, DeprecatedName)) {
- isDeprecated = true;
- } else if (CharOperation.equals(attributeName, SyntheticName)) {
- isSynthetic = true;
+ // 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;
+ }
}
readOffset += (6 + u4At(readOffset + 2));
}
}
+protected void reset() {
+ this.constantPoolOffsets = null;
+ super.reset();
+}
/**
* Answer the size of the receiver in bytes.
*
.toString();
}
-public int compareTo(Object o) {
- if (!(o instanceof FieldInfo)) {
- throw new ClassCastException();
- }
- return new String(this.getName()).compareTo(new String(((FieldInfo) o).getName()));
-}
-/**
- * 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();
- getName();
- getConstant();
- getTypeName();
- reset();
-}
-protected void reset() {
- this.constantPoolOffsets = null;
- super.reset();
-}
-
}