1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.classfmt;
13 import org.eclipse.jdt.core.Signature;
14 import org.eclipse.jdt.core.compiler.CharOperation;
15 import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants;
16 import org.eclipse.jdt.internal.compiler.env.IBinaryField;
17 import org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
18 import org.eclipse.jdt.internal.compiler.impl.ByteConstant;
19 import org.eclipse.jdt.internal.compiler.impl.CharConstant;
20 import org.eclipse.jdt.internal.compiler.impl.Constant;
21 import org.eclipse.jdt.internal.compiler.impl.DoubleConstant;
22 import org.eclipse.jdt.internal.compiler.impl.FloatConstant;
23 import org.eclipse.jdt.internal.compiler.impl.IntConstant;
24 import org.eclipse.jdt.internal.compiler.impl.LongConstant;
25 import org.eclipse.jdt.internal.compiler.impl.ShortConstant;
26 import org.eclipse.jdt.internal.compiler.impl.StringConstant;
27 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
28 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
29 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
30 import org.eclipse.jdt.internal.compiler.util.Util;
32 public class FieldInfo extends ClassFileStruct implements AttributeNamesConstants, IBinaryField, Comparable, TypeIds {
33 private int accessFlags;
34 private int attributeBytes;
35 private Constant constant;
36 private int[] constantPoolOffsets;
37 private char[] descriptor;
39 private char[] signature;
40 private int signatureUtf8Offset;
42 private Object wrappedConstantValue;
44 * @param classFileBytes byte[]
45 * @param offsets int[]
48 public FieldInfo (byte classFileBytes[], int offsets[], int offset) {
49 super(classFileBytes, offset);
50 constantPoolOffsets = offsets;
52 int attributesCount = u2At(6);
54 this.signatureUtf8Offset = -1;
55 for (int i = 0; i < attributesCount; i++) {
56 // check the name of each attribute
57 int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
58 char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
59 if (attributeName.length > 0) {
60 switch(attributeName[0]) {
62 if (CharOperation.equals(AttributeNamesConstants.SignatureName, attributeName)) {
63 this.signatureUtf8Offset = constantPoolOffsets[u2At(readOffset + 6)] - structOffset;
67 if (CharOperation.equals(attributeName, RuntimeVisibleAnnotationsName)) {
68 decodeStandardAnnotations(readOffset);
72 readOffset += (6 + u4At(readOffset + 2));
74 attributeBytes = readOffset;
77 public int compareTo(Object o) {
78 if (!(o instanceof FieldInfo)) {
79 throw new ClassCastException();
81 return new String(this.getName()).compareTo(new String(((FieldInfo) o).getName()));
83 private int decodeAnnotation(int offset) {
84 int readOffset = offset;
85 int utf8Offset = this.constantPoolOffsets[u2At(offset)] - structOffset;
86 char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
87 typeName = Signature.toCharArray(typeName);
88 CharOperation.replace(typeName, '/', '.');
89 char[][] qualifiedTypeName = CharOperation.splitOn('.', typeName);
90 int numberOfPairs = u2At(offset + 2);
92 if (qualifiedTypeName.length == 3) {
93 char[] lastPart = qualifiedTypeName[2];
94 if (lastPart[0] == 'D') {
95 if (CharOperation.equals(qualifiedTypeName, TypeConstants.JAVA_LANG_DEPRECATED)) {
96 this.tagBits |= TagBits.AnnotationDeprecated;
101 for (int i = 0; i < numberOfPairs; i++) {
103 readOffset = decodeElementValue(readOffset);
107 private int decodeElementValue(int offset) {
108 int readOffset = offset;
109 int tag = u1At(readOffset);
130 readOffset += decodeAnnotation(readOffset);
133 int numberOfValues = u2At(readOffset);
135 for (int i = 0; i < numberOfValues; i++) {
136 readOffset = decodeElementValue(readOffset);
143 * @param offset the offset is located at the beginning of the runtime visible
144 * annotation attribute.
146 private void decodeStandardAnnotations(int offset) {
147 int numberOfAnnotations = u2At(offset + 6);
148 int readOffset = offset + 8;
149 for (int i = 0; i < numberOfAnnotations; i++) {
150 readOffset = decodeAnnotation(readOffset);
154 * Return the constant of the field.
155 * Return org.eclipse.jdt.internal.compiler.impl.Constant.NotAConstant if there is none.
156 * @return org.eclipse.jdt.internal.compiler.impl.Constant
158 public Constant getConstant() {
159 if (constant == null) {
161 readConstantAttribute();
165 public char[] getGenericSignature() {
166 if (this.signatureUtf8Offset != -1) {
167 if (this.signature == null) {
168 // decode the signature
169 this.signature = utf8At(this.signatureUtf8Offset + 3, u2At(this.signatureUtf8Offset + 1));
171 return this.signature;
176 * Answer an int whose bits are set according the access constants
177 * defined by the VM spec.
178 * Set the AccDeprecated and AccSynthetic bits if necessary
181 public int getModifiers() {
182 if (this.accessFlags == -1) {
183 // compute the accessflag. Don't forget the deprecated attribute
184 this.accessFlags = u2At(0);
185 readModifierRelatedAttributes();
187 return this.accessFlags;
190 * Answer the name of the field.
193 public char[] getName() {
196 int utf8Offset = constantPoolOffsets[u2At(2)] - structOffset;
197 name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
201 public long getTagBits() {
205 * Answer the resolved name of the receiver's type in the
206 * class file format as specified in section 4.3.2 of the Java 2 VM spec.
209 * - java.lang.String is Ljava/lang/String;
211 * - a 2 dimensional array of strings is [[Ljava/lang/String;
212 * - an array of floats is [F
215 public char[] getTypeName() {
216 if (descriptor == null) {
217 // read the signature
218 int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset;
219 descriptor = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
224 * Return a wrapper that contains the constant of the field.
225 * @return java.lang.Object
227 public Object getWrappedConstantValue() {
229 if (this.wrappedConstantValue == null) {
231 Constant fieldConstant = getConstant();
232 switch (fieldConstant.typeID()) {
234 this.wrappedConstantValue = new Integer(fieldConstant.intValue());
237 this.wrappedConstantValue = new Byte(fieldConstant.byteValue());
240 this.wrappedConstantValue = new Short(fieldConstant.shortValue());
243 this.wrappedConstantValue = new Character(fieldConstant.charValue());
246 this.wrappedConstantValue = new Float(fieldConstant.floatValue());
249 this.wrappedConstantValue = new Double(fieldConstant.doubleValue());
252 this.wrappedConstantValue = Util.toBoolean(fieldConstant.booleanValue());
255 this.wrappedConstantValue = new Long(fieldConstant.longValue());
257 case T_JavaLangString :
258 this.wrappedConstantValue = fieldConstant.stringValue();
262 return this.wrappedConstantValue;
265 * Return true if the field has a constant value attribute, false otherwise.
268 public boolean hasConstant() {
269 return getConstant() != Constant.NotAConstant;
272 * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos
273 * will be therefore fully initialized and we can get rid of the bytes.
280 getGenericSignature();
284 * Return true if the field is a synthetic field, false otherwise.
287 public boolean isSynthetic() {
288 return (getModifiers() & AccSynthetic) != 0;
291 private void readConstantAttribute() {
292 int attributesCount = u2At(6);
294 boolean isConstant = false;
295 for (int i = 0; i < attributesCount; i++) {
296 int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
297 char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
299 .equals(attributeName, ConstantValueName)) {
301 // read the right constant
302 int relativeOffset = constantPoolOffsets[u2At(readOffset + 6)] - structOffset;
303 switch (u1At(relativeOffset)) {
305 char[] sign = getTypeName();
306 if (sign.length == 1) {
308 case 'Z' : // boolean constant
309 constant = new BooleanConstant(i4At(relativeOffset + 1) == 1);
311 case 'I' : // integer constant
312 constant = new IntConstant(i4At(relativeOffset + 1));
314 case 'C' : // char constant
315 constant = new CharConstant((char) i4At(relativeOffset + 1));
317 case 'B' : // byte constant
318 constant = new ByteConstant((byte) i4At(relativeOffset + 1));
320 case 'S' : // short constant
321 constant = new ShortConstant((short) i4At(relativeOffset + 1));
324 constant = Constant.NotAConstant;
327 constant = Constant.NotAConstant;
331 constant = new FloatConstant(floatAt(relativeOffset + 1));
334 constant = new DoubleConstant(doubleAt(relativeOffset + 1));
337 constant = new LongConstant(i8At(relativeOffset + 1));
340 utf8Offset = constantPoolOffsets[u2At(relativeOffset + 1)] - structOffset;
343 String.valueOf(utf8At(utf8Offset + 3, u2At(utf8Offset + 1))));
347 readOffset += (6 + u4At(readOffset + 2));
350 constant = Constant.NotAConstant;
353 private void readModifierRelatedAttributes() {
354 int attributesCount = u2At(6);
356 for (int i = 0; i < attributesCount; i++) {
357 int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
358 char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
359 // test added for obfuscated .class file. See 79772
360 if (attributeName.length != 0) {
361 switch(attributeName[0]) {
363 if (CharOperation.equals(attributeName, DeprecatedName))
364 this.accessFlags |= AccDeprecated;
367 if (CharOperation.equals(attributeName, SyntheticName))
368 this.accessFlags |= AccSynthetic;
372 readOffset += (6 + u4At(readOffset + 2));
375 protected void reset() {
376 this.constantPoolOffsets = null;
380 * Answer the size of the receiver in bytes.
384 public int sizeInBytes() {
385 return attributeBytes;
387 public void throwFormatException() throws ClassFormatException {
388 throw new ClassFormatException(ClassFormatException.ErrBadFieldInfo);
390 public String toString() {
391 StringBuffer buffer = new StringBuffer(this.getClass().getName());
392 int modifiers = getModifiers();
394 .append("{") //$NON-NLS-1$
396 ((modifiers & AccDeprecated) != 0 ? "deprecated " : "") //$NON-NLS-1$ //$NON-NLS-2$
397 + ((modifiers & 0x0001) == 1 ? "public " : "") //$NON-NLS-1$ //$NON-NLS-2$
398 + ((modifiers & 0x0002) == 0x0002 ? "private " : "") //$NON-NLS-1$ //$NON-NLS-2$
399 + ((modifiers & 0x0004) == 0x0004 ? "protected " : "") //$NON-NLS-1$ //$NON-NLS-2$
400 + ((modifiers & 0x0008) == 0x000008 ? "static " : "") //$NON-NLS-1$ //$NON-NLS-2$
401 + ((modifiers & 0x0010) == 0x0010 ? "final " : "") //$NON-NLS-1$ //$NON-NLS-2$
402 + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "") //$NON-NLS-1$ //$NON-NLS-2$
403 + ((modifiers & 0x0080) == 0x0080 ? "transient " : "")) //$NON-NLS-1$ //$NON-NLS-2$
404 .append(getTypeName())
405 .append(" ") //$NON-NLS-1$
407 .append(" ") //$NON-NLS-1$
408 .append(getConstant())
409 .append("}") //$NON-NLS-1$