blob: ddf744c5aa32740e2746ca4565249cce83d221b3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.util;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.util.*;
import org.eclipse.jdt.core.util.ClassFormatException;
import org.eclipse.jdt.core.util.IClassFileAttribute;
import org.eclipse.jdt.core.util.IClassFileReader;
import org.eclipse.jdt.core.util.ICodeAttribute;
import org.eclipse.jdt.core.util.IConstantPoolConstant;
import org.eclipse.jdt.core.util.IConstantPoolEntry;
import org.eclipse.jdt.core.util.IConstantValueAttribute;
import org.eclipse.jdt.core.util.IExceptionAttribute;
import org.eclipse.jdt.core.util.IExceptionTableEntry;
import org.eclipse.jdt.core.util.IFieldInfo;
import org.eclipse.jdt.core.util.IInnerClassesAttribute;
import org.eclipse.jdt.core.util.IInnerClassesAttributeEntry;
import org.eclipse.jdt.core.util.ILineNumberAttribute;
import org.eclipse.jdt.core.util.ILocalVariableAttribute;
import org.eclipse.jdt.core.util.ILocalVariableTableEntry;
import org.eclipse.jdt.core.util.IMethodInfo;
import org.eclipse.jdt.core.util.IModifierConstants;
import org.eclipse.jdt.core.util.ISourceAttribute;
/**
* Disassembler of .class files. It generates an output in the Writer that looks close to
* the javap output.
*/
public class Disassembler extends ClassFileBytesDisassembler {
private static final char[] ANY_EXCEPTION = Messages.classfileformat_anyexceptionhandler.toCharArray();
private static final String EMPTY_OUTPUT = ""; //$NON-NLS-1$
private static final String VERSION_UNKNOWN = "unknown";//$NON-NLS-1$
private boolean appendModifier(StringBuffer buffer, int accessFlags, int modifierConstant, String modifier, boolean firstModifier) {
if ((accessFlags & modifierConstant) != 0) {
if (!firstModifier) {
buffer.append(Messages.disassembler_space);
}
if (firstModifier) {
firstModifier = false;
}
buffer.append(modifier);
}
return firstModifier;
}
private void decodeModifiersForField(StringBuffer buffer, int accessFlags) {
boolean firstModifier = true;
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_TRANSIENT, "transient", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_VOLATILE, "volatile", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ENUM, "enum", firstModifier); //$NON-NLS-1$
if (!firstModifier) {
buffer.append(Messages.disassembler_space);
}
}
private final void decodeModifiersForInnerClasses(StringBuffer buffer, int accessFlags) {
boolean firstModifier = true;
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
if (!firstModifier) {
buffer.append(Messages.disassembler_space);
}
}
private final void decodeModifiersForMethod(StringBuffer buffer, int accessFlags) {
boolean firstModifier = true;
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNCHRONIZED, "synchronized", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_NATIVE, "native", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STRICT, "strictfp", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_BRIDGE, "bridge", firstModifier); //$NON-NLS-1$
if (!firstModifier) {
buffer.append(Messages.disassembler_space);
}
}
private final void decodeModifiersForType(StringBuffer buffer, int accessFlags) {
boolean firstModifier = true;
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
if (!firstModifier) {
buffer.append(Messages.disassembler_space);
}
}
private String decodeStringValue(char[] chars) {
StringBuffer buffer = new StringBuffer();
for (int i = 0, max = chars.length; i < max; i++) {
char c = chars[i];
switch(c) {
case '\b' :
buffer.append("\\b"); //$NON-NLS-1$
break;
case '\t' :
buffer.append("\\t"); //$NON-NLS-1$
break;
case '\n' :
buffer.append("\\n"); //$NON-NLS-1$
break;
case '\f' :
buffer.append("\\f"); //$NON-NLS-1$
break;
case '\r' :
buffer.append("\\r"); //$NON-NLS-1$
break;
case '\"':
buffer.append("\\\""); //$NON-NLS-1$
break;
case '\'':
buffer.append("\\\'"); //$NON-NLS-1$
break;
case '\\':
buffer.append("\\\\"); //$NON-NLS-1$
break;
case '\0' :
buffer.append("\\0"); //$NON-NLS-1$
break;
case '\1' :
buffer.append("\\1"); //$NON-NLS-1$
break;
case '\2' :
buffer.append("\\2"); //$NON-NLS-1$
break;
case '\3' :
buffer.append("\\3"); //$NON-NLS-1$
break;
case '\4' :
buffer.append("\\4"); //$NON-NLS-1$
break;
case '\5' :
buffer.append("\\5"); //$NON-NLS-1$
break;
case '\6' :
buffer.append("\\6"); //$NON-NLS-1$
break;
case '\7' :
buffer.append("\\7"); //$NON-NLS-1$
break;
default:
buffer.append(c);
}
}
return buffer.toString();
}
private String decodeStringValue(String s) {
return decodeStringValue(s.toCharArray());
}
/**
* @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String)
*/
public String disassemble(byte[] classFileBytes, String lineSeparator) throws ClassFormatException {
return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, ClassFileBytesDisassembler.DEFAULT);
}
/**
* @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String, int)
*/
public String disassemble(byte[] classFileBytes, String lineSeparator, int mode) throws ClassFormatException {
return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, mode);
}
private void disassemble(IAnnotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
final int typeIndex = annotation.getTypeIndex();
final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.');
buffer.append(
Messages.bind(Messages.disassembler_annotationentrystart, new String[] {
Integer.toString(typeIndex),
new String(Signature.toCharArray(typeName))
}));
final IAnnotationComponent[] components = annotation.getComponents();
for (int i = 0, max = components.length; i < max; i++) {
disassemble(components[i], buffer, lineSeparator, tabNumber + 1);
}
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_annotationentryend);
}
private void disassemble(IAnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(
Messages.bind(Messages.disassembler_annotationcomponent,
new String[] {
Integer.toString(annotationComponent.getComponentNameIndex()),
new String(annotationComponent.getComponentName())
}));
disassemble(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1);
}
private void disassemble(IAnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber) {
switch(annotationComponentValue.getTag()) {
case IAnnotationComponentValue.BYTE_TAG:
case IAnnotationComponentValue.CHAR_TAG:
case IAnnotationComponentValue.DOUBLE_TAG:
case IAnnotationComponentValue.FLOAT_TAG:
case IAnnotationComponentValue.INTEGER_TAG:
case IAnnotationComponentValue.LONG_TAG:
case IAnnotationComponentValue.SHORT_TAG:
case IAnnotationComponentValue.BOOLEAN_TAG:
case IAnnotationComponentValue.STRING_TAG:
IConstantPoolEntry constantPoolEntry = annotationComponentValue.getConstantValue();
String value = null;
switch(constantPoolEntry.getKind()) {
case IConstantPoolConstant.CONSTANT_Long :
value = constantPoolEntry.getLongValue() + "L"; //$NON-NLS-1$
break;
case IConstantPoolConstant.CONSTANT_Float :
value = constantPoolEntry.getFloatValue() + "f"; //$NON-NLS-1$
break;
case IConstantPoolConstant.CONSTANT_Double :
value = Double.toString(constantPoolEntry.getDoubleValue());
break;
case IConstantPoolConstant.CONSTANT_Integer:
switch(annotationComponentValue.getTag()) {
case IAnnotationComponentValue.CHAR_TAG :
value = "'" + (char) constantPoolEntry.getIntegerValue() + "'"; //$NON-NLS-1$//$NON-NLS-2$
break;
case IAnnotationComponentValue.BOOLEAN_TAG :
value = constantPoolEntry.getIntegerValue() == 1 ? "true" : "false";//$NON-NLS-1$//$NON-NLS-2$
break;
case IAnnotationComponentValue.BYTE_TAG :
value = "(byte) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
break;
case IAnnotationComponentValue.SHORT_TAG :
value = "(short) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
break;
case IAnnotationComponentValue.INTEGER_TAG :
value = "(int) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
}
break;
case IConstantPoolConstant.CONSTANT_Utf8:
value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$
}
buffer.append(Messages.bind(Messages.disassembler_annotationdefaultvalue, value));
break;
case IAnnotationComponentValue.ENUM_TAG:
final int enumConstantTypeNameIndex = annotationComponentValue.getEnumConstantTypeNameIndex();
final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.');
final int enumConstantNameIndex = annotationComponentValue.getEnumConstantNameIndex();
final char[] constantName = annotationComponentValue.getEnumConstantName();
buffer.append(Messages.bind(Messages.disassembler_annotationenumvalue,
new String[] {
Integer.toString(enumConstantTypeNameIndex),
Integer.toString(enumConstantNameIndex),
new String(Signature.toCharArray(typeName)),
new String(constantName)
}));
break;
case IAnnotationComponentValue.CLASS_TAG:
final int classIndex = annotationComponentValue.getClassInfoIndex();
constantPoolEntry = annotationComponentValue.getClassInfo();
final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.');
buffer.append(Messages.bind(Messages.disassembler_annotationclassvalue,
new String[] {
Integer.toString(classIndex),
new String(Signature.toCharArray(className))
}));
break;
case IAnnotationComponentValue.ANNOTATION_TAG:
buffer.append(Messages.disassembler_annotationannotationvalue);
IAnnotation annotation = annotationComponentValue.getAnnotationValue();
disassemble(annotation, buffer, lineSeparator, tabNumber + 1);
break;
case IAnnotationComponentValue.ARRAY_TAG:
buffer.append(Messages.disassembler_annotationarrayvaluestart);
final IAnnotationComponentValue[] annotationComponentValues = annotationComponentValue.getAnnotationComponentValues();
for (int i = 0, max = annotationComponentValues.length; i < max; i++) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
disassemble(annotationComponentValues[i], buffer, lineSeparator, tabNumber + 1);
}
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_annotationarrayvalueend);
}
}
private void disassemble(IAnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_annotationdefaultheader);
IAnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue();
writeNewLine(buffer, lineSeparator, tabNumber + 2);
disassemble(componentValue, buffer, lineSeparator, tabNumber + 1);
}
private void disassemble(IClassFileAttribute classFileAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.bind(Messages.disassembler_genericattributeheader,
new String[] {
new String(classFileAttribute.getAttributeName()),
Long.toString(classFileAttribute.getAttributeLength())
}));
}
/**
* Disassemble a method info header
*/
private void disassemble(IClassFileReader classFileReader, IMethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber);
ICodeAttribute codeAttribute = methodInfo.getCodeAttribute();
char[] methodDescriptor = methodInfo.getDescriptor();
IClassFileAttribute classFileAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.SIGNATURE);
ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
IClassFileAttribute runtimeVisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
IClassFileAttribute runtimeInvisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
IClassFileAttribute annotationDefaultAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.ANNOTATION_DEFAULT);
if (checkMode(mode, SYSTEM | DETAILED)) {
buffer.append(Messages.bind(Messages.classfileformat_methoddescriptor,
new String[] {
Integer.toString(methodInfo.getDescriptorIndex()),
new String(methodDescriptor)
}));
if (methodInfo.isDeprecated()) {
buffer.append(Messages.disassembler_deprecated);
}
writeNewLine(buffer, lineSeparator, tabNumber);
if (signatureAttribute != null) {
buffer.append(Messages.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature())));
writeNewLine(buffer, lineSeparator, tabNumber);
}
if (codeAttribute != null) {
buffer.append(Messages.bind(Messages.classfileformat_stacksAndLocals,
new String[] {
Integer.toString(codeAttribute.getMaxStack()),
Integer.toString(codeAttribute.getMaxLocals())
}));
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
if (checkMode(mode, DETAILED)) {
// disassemble compact version of annotations
if (runtimeInvisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1);
writeNewLine(buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1);
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
int accessFlags = methodInfo.getAccessFlags();
decodeModifiersForMethod(buffer, accessFlags);
if (methodInfo.isSynthetic()) {
buffer.append("synthetic"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
}
CharOperation.replace(methodDescriptor, '/', '.');
char[] methodName;
if (methodInfo.isConstructor()) {
methodName = classFileReader.getClassName();
buffer.append(Signature.toCharArray(methodDescriptor, methodName, getParameterNames(methodDescriptor, codeAttribute, accessFlags) , false, false, (accessFlags & IModifierConstants.ACC_VARARGS) != 0));
} else if (methodInfo.isClinit()) {
buffer.append(Messages.bind(Messages.classfileformat_clinitname));
} else {
methodName = methodInfo.getName();
buffer.append(Signature.toCharArray(methodDescriptor, methodName, getParameterNames(methodDescriptor, codeAttribute, accessFlags) , false, true, (accessFlags & IModifierConstants.ACC_VARARGS) != 0));
}
IExceptionAttribute exceptionAttribute = methodInfo.getExceptionAttribute();
if (exceptionAttribute != null) {
buffer.append(" throws "); //$NON-NLS-1$
char[][] exceptionNames = exceptionAttribute.getExceptionNames();
int length = exceptionNames.length;
for (int i = 0; i < length - 1; i++) {
char[] exceptionName = exceptionNames[i];
CharOperation.replace(exceptionName, '/', '.');
buffer
.append(exceptionName)
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space);
}
char[] exceptionName = exceptionNames[length - 1];
CharOperation.replace(exceptionName, '/', '.');
buffer.append(exceptionName);
}
if (checkMode(mode, DETAILED)) {
if (annotationDefaultAttribute != null) {
buffer.append(" default "); //$NON-NLS-1$
disassembleAsModifier((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber);
}
}
buffer.append(Messages.disassembler_endofmethodheader);
if (checkMode(mode, SYSTEM | DETAILED)) {
if (codeAttribute != null) {
disassemble(codeAttribute, buffer, lineSeparator, tabNumber, mode);
}
}
if (checkMode(mode, SYSTEM)) {
IClassFileAttribute[] attributes = methodInfo.getAttributes();
int length = attributes.length;
if (length != 0) {
for (int i = 0; i < length; i++) {
IClassFileAttribute attribute = attributes[i];
if (attribute != codeAttribute
&& attribute != exceptionAttribute
&& attribute != signatureAttribute
&& attribute != annotationDefaultAttribute
&& attribute != runtimeInvisibleAnnotationsAttribute
&& attribute != runtimeVisibleAnnotationsAttribute
&& attribute != runtimeInvisibleParameterAnnotationsAttribute
&& attribute != runtimeVisibleParameterAnnotationsAttribute
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
disassemble(attribute, buffer, lineSeparator, tabNumber);
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
}
if (annotationDefaultAttribute != null) {
disassemble((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber);
}
if (runtimeInvisibleAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleParameterAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber);
}
if (runtimeInvisibleParameterAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber);
}
}
}
/**
* @see #disassemble(org.eclipse.jdt.core.util.IClassFileReader, java.lang.String, int)
*/
public String disassemble(IClassFileReader classFileReader, String lineSeparator) {
return disassemble(classFileReader, lineSeparator, ClassFileBytesDisassembler.DEFAULT);
}
/**
* Answers back the disassembled string of the IClassFileReader according to the
* mode.
* This is an output quite similar to the javap tool.
*
* @param classFileReader The classFileReader to be disassembled
* @param lineSeparator the line separator to use.
* @param mode the mode used to disassemble the IClassFileReader
*
* @return the disassembled string of the IClassFileReader according to the mode
*/
public String disassemble(IClassFileReader classFileReader, String lineSeparator, int mode) {
if (classFileReader == null) return EMPTY_OUTPUT;
StringBuffer buffer = new StringBuffer();
ISourceAttribute sourceAttribute = classFileReader.getSourceFileAttribute();
IClassFileAttribute classFileAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.SIGNATURE);
ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
final int accessFlags = classFileReader.getAccessFlags();
if (checkMode(mode, SYSTEM | DETAILED)) {
int minorVersion = classFileReader.getMinorVersion();
int majorVersion = classFileReader.getMajorVersion();
buffer.append(Messages.disassembler_begincommentline);
if (sourceAttribute != null) {
buffer.append(Messages.disassembler_sourceattributeheader);
buffer.append(sourceAttribute.getSourceFileName());
}
String versionNumber = VERSION_UNKNOWN;//$NON-NLS-1$
if (minorVersion == 3 && majorVersion == 45) {
versionNumber = JavaCore.VERSION_1_1;
} else if (minorVersion == 0 && majorVersion == 46) {
versionNumber = JavaCore.VERSION_1_2;
} else if (minorVersion == 0 && majorVersion == 47) {
versionNumber = JavaCore.VERSION_1_3;
} else if (minorVersion == 0 && majorVersion == 48) {
versionNumber = JavaCore.VERSION_1_4;
} else if (minorVersion == 0 && majorVersion == 49) {
versionNumber = JavaCore.VERSION_1_5;
}
buffer.append(
Messages.bind(Messages.classfileformat_versiondetails,
new String[] {
versionNumber,
Integer.toString(majorVersion),
Integer.toString(minorVersion),
((accessFlags & IModifierConstants.ACC_SUPER) != 0
? Messages.classfileformat_superflagisset
: Messages.classfileformat_superflagisnotset)
+ (isDeprecated(classFileReader) ? ", deprecated" : EMPTY_OUTPUT)//$NON-NLS-1$
}));
writeNewLine(buffer, lineSeparator, 0);
if (signatureAttribute != null) {
buffer.append(Messages.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature())));
writeNewLine(buffer, lineSeparator, 0);
}
}
char[] className = classFileReader.getClassName();
if (className == null) {
// incomplete initialization. We cannot go further.
return buffer.toString();
}
IInnerClassesAttribute innerClassesAttribute = classFileReader.getInnerClassesAttribute();
IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
if (checkMode(mode, DETAILED)) {
// disassemble compact version of annotations
if (runtimeInvisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 1);
writeNewLine(buffer, lineSeparator, 0);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 1);
writeNewLine(buffer, lineSeparator, 0);
}
}
boolean decoded = false;
if (innerClassesAttribute != null) {
// search the right entry
IInnerClassesAttributeEntry[] entries = innerClassesAttribute.getInnerClassAttributesEntries();
for (int i = 0, max = entries.length; i < max ; i++) {
IInnerClassesAttributeEntry entry = entries[i];
char[] innerClassName = entry.getInnerClassName();
if (innerClassName != null) {
if (CharOperation.equals(classFileReader.getClassName(), innerClassName)) {
decodeModifiersForInnerClasses(buffer, entry.getAccessFlags());
decoded = true;
}
}
}
}
if (!decoded) {
decodeModifiersForType(buffer, accessFlags);
if (isSynthetic(classFileReader)) {
buffer.append("synthetic"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
}
}
if ((accessFlags & IModifierConstants.ACC_ENUM) != 0) {
buffer.append("enum "); //$NON-NLS-1$
} else if (classFileReader.isClass()) {
buffer.append("class "); //$NON-NLS-1$
} else {
if ((accessFlags & IModifierConstants.ACC_ANNOTATION) != 0) {
buffer.append("@"); //$NON-NLS-1$
}
buffer.append("interface "); //$NON-NLS-1$
}
CharOperation.replace(className, '/', '.');
buffer.append(className);
char[] superclassName = classFileReader.getSuperclassName();
if (superclassName != null) {
buffer.append(" extends "); //$NON-NLS-1$
CharOperation.replace(superclassName, '/', '.');
buffer.append(superclassName);
}
char[][] superclassInterfaces = classFileReader.getInterfaceNames();
int length = superclassInterfaces.length;
if (length != 0) {
buffer.append(" implements "); //$NON-NLS-1$
for (int i = 0; i < length - 1; i++) {
char[] superinterface = superclassInterfaces[i];
CharOperation.replace(superinterface, '/', '.');
buffer
.append(superinterface)
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space);
}
char[] superinterface = superclassInterfaces[length - 1];
CharOperation.replace(superinterface, '/', '.');
buffer.append(superinterface);
}
buffer.append(Messages.bind(Messages.disassembler_opentypedeclaration));
if (checkMode(mode, SYSTEM)) {
disassemble(classFileReader.getConstantPool(), buffer, lineSeparator, 1);
}
disassembleTypeMembers(classFileReader, buffer, lineSeparator, 1, mode);
if (checkMode(mode, SYSTEM | DETAILED)) {
IClassFileAttribute[] attributes = classFileReader.getAttributes();
length = attributes.length;
IEnclosingMethodAttribute enclosingMethodAttribute = getEnclosingMethodAttribute(classFileReader);
int remainingAttributesLength = length;
if (innerClassesAttribute != null) {
remainingAttributesLength--;
}
if (enclosingMethodAttribute != null) {
remainingAttributesLength--;
}
if (sourceAttribute != null) {
remainingAttributesLength--;
}
if (signatureAttribute != null) {
remainingAttributesLength--;
}
if (innerClassesAttribute != null || enclosingMethodAttribute != null || remainingAttributesLength != 0) {
writeNewLine(buffer, lineSeparator, 0);
}
if (innerClassesAttribute != null) {
disassemble(innerClassesAttribute, buffer, lineSeparator, 1);
}
if (enclosingMethodAttribute != null) {
disassemble(enclosingMethodAttribute, buffer, lineSeparator, 0);
}
if (checkMode(mode, SYSTEM)) {
if (runtimeVisibleAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0);
}
if (runtimeInvisibleAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0);
}
if (length != 0) {
for (int i = 0; i < length; i++) {
IClassFileAttribute attribute = attributes[i];
if (attribute != innerClassesAttribute
&& attribute != sourceAttribute
&& attribute != signatureAttribute
&& attribute != enclosingMethodAttribute
&& attribute != runtimeInvisibleAnnotationsAttribute
&& attribute != runtimeVisibleAnnotationsAttribute
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
disassemble(attribute, buffer, lineSeparator, 0);
}
}
}
}
}
writeNewLine(buffer, lineSeparator, 0);
buffer.append(Messages.disassembler_closetypedeclaration);
return buffer.toString();
}
private void disassemble(ICodeAttribute codeAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber - 1);
DefaultBytecodeVisitor visitor = new DefaultBytecodeVisitor(codeAttribute, buffer, lineSeparator, tabNumber, mode);
try {
codeAttribute.traverse(visitor);
} catch(ClassFormatException e) {
dumpTab(tabNumber + 2, buffer);
buffer.append(Messages.classformat_classformatexception);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
}
int exceptionTableLength = codeAttribute.getExceptionTableLength();
if (exceptionTableLength != 0) {
final int tabNumberForExceptionAttribute = tabNumber + 2;
dumpTab(tabNumberForExceptionAttribute, buffer);
IExceptionTableEntry[] exceptionTableEntries = codeAttribute.getExceptionTable();
buffer.append(Messages.disassembler_exceptiontableheader);
writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
for (int i = 0; i < exceptionTableLength - 1; i++) {
IExceptionTableEntry exceptionTableEntry = exceptionTableEntries[i];
char[] catchType;
if (exceptionTableEntry.getCatchTypeIndex() != 0) {
catchType = exceptionTableEntry.getCatchType();
CharOperation.replace(catchType, '/', '.');
} else {
catchType = ANY_EXCEPTION;
}
buffer.append(Messages.bind(Messages.classfileformat_exceptiontableentry,
new String[] {
Integer.toString(exceptionTableEntry.getStartPC()),
Integer.toString(exceptionTableEntry.getEndPC()),
Integer.toString(exceptionTableEntry.getHandlerPC()),
new String(catchType)
}));
writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
}
IExceptionTableEntry exceptionTableEntry = exceptionTableEntries[exceptionTableLength - 1];
char[] catchType;
if (exceptionTableEntry.getCatchTypeIndex() != 0) {
catchType = exceptionTableEntry.getCatchType();
CharOperation.replace(catchType, '/', '.');
} else {
catchType = ANY_EXCEPTION;
}
buffer.append(Messages.bind(Messages.classfileformat_exceptiontableentry,
new String[] {
Integer.toString(exceptionTableEntry.getStartPC()),
Integer.toString(exceptionTableEntry.getEndPC()),
Integer.toString(exceptionTableEntry.getHandlerPC()),
new String(catchType)
}));
writeNewLine(buffer, lineSeparator, 0);
}
ILineNumberAttribute lineNumberAttribute = codeAttribute.getLineNumberAttribute();
int lineAttributeLength = lineNumberAttribute == null ? 0 : lineNumberAttribute.getLineNumberTableLength();
if (lineAttributeLength != 0) {
int tabNumberForLineAttribute = tabNumber + 2;
dumpTab(tabNumberForLineAttribute, buffer);
buffer.append(Messages.disassembler_linenumberattributeheader);
writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
int[][] lineattributesEntries = lineNumberAttribute.getLineNumberTable();
for (int i = 0; i < lineAttributeLength - 1; i++) {
buffer.append(Messages.bind(Messages.classfileformat_linenumbertableentry,
new String[] {
Integer.toString(lineattributesEntries[i][0]),
Integer.toString(lineattributesEntries[i][1])
}));
writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
}
buffer.append(Messages.bind(Messages.classfileformat_linenumbertableentry,
new String[] {
Integer.toString(lineattributesEntries[lineAttributeLength - 1][0]),
Integer.toString(lineattributesEntries[lineAttributeLength - 1][1])
}));
}
ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute();
int localVariableAttributeLength = localVariableAttribute == null ? 0 : localVariableAttribute.getLocalVariableTableLength();
if (localVariableAttributeLength != 0) {
int tabNumberForLocalVariableAttribute = tabNumber + 2;
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
buffer.append(Messages.disassembler_localvariabletableattributeheader);
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
ILocalVariableTableEntry[] localVariableTableEntries = localVariableAttribute.getLocalVariableTable();
for (int i = 0; i < localVariableAttributeLength - 1; i++) {
ILocalVariableTableEntry localVariableTableEntry = localVariableTableEntries[i];
int index= localVariableTableEntry.getIndex();
int startPC = localVariableTableEntry.getStartPC();
int length = localVariableTableEntry.getLength();
buffer.append(Messages.bind(Messages.classfileformat_localvariabletableentry,
new String[] {
Integer.toString(startPC),
Integer.toString(startPC + length),
new String(localVariableTableEntry.getName()),
Integer.toString(index),
new String(localVariableTableEntry.getDescriptor())
}));
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
}
ILocalVariableTableEntry localVariableTableEntry = localVariableTableEntries[localVariableAttributeLength - 1];
int index= localVariableTableEntry.getIndex();
int startPC = localVariableTableEntry.getStartPC();
int length = localVariableTableEntry.getLength();
buffer.append(Messages.bind(Messages.classfileformat_localvariabletableentry,
new String[] {
Integer.toString(startPC),
Integer.toString(startPC + length),
new String(localVariableTableEntry.getName()),
Integer.toString(index),
new String(localVariableTableEntry.getDescriptor())
}));
}
ILocalVariableTypeTableAttribute localVariableTypeAttribute= getLocalVariableTypeAttribute(codeAttribute);
int localVariableTypeTableLength = localVariableTypeAttribute == null ? 0 : localVariableTypeAttribute.getLocalVariableTypeTableLength();
if (localVariableTypeTableLength != 0) {
int tabNumberForLocalVariableAttribute = tabNumber + 2;
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
buffer.append(Messages.disassembler_localvariabletypetableattributeheader);
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
ILocalVariableTypeTableEntry[] localVariableTypeTableEntries = localVariableTypeAttribute.getLocalVariableTypeTable();
for (int i = 0; i < localVariableTypeTableLength - 1; i++) {
ILocalVariableTypeTableEntry localVariableTypeTableEntry = localVariableTypeTableEntries[i];
int index= localVariableTypeTableEntry.getIndex();
int startPC = localVariableTypeTableEntry.getStartPC();
int length = localVariableTypeTableEntry.getLength();
buffer.append(Messages.bind(Messages.classfileformat_localvariabletableentry,
new String[] {
Integer.toString(startPC),
Integer.toString(startPC + length),
new String(localVariableTypeTableEntry.getName()),
Integer.toString(index),
new String(localVariableTypeTableEntry.getSignature())
}));
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
}
ILocalVariableTypeTableEntry localVariableTypeTableEntry = localVariableTypeTableEntries[localVariableTypeTableLength - 1];
int index= localVariableTypeTableEntry.getIndex();
int startPC = localVariableTypeTableEntry.getStartPC();
int length = localVariableTypeTableEntry.getLength();
buffer.append(Messages.bind(Messages.classfileformat_localvariabletableentry,
new String[] {
Integer.toString(startPC),
Integer.toString(startPC + length),
new String(localVariableTypeTableEntry.getName()),
Integer.toString(index),
new String(localVariableTypeTableEntry.getSignature())
}));
}
}
private void disassemble(IConstantPool constantPool, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber);
int length = constantPool.getConstantPoolCount();
buffer.append(Messages.disassembler_constantpoolheader);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
for (int i = 1; i < length; i++) {
IConstantPoolEntry constantPoolEntry = constantPool.decodeEntry(i);
switch (constantPool.getEntryKind(i)) {
case IConstantPoolConstant.CONSTANT_Class :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_class,
new String[] {
Integer.toString(i),
Integer.toString(constantPoolEntry.getClassInfoNameIndex()),
new String(constantPoolEntry.getClassInfoName())}));
break;
case IConstantPoolConstant.CONSTANT_Double :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_double,
new String[] {
Integer.toString(i),
Double.toString(constantPoolEntry.getDoubleValue())}));
break;
case IConstantPoolConstant.CONSTANT_Fieldref :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_fieldref,
new String[] {
Integer.toString(i),
Integer.toString(constantPoolEntry.getClassIndex()),
Integer.toString(constantPoolEntry.getNameAndTypeIndex()),
new String(constantPoolEntry.getClassName()),
new String(constantPoolEntry.getFieldName()),
new String(constantPoolEntry.getFieldDescriptor())}));
break;
case IConstantPoolConstant.CONSTANT_Float :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_float,
new String[] {
Integer.toString(i),
Float.toString(constantPoolEntry.getFloatValue())}));
break;
case IConstantPoolConstant.CONSTANT_Integer :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_integer,
new String[] {
Integer.toString(i),
Integer.toString(constantPoolEntry.getIntegerValue())}));
break;
case IConstantPoolConstant.CONSTANT_InterfaceMethodref :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_interfacemethodref,
new String[] {
Integer.toString(i),
Integer.toString(constantPoolEntry.getClassIndex()),
Integer.toString(constantPoolEntry.getNameAndTypeIndex()),
new String(constantPoolEntry.getClassName()),
new String(constantPoolEntry.getMethodName()),
new String(constantPoolEntry.getMethodDescriptor())}));
break;
case IConstantPoolConstant.CONSTANT_Long :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_long,
new String[] {
Integer.toString(i),
Long.toString(constantPoolEntry.getLongValue())}));
break;
case IConstantPoolConstant.CONSTANT_Methodref :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_methodref,
new String[] {
Integer.toString(i),
Integer.toString(constantPoolEntry.getClassIndex()),
Integer.toString(constantPoolEntry.getNameAndTypeIndex()),
new String(constantPoolEntry.getClassName()),
new String(constantPoolEntry.getMethodName()),
new String(constantPoolEntry.getMethodDescriptor())}));
break;
case IConstantPoolConstant.CONSTANT_NameAndType :
int nameIndex = constantPoolEntry.getNameAndTypeInfoNameIndex();
int typeIndex = constantPoolEntry.getNameAndTypeInfoDescriptorIndex();
IConstantPoolEntry entry = constantPool.decodeEntry(nameIndex);
char[] nameValue = entry.getUtf8Value();
entry = constantPool.decodeEntry(typeIndex);
char[] typeValue = entry.getUtf8Value();
buffer.append(
Messages.bind(Messages.disassembler_constantpool_name_and_type,
new String[] {
Integer.toString(i),
Integer.toString(nameIndex),
Integer.toString(typeIndex),
String.valueOf(nameValue),
String.valueOf(typeValue)}));
break;
case IConstantPoolConstant.CONSTANT_String :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_string,
new String[] {
Integer.toString(i),
Integer.toString(constantPoolEntry.getStringIndex()),
constantPoolEntry.getStringValue()}));
break;
case IConstantPoolConstant.CONSTANT_Utf8 :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_utf8,
new String[] {
Integer.toString(i),
new String(constantPoolEntry.getUtf8Value())}));
break;
}
if (i < length - 1) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
}
}
}
private void disassemble(IEnclosingMethodAttribute enclosingMethodAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_enclosingmethodheader);
buffer
.append(Messages.disassembler_constantpoolindex)
.append(enclosingMethodAttribute.getEnclosingClassIndex())
.append(" ")//$NON-NLS-1$
.append(Messages.disassembler_constantpoolindex)
.append(enclosingMethodAttribute.getMethodNameAndTypeIndex())
.append(" ")//$NON-NLS-1$
.append(enclosingMethodAttribute.getEnclosingClass()); //$NON-NLS-1$
if (enclosingMethodAttribute.getMethodNameAndTypeIndex() != 0) {
buffer
.append(".")//$NON-NLS-1$
.append(enclosingMethodAttribute.getMethodName()) //$NON-NLS-1$
.append(enclosingMethodAttribute.getMethodDescriptor()); //$NON-NLS-1$
}
}
/**
* Disassemble a field info
*/
private void disassemble(IFieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber);
char[] fieldDescriptor = fieldInfo.getDescriptor();
IClassFileAttribute classFileAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.SIGNATURE);
ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
if (checkMode(mode, SYSTEM | DETAILED)) {
buffer.append(Messages.bind(Messages.classfileformat_fieldddescriptor,
new String[] {
Integer.toString(fieldInfo.getDescriptorIndex()),
new String(fieldDescriptor)
}));
if (fieldInfo.isDeprecated()) {
buffer.append(Messages.disassembler_deprecated);
}
writeNewLine(buffer, lineSeparator, tabNumber);
if (signatureAttribute != null) {
buffer.append(Messages.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature())));
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
if (checkMode(mode, DETAILED)) {
// disassemble compact version of annotations
if (runtimeInvisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1);
writeNewLine(buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1);
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
decodeModifiersForField(buffer, fieldInfo.getAccessFlags());
if (fieldInfo.isSynthetic()) {
buffer.append("synthetic"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
}
buffer.append(getSignatureForField(fieldDescriptor));
buffer.append(' ');
buffer.append(new String(fieldInfo.getName()));
IConstantValueAttribute constantValueAttribute = fieldInfo.getConstantValueAttribute();
if (constantValueAttribute != null) {
buffer.append(Messages.disassembler_fieldhasconstant);
IConstantPoolEntry constantPoolEntry = constantValueAttribute.getConstantValue();
switch(constantPoolEntry.getKind()) {
case IConstantPoolConstant.CONSTANT_Long :
buffer.append(constantPoolEntry.getLongValue() + "L"); //$NON-NLS-1$
break;
case IConstantPoolConstant.CONSTANT_Float :
buffer.append(constantPoolEntry.getFloatValue() + "f"); //$NON-NLS-1$
break;
case IConstantPoolConstant.CONSTANT_Double :
buffer.append(constantPoolEntry.getDoubleValue());
break;
case IConstantPoolConstant.CONSTANT_Integer:
switch(fieldDescriptor[0]) {
case 'C' :
buffer.append("'" + (char) constantPoolEntry.getIntegerValue() + "'"); //$NON-NLS-1$//$NON-NLS-2$
break;
case 'Z' :
buffer.append(constantPoolEntry.getIntegerValue() == 1 ? "true" : "false");//$NON-NLS-1$//$NON-NLS-2$
break;
case 'B' :
buffer.append(constantPoolEntry.getIntegerValue());
break;
case 'S' :
buffer.append(constantPoolEntry.getIntegerValue());
break;
case 'I' :
buffer.append(constantPoolEntry.getIntegerValue());
}
break;
case IConstantPoolConstant.CONSTANT_String:
buffer.append("\"" + decodeStringValue(constantPoolEntry.getStringValue()) + "\"" );//$NON-NLS-1$//$NON-NLS-2$
}
}
buffer.append(Messages.disassembler_endoffieldheader);
if (checkMode(mode, SYSTEM)) {
IClassFileAttribute[] attributes = fieldInfo.getAttributes();
int length = attributes.length;
if (length != 0) {
for (int i = 0; i < length; i++) {
IClassFileAttribute attribute = attributes[i];
if (attribute != constantValueAttribute
&& attribute != signatureAttribute
&& attribute != runtimeInvisibleAnnotationsAttribute
&& attribute != runtimeVisibleAnnotationsAttribute
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
disassemble(attribute, buffer, lineSeparator, tabNumber);
}
}
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber);
}
if (runtimeInvisibleAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber);
}
}
}
private void disassemble(IInnerClassesAttribute innerClassesAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber);
buffer.append(Messages.disassembler_innerattributesheader);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
IInnerClassesAttributeEntry[] innerClassesAttributeEntries = innerClassesAttribute.getInnerClassAttributesEntries();
int length = innerClassesAttributeEntries.length;
int innerClassNameIndex, outerClassNameIndex, innerNameIndex, accessFlags;
IInnerClassesAttributeEntry innerClassesAttributeEntry;
for (int i = 0; i < length - 1; i++) {
innerClassesAttributeEntry = innerClassesAttributeEntries[i];
innerClassNameIndex = innerClassesAttributeEntry.getInnerClassNameIndex();
outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex();
innerNameIndex = innerClassesAttributeEntry.getInnerNameIndex();
accessFlags = innerClassesAttributeEntry.getAccessFlags();
buffer
.append(Messages.disassembler_openinnerclassentry)
.append(Messages.disassembler_inner_class_info_name)
.append(Messages.disassembler_constantpoolindex)
.append(innerClassNameIndex);
if (innerClassNameIndex != 0) {
buffer
.append(Messages.disassembler_space)
.append(innerClassesAttributeEntry.getInnerClassName());
}
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space)
.append(Messages.disassembler_outer_class_info_name)
.append(Messages.disassembler_constantpoolindex)
.append(outerClassNameIndex);
if (outerClassNameIndex != 0) {
buffer
.append(Messages.disassembler_space)
.append(innerClassesAttributeEntry.getOuterClassName());
}
writeNewLine(buffer, lineSeparator, tabNumber);
dumpTab(tabNumber, buffer);
buffer.append(Messages.disassembler_space);
buffer
.append(Messages.disassembler_inner_name)
.append(Messages.disassembler_constantpoolindex)
.append(innerNameIndex);
if (innerNameIndex != 0) {
buffer
.append(Messages.disassembler_space)
.append(innerClassesAttributeEntry.getInnerName());
}
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space)
.append(Messages.disassembler_inner_accessflags)
.append(accessFlags)
.append(Messages.disassembler_space);
decodeModifiersForInnerClasses(buffer, accessFlags);
buffer
.append(Messages.disassembler_closeinnerclassentry)
.append(Messages.disassembler_comma);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
}
// last entry
innerClassesAttributeEntry = innerClassesAttributeEntries[length - 1];
innerClassNameIndex = innerClassesAttributeEntry.getInnerClassNameIndex();
outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex();
innerNameIndex = innerClassesAttributeEntry.getInnerNameIndex();
accessFlags = innerClassesAttributeEntry.getAccessFlags();
buffer
.append(Messages.disassembler_openinnerclassentry)
.append(Messages.disassembler_inner_class_info_name)
.append(Messages.disassembler_constantpoolindex)
.append(innerClassNameIndex);
if (innerClassNameIndex != 0) {
buffer
.append(Messages.disassembler_space)
.append(innerClassesAttributeEntry.getInnerClassName());
}
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space)
.append(Messages.disassembler_outer_class_info_name)
.append(Messages.disassembler_constantpoolindex)
.append(outerClassNameIndex);
if (outerClassNameIndex != 0) {
buffer
.append(Messages.disassembler_space)
.append(innerClassesAttributeEntry.getOuterClassName());
}
writeNewLine(buffer, lineSeparator, tabNumber);
dumpTab(tabNumber, buffer);
buffer.append(Messages.disassembler_space);
buffer
.append(Messages.disassembler_inner_name)
.append(Messages.disassembler_constantpoolindex)
.append(innerNameIndex);
if (innerNameIndex != 0) {
buffer
.append(Messages.disassembler_space)
.append(innerClassesAttributeEntry.getInnerName());
}
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space)
.append(Messages.disassembler_inner_accessflags)
.append(accessFlags)
.append(Messages.disassembler_space);
decodeModifiersForInnerClasses(buffer, accessFlags);
buffer.append(Messages.disassembler_closeinnerclassentry);
}
private void disassemble(int index, IParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber) {
IAnnotation[] annotations = parameterAnnotation.getAnnotations();
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(
Messages.bind(Messages.disassembler_parameterannotationentrystart, new String[] {Integer.toString(index), Integer.toString(annotations.length)}));
for (int i = 0, max = annotations.length; i < max; i++) {
disassemble(annotations[i], buffer, lineSeparator, tabNumber + 1);
}
}
private void disassemble(IRuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_runtimeinvisibleannotationsattributeheader);
IAnnotation[] annotations = runtimeInvisibleAnnotationsAttribute.getAnnotations();
for (int i = 0, max = annotations.length; i < max; i++) {
disassemble(annotations[i], buffer, lineSeparator, tabNumber + 1);
}
}
private void disassemble(IRuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_runtimeinvisibleparameterannotationsattributeheader);
IParameterAnnotation[] parameterAnnotations = runtimeInvisibleParameterAnnotationsAttribute.getParameterAnnotations();
for (int i = 0, max = parameterAnnotations.length; i < max; i++) {
disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1);
}
}
private void disassemble(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_runtimevisibleannotationsattributeheader);
IAnnotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations();
for (int i = 0, max = annotations.length; i < max; i++) {
disassemble(annotations[i], buffer, lineSeparator, tabNumber + 1);
}
}
private void disassemble(IRuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_runtimevisibleparameterannotationsattributeheader);
IParameterAnnotation[] parameterAnnotations = runtimeVisibleParameterAnnotationsAttribute.getParameterAnnotations();
for (int i = 0, max = parameterAnnotations.length; i < max; i++) {
disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1);
}
}
private void disassembleAsModifier(IAnnotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber) {
final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.');
buffer.append('@').append(Signature.toCharArray(typeName)).append('(');
final IAnnotationComponent[] components = annotation.getComponents();
for (int i = 0, max = components.length; i < max; i++) {
if (i > 0) {
buffer.append(',');
writeNewLine(buffer, lineSeparator, tabNumber);
}
disassembleAsModifier(components[i], buffer, lineSeparator, tabNumber + 1);
}
buffer.append(')');
}
private void disassembleAsModifier(IAnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber) {
buffer.append(annotationComponent.getComponentName()).append('=');
disassembleAsModifier(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1);
}
private void disassembleAsModifier(IAnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber) {
switch(annotationComponentValue.getTag()) {
case IAnnotationComponentValue.BYTE_TAG:
case IAnnotationComponentValue.CHAR_TAG:
case IAnnotationComponentValue.DOUBLE_TAG:
case IAnnotationComponentValue.FLOAT_TAG:
case IAnnotationComponentValue.INTEGER_TAG:
case IAnnotationComponentValue.LONG_TAG:
case IAnnotationComponentValue.SHORT_TAG:
case IAnnotationComponentValue.BOOLEAN_TAG:
case IAnnotationComponentValue.STRING_TAG:
IConstantPoolEntry constantPoolEntry = annotationComponentValue.getConstantValue();
String value = null;
switch(constantPoolEntry.getKind()) {
case IConstantPoolConstant.CONSTANT_Long :
value = constantPoolEntry.getLongValue() + "L"; //$NON-NLS-1$
break;
case IConstantPoolConstant.CONSTANT_Float :
value = constantPoolEntry.getFloatValue() + "f"; //$NON-NLS-1$
break;
case IConstantPoolConstant.CONSTANT_Double :
value = Double.toString(constantPoolEntry.getDoubleValue());
break;
case IConstantPoolConstant.CONSTANT_Integer:
switch(annotationComponentValue.getTag()) {
case IAnnotationComponentValue.CHAR_TAG :
value = "'" + (char) constantPoolEntry.getIntegerValue() + "'"; //$NON-NLS-1$//$NON-NLS-2$
break;
case IAnnotationComponentValue.BOOLEAN_TAG :
value = constantPoolEntry.getIntegerValue() == 1 ? "true" : "false";//$NON-NLS-1$//$NON-NLS-2$
break;
case IAnnotationComponentValue.BYTE_TAG :
value = "(byte) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
break;
case IAnnotationComponentValue.SHORT_TAG :
value = "(short) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
break;
case IAnnotationComponentValue.INTEGER_TAG :
value = "(int) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
}
break;
case IConstantPoolConstant.CONSTANT_Utf8:
value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$
}
buffer.append(value); //$NON-NLS-1$
break;
case IAnnotationComponentValue.ENUM_TAG:
final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.');
final char[] constantName = annotationComponentValue.getEnumConstantName();
buffer.append(Signature.toCharArray(typeName)).append('.').append(constantName);
break;
case IAnnotationComponentValue.CLASS_TAG:
constantPoolEntry = annotationComponentValue.getClassInfo();
final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.');
buffer.append(Signature.toCharArray(className));
break;
case IAnnotationComponentValue.ANNOTATION_TAG:
IAnnotation annotation = annotationComponentValue.getAnnotationValue();
disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1);
break;
case IAnnotationComponentValue.ARRAY_TAG:
final IAnnotationComponentValue[] annotationComponentValues = annotationComponentValue.getAnnotationComponentValues();
buffer.append('{');
for (int i = 0, max = annotationComponentValues.length; i < max; i++) {
if (i > 0) {
buffer.append(',');
}
disassembleAsModifier(annotationComponentValues[i], buffer, lineSeparator, tabNumber + 1);
}
buffer.append('}');
}
}
private void disassembleAsModifier(IAnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
IAnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue();
disassembleAsModifier(componentValue, buffer, lineSeparator, tabNumber + 1);
}
private void disassembleAsModifier(IRuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
IAnnotation[] annotations = runtimeInvisibleAnnotationsAttribute.getAnnotations();
for (int i = 0, max = annotations.length; i < max; i++) {
disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1);
}
}
private void disassembleAsModifier(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
IAnnotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations();
for (int i = 0, max = annotations.length; i < max; i++) {
disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1);
}
}
private void disassembleTypeMembers(IClassFileReader classFileReader, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
IFieldInfo[] fields = classFileReader.getFieldInfos();
for (int i = 0, max = fields.length; i < max; i++) {
writeNewLine(buffer, lineSeparator, tabNumber);
disassemble(fields[i], buffer, lineSeparator, tabNumber, mode);
}
IMethodInfo[] methods = classFileReader.getMethodInfos();
for (int i = 0, max = methods.length; i < max; i++) {
writeNewLine(buffer, lineSeparator, tabNumber);
disassemble(classFileReader, methods[i], buffer, lineSeparator, tabNumber, mode);
}
}
private final void dumpTab(int tabNumber, StringBuffer buffer) {
for (int i = 0; i < tabNumber; i++) {
buffer.append(Messages.disassembler_indentation);
}
}
/**
* @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#getDescription()
*/
public String getDescription() {
return Messages.disassembler_description;
}
private IEnclosingMethodAttribute getEnclosingMethodAttribute(IClassFileReader classFileReader) {
IClassFileAttribute[] attributes = classFileReader.getAttributes();
for (int i = 0, max = attributes.length; i < max; i++) {
if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.ENCLOSING_METHOD)) {
return (IEnclosingMethodAttribute) attributes[i];
}
}
return null;
}
/**
* Method getEntryFor.
* @param localIndex
* @param entries
* @return ILocalVariableTableEntry
*/
private ILocalVariableTableEntry getEntryFor(
int localIndex,
ILocalVariableTableEntry[] entries) {
for (int i = 0, max = entries.length; i < max; i++) {
ILocalVariableTableEntry entry = entries[i];
if (localIndex == entry.getIndex()) {
return entry;
}
}
return null;
}
private ILocalVariableTypeTableAttribute getLocalVariableTypeAttribute(ICodeAttribute codeAttribute) {
IClassFileAttribute[] attributes = codeAttribute.getAttributes();
for (int i = 0, max = attributes.length; i < max; i++) {
if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.LOCAL_VARIABLE_TYPE_TABLE)) {
return (ILocalVariableTypeTableAttribute) attributes[i];
}
}
return null;
}
private char[][] getParameterNames(char[] methodDescriptor, ICodeAttribute codeAttribute, int accessFlags) {
int paramCount = Signature.getParameterCount(methodDescriptor);
char[][] parameterNames = new char[paramCount][];
// check if the code attribute has debug info for this method
if (codeAttribute != null) {
ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute();
if (localVariableAttribute != null) {
ILocalVariableTableEntry[] entries = localVariableAttribute.getLocalVariableTable();
int startingIndex = (accessFlags & IModifierConstants.ACC_STATIC) != 0 ? 0 : 1;
for (int i = 0; i < paramCount; i++) {
ILocalVariableTableEntry searchedEntry = getEntryFor(startingIndex + i, entries);
if (searchedEntry != null) {
parameterNames[i] = searchedEntry.getName();
} else {
parameterNames[i] = Messages.disassembler_parametername.toCharArray();
}
}
} else {
for (int i = 0; i < paramCount; i++) {
parameterNames[i] = Messages.disassembler_parametername.toCharArray();
}
}
} else {
for (int i = 0; i < paramCount; i++) {
parameterNames[i] = Messages.disassembler_parametername.toCharArray();
}
}
return parameterNames;
}
private char[] getSignatureForField(char[] fieldDescriptor) {
char[] newFieldDescriptor = CharOperation.replaceOnCopy(fieldDescriptor, '/', '.');
newFieldDescriptor = CharOperation.replaceOnCopy(newFieldDescriptor, '$', '~');
char[] fieldDescriptorSignature = Signature.toCharArray(newFieldDescriptor);
CharOperation.replace(fieldDescriptorSignature, '~', '$');
return fieldDescriptorSignature;
}
private boolean isDeprecated(IClassFileReader classFileReader) {
IClassFileAttribute[] attributes = classFileReader.getAttributes();
for (int i = 0, max = attributes.length; i < max; i++) {
if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.DEPRECATED)) {
return true;
}
}
return false;
}
private boolean isSynthetic(IClassFileReader classFileReader) {
int flags = classFileReader.getAccessFlags();
if ((flags & IModifierConstants.ACC_SYNTHETIC) != 0) {
return true;
}
IClassFileAttribute[] attributes = classFileReader.getAttributes();
for (int i = 0, max = attributes.length; i < max; i++) {
if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
return true;
}
}
return false;
}
private boolean checkMode(int mode, int flag) {
return (mode & flag) != 0;
}
private void writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber) {
buffer.append(lineSeparator);
dumpTab(tabNumber, buffer);
}
}