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.IBinaryMethod;
17 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
18 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
20 public class MethodInfo extends ClassFileStruct implements IBinaryMethod, AttributeNamesConstants, Comparable {
21 static private final char[][] noException = CharOperation.NO_CHAR_CHAR;
22 private int accessFlags;
23 private int attributeBytes;
24 private int[] constantPoolOffsets;
25 private char[] descriptor;
26 private char[][] exceptionNames;
28 private char[] signature;
29 private int signatureUtf8Offset;
33 * @param classFileBytes byte[]
34 * @param offsets int[]
37 public MethodInfo (byte classFileBytes[], int offsets[], int offset) {
38 super(classFileBytes, offset);
39 constantPoolOffsets = offsets;
41 int attributesCount = u2At(6);
43 this.signatureUtf8Offset = -1;
44 for (int i = 0; i < attributesCount; i++) {
45 // check the name of each attribute
46 int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
47 char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
48 if (attributeName.length > 0) {
49 switch(attributeName[0]) {
51 if (CharOperation.equals(AttributeNamesConstants.SignatureName, attributeName)) {
52 this.signatureUtf8Offset = constantPoolOffsets[u2At(readOffset + 6)] - structOffset;
56 if (CharOperation.equals(attributeName, RuntimeVisibleAnnotationsName)) {
57 decodeStandardAnnotations(readOffset);
61 readOffset += (6 + u4At(readOffset + 2));
63 attributeBytes = readOffset;
65 public int compareTo(Object o) {
66 if (!(o instanceof MethodInfo)) {
67 throw new ClassCastException();
70 MethodInfo otherMethod = (MethodInfo) o;
71 int result = new String(this.getSelector()).compareTo(new String(otherMethod.getSelector()));
72 if (result != 0) return result;
73 return new String(this.getMethodDescriptor()).compareTo(new String(otherMethod.getMethodDescriptor()));
75 private int decodeAnnotation(int offset) {
76 int readOffset = offset;
77 int utf8Offset = this.constantPoolOffsets[u2At(offset)] - structOffset;
78 char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
79 typeName = Signature.toCharArray(typeName);
80 CharOperation.replace(typeName, '/', '.');
81 char[][] qualifiedTypeName = CharOperation.splitOn('.', typeName);
82 int numberOfPairs = u2At(offset + 2);
84 if (qualifiedTypeName.length == 3) {
85 char[] lastPart = qualifiedTypeName[2];
86 if (lastPart[0] == 'D') {
87 if (CharOperation.equals(qualifiedTypeName, TypeConstants.JAVA_LANG_DEPRECATED)) {
88 this.tagBits |= TagBits.AnnotationDeprecated;
93 for (int i = 0; i < numberOfPairs; i++) {
95 readOffset = decodeElementValue(readOffset);
99 private int decodeElementValue(int offset) {
100 int readOffset = offset;
101 int tag = u1At(readOffset);
122 readOffset += decodeAnnotation(readOffset);
125 int numberOfValues = u2At(readOffset);
127 for (int i = 0; i < numberOfValues; i++) {
128 readOffset = decodeElementValue(readOffset);
135 * @param offset the offset is located at the beginning of the runtime visible
136 * annotation attribute.
138 private void decodeStandardAnnotations(int offset) {
139 int numberOfAnnotations = u2At(offset + 6);
140 int readOffset = offset + 8;
141 for (int i = 0; i < numberOfAnnotations; i++) {
142 readOffset = decodeAnnotation(readOffset);
146 * @see org.eclipse.jdt.internal.compiler.env.IGenericMethod#getArgumentNames()
148 public char[][] getArgumentNames() {
152 * Answer the resolved names of the exception types in the
153 * class file format as specified in section 4.2 of the Java 2 VM spec
154 * or null if the array is empty.
156 * For example, java.lang.String is java/lang/String.
159 public char[][] getExceptionTypeNames() {
160 if (exceptionNames == null) {
161 readExceptionAttributes();
163 return exceptionNames;
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 the receiver's method descriptor which describes the parameter &
177 * return types as specified in section 4.3.3 of the Java 2 VM spec.
180 * - int foo(String) is (Ljava/lang/String;)I
181 * - void foo(Object[]) is (I)[Ljava/lang/Object;
184 public char[] getMethodDescriptor() {
185 if (descriptor == null) {
187 int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset;
188 descriptor = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
193 * Answer an int whose bits are set according the access constants
194 * defined by the VM spec.
195 * Set the AccDeprecated and AccSynthetic bits if necessary
198 public int getModifiers() {
199 if (this.accessFlags == -1) {
200 // compute the accessflag. Don't forget the deprecated attribute
201 this.accessFlags = u2At(0);
202 readModifierRelatedAttributes();
204 return this.accessFlags;
207 * Answer the name of the method.
209 * For a constructor, answer <init> & <clinit> for a clinit method.
212 public char[] getSelector() {
215 int utf8Offset = constantPoolOffsets[u2At(2)] - structOffset;
216 name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
220 public long getTagBits() {
224 * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos
225 * will be therefore fully initialized and we can get rid of the bytes.
230 getMethodDescriptor();
231 getExceptionTypeNames();
232 getGenericSignature();
236 * Answer true if the method is a class initializer, false otherwise.
239 public boolean isClinit() {
240 char[] selector = getSelector();
241 return selector[0] == '<' && selector.length == 8; // Can only match <clinit>
244 * Answer true if the method is a constructor, false otherwise.
247 public boolean isConstructor() {
248 char[] selector = getSelector();
249 return selector[0] == '<' && selector.length == 6; // Can only match <init>
252 * Return true if the field is a synthetic method, false otherwise.
255 public boolean isSynthetic() {
256 return (getModifiers() & AccSynthetic) != 0;
258 private void readExceptionAttributes() {
259 int attributesCount = u2At(6);
261 for (int i = 0; i < attributesCount; i++) {
262 int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
263 char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
264 if (CharOperation.equals(attributeName, ExceptionsName)) {
265 // read the number of exception entries
266 int entriesNumber = u2At(readOffset + 6);
267 // place the readOffset at the beginning of the exceptions table
269 if (entriesNumber == 0) {
270 exceptionNames = noException;
272 exceptionNames = new char[entriesNumber][];
273 for (int j = 0; j < entriesNumber; j++) {
275 constantPoolOffsets[u2At(
276 constantPoolOffsets[u2At(readOffset)] - structOffset + 1)]
278 exceptionNames[j] = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
283 readOffset += (6 + u4At(readOffset + 2));
286 if (exceptionNames == null) {
287 exceptionNames = noException;
290 private void readModifierRelatedAttributes() {
291 int attributesCount = u2At(6);
293 for (int i = 0; i < attributesCount; i++) {
294 int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
295 char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
296 // test added for obfuscated .class file. See 79772
297 if (attributeName.length != 0) {
298 switch(attributeName[0]) {
300 if (CharOperation.equals(attributeName, DeprecatedName))
301 this.accessFlags |= AccDeprecated;
304 if (CharOperation.equals(attributeName, SyntheticName))
305 this.accessFlags |= AccSynthetic;
308 if (CharOperation.equals(attributeName, AnnotationDefaultName))
309 this.accessFlags |= AccAnnotationDefault;
313 readOffset += (6 + u4At(readOffset + 2));
316 protected void reset() {
317 this.constantPoolOffsets = null;
321 * Answer the size of the receiver in bytes.
325 public int sizeInBytes() {
326 return attributeBytes;
328 public String toString() {
329 int modifiers = getModifiers();
330 char[] desc = getGenericSignature();
332 desc = getMethodDescriptor();
333 StringBuffer buffer = new StringBuffer(this.getClass().getName());
335 .append("{") //$NON-NLS-1$
337 ((modifiers & AccDeprecated) != 0 ? "deprecated " : "") //$NON-NLS-1$ //$NON-NLS-2$
338 + ((modifiers & 0x0001) == 1 ? "public " : "") //$NON-NLS-1$ //$NON-NLS-2$
339 + ((modifiers & 0x0002) == 0x0002 ? "private " : "") //$NON-NLS-1$ //$NON-NLS-2$
340 + ((modifiers & 0x0004) == 0x0004 ? "protected " : "") //$NON-NLS-1$ //$NON-NLS-2$
341 + ((modifiers & 0x0008) == 0x000008 ? "static " : "") //$NON-NLS-1$ //$NON-NLS-2$
342 + ((modifiers & 0x0010) == 0x0010 ? "final " : "") //$NON-NLS-1$ //$NON-NLS-2$
343 + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "") //$NON-NLS-1$ //$NON-NLS-2$
344 + ((modifiers & 0x0080) == 0x0080 ? "varargs " : "")) //$NON-NLS-1$ //$NON-NLS-2$
345 .append(getSelector())
347 .append("}") //$NON-NLS-1$