org.eclipse.jdt.internal.core.util.Disassembler Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2000, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Andy Clement (GoPivotal, Inc) [email protected] - Contributions for
* Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
* Jesper Steen Moeller - Contributions for:
* Bug 406973 - [compiler] Parse MethodParameters attribute
*******************************************************************************/
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.internal.compiler.codegen.AttributeNamesConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
/**
* 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 VERSION_UNKNOWN = Messages.classfileformat_versionUnknown;
private boolean appendModifier(StringBuilder 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 decodeModifiers(StringBuilder buffer, int accessFlags, int[] checkBits) {
decodeModifiers(buffer, accessFlags, false, false, checkBits);
}
private void decodeModifiers(StringBuilder buffer, int accessFlags, boolean printDefault, boolean asBridge, int[] checkBits) {
if (checkBits == null) return;
boolean firstModifier = true;
for (int i = 0, max = checkBits.length; i < max; i++) {
switch(checkBits[i]) {
case IModifierConstants.ACC_PUBLIC :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_PROTECTED :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_PRIVATE :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_ABSTRACT :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_STATIC :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_FINAL :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_SYNCHRONIZED :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNCHRONIZED, "synchronized", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_NATIVE :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_NATIVE, "native", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_STRICT :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STRICT, "strictfp", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_TRANSIENT :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_TRANSIENT, "transient", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_VOLATILE :
// case IModifierConstants.ACC_BRIDGE :
if (asBridge) {
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_BRIDGE, "bridge", firstModifier); //$NON-NLS-1$
} else {
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_VOLATILE, "volatile", firstModifier); //$NON-NLS-1$
}
break;
case IModifierConstants.ACC_ENUM :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ENUM, "enum", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_SYNTHETIC :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNTHETIC, "synthetic", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_MANDATED :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_MANDATED, "mandated", firstModifier); //$NON-NLS-1$
break;
}
}
if (!firstModifier) {
if (!printDefault) buffer.append(Messages.disassembler_space);
} else if (printDefault) {
// no modifier: package default visibility
buffer.append("default"); //$NON-NLS-1$
}
}
private void decodeModifiersForField(StringBuilder buffer, int accessFlags) {
decodeModifiers(buffer, accessFlags, new int[] {
IModifierConstants.ACC_PUBLIC,
IModifierConstants.ACC_PROTECTED,
IModifierConstants.ACC_PRIVATE,
IModifierConstants.ACC_STATIC,
IModifierConstants.ACC_FINAL,
IModifierConstants.ACC_TRANSIENT,
IModifierConstants.ACC_VOLATILE,
IModifierConstants.ACC_ENUM
});
}
private void decodeModifiersForFieldForWorkingCopy(StringBuilder buffer, int accessFlags) {
decodeModifiers(buffer, accessFlags, new int[] {
IModifierConstants.ACC_PUBLIC,
IModifierConstants.ACC_PROTECTED,
IModifierConstants.ACC_PRIVATE,
IModifierConstants.ACC_STATIC,
IModifierConstants.ACC_FINAL,
IModifierConstants.ACC_TRANSIENT,
IModifierConstants.ACC_VOLATILE,
});
}
private final void decodeModifiersForInnerClasses(StringBuilder buffer, int accessFlags, boolean printDefault) {
decodeModifiers(buffer, accessFlags, printDefault, false, new int[] {
IModifierConstants.ACC_PUBLIC,
IModifierConstants.ACC_PROTECTED,
IModifierConstants.ACC_PRIVATE,
IModifierConstants.ACC_ABSTRACT,
IModifierConstants.ACC_STATIC,
IModifierConstants.ACC_FINAL,
});
}
private final void decodeModifiersForMethod(StringBuilder buffer, int accessFlags) {
decodeModifiers(buffer, accessFlags, false, true, new int[] {
IModifierConstants.ACC_PUBLIC,
IModifierConstants.ACC_PROTECTED,
IModifierConstants.ACC_PRIVATE,
IModifierConstants.ACC_ABSTRACT,
IModifierConstants.ACC_STATIC,
IModifierConstants.ACC_FINAL,
IModifierConstants.ACC_SYNCHRONIZED,
IModifierConstants.ACC_NATIVE,
IModifierConstants.ACC_STRICT,
IModifierConstants.ACC_BRIDGE,
});
}
private final void decodeModifiersForMethodParameters(StringBuilder buffer, int accessFlags) {
decodeModifiers(buffer, accessFlags, false, true, new int[] {
IModifierConstants.ACC_FINAL,
IModifierConstants.ACC_MANDATED,
IModifierConstants.ACC_SYNTHETIC,
});
}
private final void decodeModifiersForType(StringBuilder buffer, int accessFlags) {
decodeModifiers(buffer, accessFlags, new int[] {
IModifierConstants.ACC_PUBLIC,
IModifierConstants.ACC_ABSTRACT,
IModifierConstants.ACC_FINAL,
});
}
private final void decodeModifiersForModuleRequires(StringBuilder buffer, int accessFlags) {
int[] checkBits = new int[] {
IModifierConstants.ACC_TRANSITIVE,
IModifierConstants.ACC_STATIC_PHASE,
};
boolean firstModifier = true;
for (int i = 0, max = checkBits.length; i < max; i++) {
switch(checkBits[i]) {
case IModifierConstants.ACC_TRANSITIVE :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_TRANSITIVE, "transitive", firstModifier); //$NON-NLS-1$
break;
case IModifierConstants.ACC_STATIC_PHASE :
firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC_PHASE, "protected", firstModifier); //$NON-NLS-1$
break;
}
}
if (!firstModifier) {
buffer.append(Messages.disassembler_space);
}
}
private final void decodeModifiersForModule(StringBuilder buffer, int accessFlags) {
appendModifier(buffer, accessFlags, IModifierConstants.ACC_OPEN, "open", true); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
}
public static String escapeString(String s) {
return decodeStringValue(s);
}
static String decodeStringValue(char[] chars) {
StringBuilder buffer = new StringBuilder();
for (int i = 0, max = chars.length; i < max; i++) {
char c = chars[i];
org.eclipse.jdt.internal.compiler.util.Util.appendEscapedChar(buffer, c, true);
}
return buffer.toString();
}
private static void escapeChar(StringBuilder buffer, char c) {
org.eclipse.jdt.internal.compiler.util.Util.appendEscapedChar(buffer, c, false);
}
static String decodeStringValue(String s) {
return decodeStringValue(s.toCharArray());
}
/**
* @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String)
*/
@Override
public String disassemble(byte[] classFileBytes, String lineSeparator) throws ClassFormatException {
try {
return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, ClassFileBytesDisassembler.DEFAULT);
} catch (ArrayIndexOutOfBoundsException e) {
throw new ClassFormatException(e.getMessage(), e);
}
}
/**
* @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String, int)
*/
@Override
public String disassemble(byte[] classFileBytes, String lineSeparator, int mode) throws ClassFormatException {
try {
return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, mode);
} catch (ArrayIndexOutOfBoundsException e) {
throw new ClassFormatException(e.getMessage(), e);
}
}
private void disassemble(IAnnotation annotation, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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(returnClassName(Signature.toCharArray(typeName), '.', mode))
}));
final IAnnotationComponent[] components = annotation.getComponents();
for (int i = 0, max = components.length; i < max; i++) {
disassemble(components[i], buffer, lineSeparator, tabNumber + 1, mode);
}
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_annotationentryend);
}
private void disassemble(IExtendedAnnotation extendedAnnotation, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
final int typeIndex = extendedAnnotation.getTypeIndex();
final char[] typeName = CharOperation.replaceOnCopy(extendedAnnotation.getTypeName(), '/', '.');
buffer.append(
Messages.bind(Messages.disassembler_extendedannotationentrystart, new String[] {
Integer.toString(typeIndex),
new String(returnClassName(Signature.toCharArray(typeName), '.', mode))
}));
final IAnnotationComponent[] components = extendedAnnotation.getComponents();
for (int i = 0, max = components.length; i < max; i++) {
disassemble(components[i], buffer, lineSeparator, tabNumber + 1, mode);
}
writeNewLine(buffer, lineSeparator, tabNumber + 2);
int targetType = extendedAnnotation.getTargetType();
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_targetType, new String[] {
Integer.toHexString(targetType),
getTargetType(targetType),
}));
switch(targetType) {
case IExtendedAnnotationConstants.METHOD_RECEIVER :
case IExtendedAnnotationConstants.METHOD_RETURN:
case IExtendedAnnotationConstants.FIELD :
break;
default:
writeNewLine(buffer, lineSeparator, tabNumber + 2);
disassembleTargetTypeContents(false, targetType, extendedAnnotation, buffer, lineSeparator, tabNumber, mode);
}
disassembleTypePathContents(targetType, extendedAnnotation, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_extendedannotationentryend);
}
private void disassembleTypePathContents(int targetType, IExtendedAnnotation extendedAnnotation,StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
int[][] typepath = extendedAnnotation.getTypePath();
if (typepath.length != 0) {
writeNewLine(buffer, lineSeparator, tabNumber + 2);
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_typepath, new String[] {
toTypePathString(typepath),
}));
}
}
private void disassembleTargetTypeContents(boolean insideWildcard, int targetType, IExtendedAnnotation extendedAnnotation, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
switch(targetType) {
case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER :
case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER :
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_type_parameter, new String[] {
Integer.toString(extendedAnnotation.getTypeParameterIndex()),
}));
break;
case IExtendedAnnotationConstants.CLASS_EXTENDS :
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_classextendsimplements, new String[] {
Integer.toString(extendedAnnotation.getAnnotationTypeIndex()),
}));
break;
case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER_BOUND :
case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER_BOUND :
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_type_parameter_with_bound, new String[] {
Integer.toString(extendedAnnotation.getTypeParameterIndex()),
Integer.toString(extendedAnnotation.getTypeParameterBoundIndex()),
}));
break;
case IExtendedAnnotationConstants.FIELD :
case IExtendedAnnotationConstants.METHOD_RETURN :
case IExtendedAnnotationConstants.METHOD_RECEIVER :
break;
case IExtendedAnnotationConstants.METHOD_FORMAL_PARAMETER :
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_method_parameter, new String[] {
Integer.toString(extendedAnnotation.getParameterIndex()),
}));
break;
case IExtendedAnnotationConstants.THROWS :
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_throws, new String[] {
Integer.toString(extendedAnnotation.getAnnotationTypeIndex()),
}));
break;
case IExtendedAnnotationConstants.LOCAL_VARIABLE :
case IExtendedAnnotationConstants.RESOURCE_VARIABLE :
buffer.append(Messages.disassembler_localvariabletargetheader);
writeNewLine(buffer, lineSeparator, tabNumber + 3);
int localVariableTableSize = extendedAnnotation.getLocalVariableRefenceInfoLength();
ILocalVariableReferenceInfo[] localVariableTable = extendedAnnotation.getLocalVariableTable();
for (int i = 0; i < localVariableTableSize; i++) {
if (i != 0) {
writeNewLine(buffer, lineSeparator, tabNumber + 3);
}
ILocalVariableReferenceInfo info = localVariableTable[i];
int index= info.getIndex();
int startPC = info.getStartPC();
int length = info.getLength();
buffer.append(Messages.bind(Messages.classfileformat_localvariablereferenceinfoentry,
new String[] {
Integer.toString(startPC),
Integer.toString(startPC + length),
Integer.toString(index),
}));
}
break;
case IExtendedAnnotationConstants.EXCEPTION_PARAMETER :
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_exception_table_index, new String[] {
Integer.toString(extendedAnnotation.getExceptionTableIndex()),
}));
break;
case IExtendedAnnotationConstants.INSTANCEOF :
case IExtendedAnnotationConstants.NEW :
case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE :
case IExtendedAnnotationConstants.METHOD_REFERENCE :
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_offset, new String[] {
Integer.toString(extendedAnnotation.getOffset()),
}));
break;
case IExtendedAnnotationConstants.CAST :
case IExtendedAnnotationConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT :
case IExtendedAnnotationConstants.METHOD_INVOCATION_TYPE_ARGUMENT :
case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT :
case IExtendedAnnotationConstants.METHOD_REFERENCE_TYPE_ARGUMENT :
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_offset, new String[] {
Integer.toString(extendedAnnotation.getOffset()),
}));
writeNewLine(buffer, lineSeparator, tabNumber + 2);
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_type_argument, new String[] {
Integer.toString(extendedAnnotation.getAnnotationTypeIndex()),
}));
break;
}
}
private String getTargetType(int targetType) {
switch(targetType) {
case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER :
return "CLASS_TYPE_PARAMETER"; //$NON-NLS-1$
case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER :
return "METHOD_TYPE_PARAMETER"; //$NON-NLS-1$
case IExtendedAnnotationConstants.CLASS_EXTENDS :
return "CLASS_EXTENDS"; //$NON-NLS-1$
case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER_BOUND :
return "CLASS_TYPE_PARAMETER_BOUND"; //$NON-NLS-1$
case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER_BOUND :
return "METHOD_TYPE_PARAMETER_BOUND"; //$NON-NLS-1$
case IExtendedAnnotationConstants.FIELD :
return "FIELD"; //$NON-NLS-1$
case IExtendedAnnotationConstants.METHOD_RETURN :
return "METHOD_RETURN"; //$NON-NLS-1$
case IExtendedAnnotationConstants.METHOD_RECEIVER :
return "METHOD_RECEIVER"; //$NON-NLS-1$
case IExtendedAnnotationConstants.METHOD_FORMAL_PARAMETER :
return "METHOD_FORMAL_PARAMETER"; //$NON-NLS-1$
case IExtendedAnnotationConstants.THROWS :
return "THROWS"; //$NON-NLS-1$
case IExtendedAnnotationConstants.LOCAL_VARIABLE :
return "LOCAL_VARIABLE"; //$NON-NLS-1$
case IExtendedAnnotationConstants.RESOURCE_VARIABLE :
return "RESOURCE_VARIABLE"; //$NON-NLS-1$
case IExtendedAnnotationConstants.EXCEPTION_PARAMETER :
return "EXCEPTION_PARAMETER"; //$NON-NLS-1$
case IExtendedAnnotationConstants.INSTANCEOF :
return "INSTANCEOF"; //$NON-NLS-1$
case IExtendedAnnotationConstants.NEW :
return "NEW"; //$NON-NLS-1$
case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE :
return "CONSTRUCTOR_REFERENCE"; //$NON-NLS-1$
case IExtendedAnnotationConstants.METHOD_REFERENCE :
return "METHOD_REFERENCE"; //$NON-NLS-1$
case IExtendedAnnotationConstants.CAST :
return "CAST"; //$NON-NLS-1$
case IExtendedAnnotationConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT :
return "CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT"; //$NON-NLS-1$
case IExtendedAnnotationConstants.METHOD_INVOCATION_TYPE_ARGUMENT :
return "METHOD_INVOCATION_TYPE_ARGUMENT"; //$NON-NLS-1$
case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT :
return "CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT"; //$NON-NLS-1$
case IExtendedAnnotationConstants.METHOD_REFERENCE_TYPE_ARGUMENT :
return "METHOD_REFERENCE_TYPE_ARGUMENT"; //$NON-NLS-1$
default:
return "UNKNOWN"; //$NON-NLS-1$
}
}
private void disassemble(IAnnotationComponent annotationComponent, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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, mode);
}
private void disassemble(IAnnotationComponentValue annotationComponentValue, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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:
StringBuilder temp = new StringBuilder();
switch(annotationComponentValue.getTag()) {
case IAnnotationComponentValue.CHAR_TAG :
temp.append('\'');
escapeChar(temp, (char) constantPoolEntry.getIntegerValue());
temp.append('\'');
break;
case IAnnotationComponentValue.BOOLEAN_TAG :
temp.append(constantPoolEntry.getIntegerValue() == 1 ? "true" : "false");//$NON-NLS-1$//$NON-NLS-2$
break;
case IAnnotationComponentValue.BYTE_TAG :
temp.append("(byte) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$
break;
case IAnnotationComponentValue.SHORT_TAG :
temp.append("(short) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$
break;
case IAnnotationComponentValue.INTEGER_TAG :
temp.append("(int) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$
}
value = String.valueOf(temp);
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(returnClassName(Signature.toCharArray(typeName), '.', mode)),
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(returnClassName(Signature.toCharArray(className), '.', mode))
}));
break;
case IAnnotationComponentValue.ANNOTATION_TAG:
buffer.append(Messages.disassembler_annotationannotationvalue);
IAnnotation annotation = annotationComponentValue.getAnnotationValue();
disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode);
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, mode);
}
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_annotationarrayvalueend);
}
}
private void disassemble(IAnnotationDefaultAttribute annotationDefaultAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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, mode);
}
private void disassemble(IClassFileAttribute classFileAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.bind(Messages.disassembler_genericattributeheader,
new String[] {
new String(classFileAttribute.getAttributeName()),
Long.toString(classFileAttribute.getAttributeLength())
}));
}
private void disassemble(IMethodParametersAttribute methodParametersAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
tabNumber += 2;
writeNewLine(buffer, lineSeparator, tabNumber);
buffer.append(Messages.disassembler_methodparametersheader);
for (int i = 0, length = methodParametersAttribute.getMethodParameterLength(); i < length; ++i) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
short accessFlags = methodParametersAttribute.getAccessFlags(i);
decodeModifiersForMethodParameters(buffer, accessFlags);
char [] parameterName = methodParametersAttribute.getParameterName(i);
if (parameterName == null)
parameterName = Messages.disassembler_anonymousparametername.toCharArray();
buffer.append(parameterName);
}
}
private void disassembleEnumConstructor(IClassFileReader classFileReader, char[] className, IMethodInfo methodInfo, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber);
final ICodeAttribute codeAttribute = methodInfo.getCodeAttribute();
IMethodParametersAttribute methodParametersAttribute = (IMethodParametersAttribute) Util.getAttribute(methodInfo, IAttributeNamesConstants.METHOD_PARAMETERS);
char[] methodDescriptor = methodInfo.getDescriptor();
final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
// disassemble compact version of annotations
if (runtimeInvisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
final int accessFlags = methodInfo.getAccessFlags();
decodeModifiersForMethod(buffer, accessFlags & IModifierConstants.ACC_PRIVATE);
CharOperation.replace(methodDescriptor, '/', '.');
final boolean isVarArgs = (accessFlags & IModifierConstants.ACC_VARARGS) != 0;
final char[] signature = Signature.toCharArray(methodDescriptor, returnClassName(className, '.', COMPACT), getParameterNames(methodDescriptor, codeAttribute, methodParametersAttribute, accessFlags) , !checkMode(mode, COMPACT), false, isVarArgs);
int index = CharOperation.indexOf(',', signature);
index = CharOperation.indexOf(',', signature, index + 1);
buffer.append(signature, 0, CharOperation.indexOf('(', signature) + 1);
buffer.append(signature, index + 2, signature.length - index - 2);
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; i++) {
if (i != 0) {
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space);
}
char[] exceptionName = exceptionNames[i];
CharOperation.replace(exceptionName, '/', '.');
buffer.append(returnClassName(exceptionName, '.', mode));
}
}
if (((accessFlags & IModifierConstants.ACC_NATIVE) == 0)
&& ((accessFlags & IModifierConstants.ACC_ABSTRACT) == 0)) {
buffer.append(" {"); //$NON-NLS-1$
final char[] returnType = Signature.getReturnType(methodDescriptor);
if (returnType.length == 1) {
switch(returnType[0]) {
case 'V' :
writeNewLine(buffer, lineSeparator, tabNumber);
break;
case 'I' :
case 'B' :
case 'J' :
case 'D' :
case 'F' :
case 'S' :
case 'C' :
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append("return 0;"); //$NON-NLS-1$
writeNewLine(buffer, lineSeparator, tabNumber);
break;
default :
// boolean
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append("return false;"); //$NON-NLS-1$
writeNewLine(buffer, lineSeparator, tabNumber);
}
} else {
// object
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append("return null;"); //$NON-NLS-1$
writeNewLine(buffer, lineSeparator, tabNumber);
}
buffer.append('}');
} else {
buffer.append(';');
}
}
/**
* Disassemble a method info header
*/
private void disassemble(IClassFileReader classFileReader, char[] className, IMethodInfo methodInfo, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber);
final ICodeAttribute codeAttribute = methodInfo.getCodeAttribute();
final char[] methodDescriptor = methodInfo.getDescriptor();
final ISignatureAttribute signatureAttribute = (ISignatureAttribute) Util.getAttribute(methodInfo, IAttributeNamesConstants.SIGNATURE);
final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
final IClassFileAttribute runtimeVisibleTypeAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleTypeAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
final IClassFileAttribute runtimeVisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
final IClassFileAttribute methodParametersAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.METHOD_PARAMETERS);
final 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, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
final int accessFlags = methodInfo.getAccessFlags();
decodeModifiersForMethod(buffer, accessFlags);
if (methodInfo.isSynthetic() && !checkMode(mode, WORKING_COPY)) {
buffer.append("synthetic"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
}
CharOperation.replace(methodDescriptor, '/', '.');
final boolean isVarArgs = isVarArgs(methodInfo);
char[] methodHeader = null;
char[][] parameterNames = null;
if (!methodInfo.isClinit()) {
parameterNames = getParameterNames(methodDescriptor, codeAttribute, (IMethodParametersAttribute)methodParametersAttribute, accessFlags);
}
if (methodInfo.isConstructor()) {
if (checkMode(mode, WORKING_COPY) && signatureAttribute != null) {
final char[] signature = signatureAttribute.getSignature();
CharOperation.replace(signature, '/', '.');
disassembleGenericSignature(mode, buffer, signature);
buffer.append(' ');
methodHeader = Signature.toCharArray(signature, returnClassName(className, '.', COMPACT), parameterNames, !checkMode(mode, COMPACT), false, isVarArgs);
} else {
methodHeader = Signature.toCharArray(methodDescriptor, returnClassName(className, '.', COMPACT), parameterNames, !checkMode(mode, COMPACT), false, isVarArgs);
}
} else if (methodInfo.isClinit()) {
methodHeader = Messages.bind(Messages.classfileformat_clinitname).toCharArray();
} else {
if (checkMode(mode, WORKING_COPY) && signatureAttribute != null) {
final char[] signature = signatureAttribute.getSignature();
CharOperation.replace(signature, '/', '.');
disassembleGenericSignature(mode, buffer, signature);
buffer.append(' ');
methodHeader = Signature.toCharArray(signature, methodInfo.getName(), parameterNames, !checkMode(mode, COMPACT), true, isVarArgs);
} else {
methodHeader = Signature.toCharArray(methodDescriptor, methodInfo.getName(), parameterNames, !checkMode(mode, COMPACT), true, isVarArgs);
}
}
if (checkMode(mode, DETAILED) && (runtimeInvisibleParameterAnnotationsAttribute != null || runtimeVisibleParameterAnnotationsAttribute != null)) {
IParameterAnnotation[] invisibleParameterAnnotations = null;
IParameterAnnotation[] visibleParameterAnnotations = null;
int length = -1;
if (runtimeInvisibleParameterAnnotationsAttribute != null) {
IRuntimeInvisibleParameterAnnotationsAttribute attribute = (IRuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute;
invisibleParameterAnnotations = attribute.getParameterAnnotations();
length = invisibleParameterAnnotations.length;
if (length > 0) {
int parameterNamesLength = parameterNames.length;
if (length < parameterNamesLength) {
int startExplicitParams = parameterNamesLength - length;
System.arraycopy(invisibleParameterAnnotations, 0, (invisibleParameterAnnotations = new IParameterAnnotation[parameterNamesLength]), startExplicitParams, length);
length = parameterNamesLength;
}
}
}
if (runtimeVisibleParameterAnnotationsAttribute != null) {
IRuntimeVisibleParameterAnnotationsAttribute attribute = (IRuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute;
visibleParameterAnnotations = attribute.getParameterAnnotations();
length = visibleParameterAnnotations.length;
if (length > 0) {
int parameterNamesLength = parameterNames.length;
if (length < parameterNamesLength) {
int startExplicitParams = parameterNamesLength - length;
System.arraycopy(visibleParameterAnnotations, 0, (visibleParameterAnnotations = new IParameterAnnotation[parameterNamesLength]), startExplicitParams, length);
length = parameterNamesLength;
}
}
}
int insertionPosition = CharOperation.indexOf('(', methodHeader) + 1;
int start = 0;
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append(methodHeader, 0, insertionPosition);
for (int i = 0; i < length; i++) {
if (i > 0) {
stringBuffer.append(' ');
}
int stringBufferSize = stringBuffer.length();
if (visibleParameterAnnotations != null) {
disassembleAsModifier(visibleParameterAnnotations, stringBuffer, i, lineSeparator, tabNumber, mode);
}
if (invisibleParameterAnnotations != null) {
if (stringBuffer.length() != stringBufferSize) {
stringBuffer.append(' ');
stringBufferSize = stringBuffer.length();
}
disassembleAsModifier(invisibleParameterAnnotations, stringBuffer, i, lineSeparator, tabNumber, mode);
}
if (i == 0 && stringBuffer.length() != stringBufferSize) {
stringBuffer.append(' ');
}
start = insertionPosition;
insertionPosition = CharOperation.indexOf(',', methodHeader, start + 1) + 1;
if (insertionPosition == 0) {
stringBuffer.append(methodHeader, start, methodHeader.length - start);
} else {
stringBuffer.append(methodHeader, start, insertionPosition - start);
}
}
buffer.append(stringBuffer);
} else {
buffer.append(methodHeader);
}
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; i++) {
if (i != 0) {
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space);
}
char[] exceptionName = exceptionNames[i];
CharOperation.replace(exceptionName, '/', '.');
buffer.append(returnClassName(exceptionName, '.', mode));
}
}
if (checkMode(mode, DETAILED)) {
if (annotationDefaultAttribute != null) {
buffer.append(" default "); //$NON-NLS-1$
disassembleAsModifier((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode);
}
}
if (checkMode(mode, WORKING_COPY)) {
// put the annotation default attribute if needed
if (annotationDefaultAttribute != null) {
buffer.append(" default "); //$NON-NLS-1$
disassembleAsModifier((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (((accessFlags & IModifierConstants.ACC_NATIVE) == 0)
&& ((accessFlags & IModifierConstants.ACC_ABSTRACT) == 0)) {
buffer.append(" {"); //$NON-NLS-1$
final char[] returnType = Signature.getReturnType(methodDescriptor);
if (returnType.length == 1) {
switch(returnType[0]) {
case 'V' :
writeNewLine(buffer, lineSeparator, tabNumber);
break;
case 'I' :
case 'B' :
case 'J' :
case 'D' :
case 'F' :
case 'S' :
case 'C' :
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append("return 0;"); //$NON-NLS-1$
writeNewLine(buffer, lineSeparator, tabNumber);
break;
default :
// boolean
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append("return false;"); //$NON-NLS-1$
writeNewLine(buffer, lineSeparator, tabNumber);
}
} else {
// object
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append("return null;"); //$NON-NLS-1$
writeNewLine(buffer, lineSeparator, tabNumber);
}
buffer.append('}');
} else {
buffer.append(';');
}
} else {
buffer.append(Messages.disassembler_endofmethodheader);
}
if (checkMode(mode, SYSTEM | DETAILED)) {
if (codeAttribute != null) {
disassemble(codeAttribute, parameterNames, methodDescriptor, (accessFlags & IModifierConstants.ACC_STATIC) != 0, buffer, lineSeparator, tabNumber, mode);
}
}
if (checkMode(mode, SYSTEM | DETAILED)) {
if (methodParametersAttribute != null) {
disassemble((IMethodParametersAttribute)methodParametersAttribute, 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 != runtimeInvisibleTypeAnnotationsAttribute
&& attribute != runtimeVisibleTypeAnnotationsAttribute
&& attribute != runtimeInvisibleParameterAnnotationsAttribute
&& attribute != runtimeVisibleParameterAnnotationsAttribute
&& attribute != methodParametersAttribute
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
disassemble(attribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
}
if (annotationDefaultAttribute != null) {
disassemble((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeInvisibleAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeVisibleParameterAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeInvisibleParameterAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeVisibleTypeAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleTypeAnnotationsAttribute) runtimeVisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeInvisibleTypeAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) runtimeInvisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
}
}
/**
* @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 org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING;
char[] className = classFileReader.getClassName();
if (className == null) {
// incomplete initialization. We cannot go further.
return org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING;
}
className= CharOperation.replaceOnCopy(className, '/', '.');
final int classNameLength = className.length;
final int accessFlags = classFileReader.getAccessFlags();
final boolean isEnum = (accessFlags & IModifierConstants.ACC_ENUM) != 0;
StringBuilder buffer = new StringBuilder();
ISourceAttribute sourceAttribute = classFileReader.getSourceFileAttribute();
IClassFileAttribute classFileAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.SIGNATURE);
ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
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;
if (minorVersion == 3 && majorVersion == 45) {
versionNumber = JavaCore.VERSION_1_1;
} else {
versionNumber = CompilerOptions.versionFromJdkLevel((majorVersion << 16) + minorVersion);
if (versionNumber.length() == 0)
versionNumber = VERSION_UNKNOWN;
}
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" : org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING)//$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);
}
}
final int lastDotIndexInClassName = CharOperation.lastIndexOf('.', className);
if (checkMode(mode, WORKING_COPY) && lastDotIndexInClassName != -1) {
// we print a package declaration
buffer.append("package ");//$NON-NLS-1$
buffer.append(className, 0, lastDotIndexInClassName);
buffer.append(';');
writeNewLine(buffer, lineSeparator, 0);
}
INestMembersAttribute nestMembersAttribute = classFileReader.getNestMembersAttribute();
IPermittedSubclassesAttribute permittedSubclassesAttribute = classFileReader.getPermittedSubclassesAttribute();
IInnerClassesAttribute innerClassesAttribute = classFileReader.getInnerClassesAttribute();
IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
IClassFileAttribute runtimeVisibleTypeAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
IClassFileAttribute runtimeInvisibleTypeAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
IClassFileAttribute bootstrapMethods = Util.getAttribute(classFileReader, IAttributeNamesConstants.BOOTSTRAP_METHODS);
IModuleAttribute moduleAttribute = (IModuleAttribute) Util.getAttribute(classFileReader, IAttributeNamesConstants.MODULE);
IRecordAttribute recordAttribute = classFileReader.getRecordAttribute();
if (checkMode(mode, DETAILED)) {
// disassemble compact version of annotations
if (runtimeInvisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode);
writeNewLine(buffer, lineSeparator, 0);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode);
writeNewLine(buffer, lineSeparator, 0);
}
}
boolean decoded = false;
if (isEnum && checkMode(mode, WORKING_COPY)) {
decodeModifiersForType(buffer, accessFlags & IModifierConstants.ACC_PUBLIC);
} else {
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(), false);
decoded = true;
}
}
}
}
if (!decoded) {
decodeModifiersForType(buffer, accessFlags);
if (isSynthetic(classFileReader)) {
buffer.append("synthetic"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
}
}
}
final boolean isAnnotation = (accessFlags & IModifierConstants.ACC_ANNOTATION) != 0;
final boolean isModule = (accessFlags & IModifierConstants.ACC_MODULE) != 0;
boolean isInterface = false;
if (isEnum) {
buffer.append("enum "); //$NON-NLS-1$
} else if (isModule) {
// skip - process under module attribute
} else if (classFileReader.isClass()) {
if (CharOperation.equals(classFileReader.getSuperclassName(), TypeConstants.CharArray_JAVA_LANG_RECORD_SLASH)) {
buffer.append("record "); //$NON-NLS-1$
}
else {
buffer.append("class "); //$NON-NLS-1$
}
} else {
if (isAnnotation) {
buffer.append("@"); //$NON-NLS-1$
}
buffer.append("interface "); //$NON-NLS-1$
isInterface = true;
}
if (checkMode(mode, WORKING_COPY)) {
// we print the simple class name
final int start = lastDotIndexInClassName + 1;
buffer.append(className, start, classNameLength - start);
className = CharOperation.subarray(className, start, classNameLength);
if (signatureAttribute != null) {
disassembleGenericSignature(mode, buffer, signatureAttribute.getSignature());
}
} else if (!isModule) {
buffer.append(className);
}
char[] superclassName = classFileReader.getSuperclassName();
if (superclassName != null) {
CharOperation.replace(superclassName, '/', '.');
if (!isJavaLangObject(superclassName) && !isEnum) {
buffer.append(" extends "); //$NON-NLS-1$
buffer.append(returnClassName(superclassName, '.', mode));
}
}
if (!isAnnotation || !checkMode(mode, WORKING_COPY)) {
char[][] superclassInterfaces = classFileReader.getInterfaceNames();
int length = superclassInterfaces.length;
if (length != 0) {
if (isInterface) {
buffer.append(" extends "); //$NON-NLS-1$
} else {
buffer.append(" implements "); //$NON-NLS-1$
}
for (int i = 0; i < length; i++) {
if (i != 0) {
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space);
}
char[] superinterface = superclassInterfaces[i];
CharOperation.replace(superinterface, '/', '.');
buffer
.append(returnClassName(superinterface, '.', mode));
}
}
}
if (!isModule)
buffer.append(Messages.bind(Messages.disassembler_opentypedeclaration));
if (checkMode(mode, SYSTEM)) {
disassemble(classFileReader.getConstantPool(), buffer, lineSeparator, 1);
}
if (isModule && moduleAttribute != null) { // print attributes - module package and main class only if the mandatory module attribute non-null
decodeModifiersForModule(buffer, accessFlags);
buffer.append("module"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
buffer.append(moduleAttribute.getModuleName());
buffer.append(Messages.disassembler_space);
buffer.append(Messages.bind(Messages.disassembler_opentypedeclaration));
disassembleModule(moduleAttribute, buffer, lineSeparator, 1);
IModulePackagesAttribute modulePackagesAttribute = (IModulePackagesAttribute) Util.getAttribute(classFileReader, IAttributeNamesConstants.MODULE_PACKAGES);
disassembleModule(modulePackagesAttribute, buffer, lineSeparator, 1);
IModuleMainClassAttribute mainClassAttribute = (IModuleMainClassAttribute) Util.getAttribute(classFileReader, IAttributeNamesConstants.MODULE_MAIN_CLASS);
disassembleModule(mainClassAttribute, buffer, lineSeparator, 1);
}
disassembleTypeMembers(classFileReader, className, buffer, lineSeparator, 1, mode, isEnum);
if (checkMode(mode, SYSTEM | DETAILED)) {
IClassFileAttribute[] attributes = classFileReader.getAttributes();
int length = attributes.length;
IEnclosingMethodAttribute enclosingMethodAttribute = (IEnclosingMethodAttribute) Util.getAttribute(classFileReader, IAttributeNamesConstants.ENCLOSING_METHOD);
INestHostAttribute nestHostAttribute = (INestHostAttribute) Util.getAttribute(classFileReader, IAttributeNamesConstants.NEST_HOST);
int remainingAttributesLength = length;
if (innerClassesAttribute != null) {
remainingAttributesLength--;
}
if (enclosingMethodAttribute != null) {
remainingAttributesLength--;
}
if (sourceAttribute != null) {
remainingAttributesLength--;
}
if (signatureAttribute != null) {
remainingAttributesLength--;
}
if (bootstrapMethods != null) {
remainingAttributesLength--;
}
if (moduleAttribute != null) {
remainingAttributesLength--;
}
if (nestHostAttribute != null) {
remainingAttributesLength--;
}
if (nestMembersAttribute != null) {
remainingAttributesLength--;
}
if (permittedSubclassesAttribute != null) {
remainingAttributesLength--;
}
if (innerClassesAttribute != null
|| enclosingMethodAttribute != null
|| nestHostAttribute != null
|| nestMembersAttribute != null
|| bootstrapMethods != null
|| moduleAttribute != null
|| recordAttribute != null
|| permittedSubclassesAttribute != null
|| remainingAttributesLength != 0) {
// this test is to ensure we don't insert more than one line separator
if (buffer.lastIndexOf(lineSeparator) != buffer.length() - lineSeparator.length()) {
writeNewLine(buffer, lineSeparator, 0);
}
}
if (innerClassesAttribute != null) {
disassemble(innerClassesAttribute, buffer, lineSeparator, 1);
}
if (enclosingMethodAttribute != null) {
disassemble(enclosingMethodAttribute, buffer, lineSeparator, 0);
}
if (nestHostAttribute != null) {
disassemble(nestHostAttribute, buffer, lineSeparator, 0);
}
if (nestMembersAttribute != null) {
disassemble(nestMembersAttribute, buffer, lineSeparator, 0);
}
if (recordAttribute != null) {
disassemble(recordAttribute, buffer, lineSeparator, 0, mode);
}
if (bootstrapMethods != null) {
disassemble((IBootstrapMethodsAttribute) bootstrapMethods, buffer, lineSeparator, 0, classFileReader.getConstantPool());
}
if (permittedSubclassesAttribute != null) {
disassemble(permittedSubclassesAttribute, buffer, lineSeparator, 0);
}
if (checkMode(mode, SYSTEM)) {
if (runtimeVisibleAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode);
}
if (runtimeInvisibleAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode);
}
if (runtimeVisibleTypeAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleTypeAnnotationsAttribute) runtimeVisibleTypeAnnotationsAttribute, buffer, lineSeparator, 0, mode);
}
if (runtimeInvisibleTypeAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) runtimeInvisibleTypeAnnotationsAttribute, buffer, lineSeparator, 0, mode);
}
if (length != 0) {
for (int i = 0; i < length; i++) {
IClassFileAttribute attribute = attributes[i];
if (attribute != innerClassesAttribute
&& attribute != nestHostAttribute
&& attribute != nestMembersAttribute
&& attribute != recordAttribute
&& attribute != permittedSubclassesAttribute
&& attribute != sourceAttribute
&& attribute != signatureAttribute
&& attribute != enclosingMethodAttribute
&& attribute != runtimeInvisibleAnnotationsAttribute
&& attribute != runtimeVisibleAnnotationsAttribute
&& attribute != runtimeInvisibleTypeAnnotationsAttribute
&& attribute != runtimeVisibleTypeAnnotationsAttribute
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)
&& attribute != bootstrapMethods
&& attribute != moduleAttribute
) {
disassemble(attribute, buffer, lineSeparator, 0, mode);
}
}
}
}
}
writeNewLine(buffer, lineSeparator, 0);
buffer.append(Messages.disassembler_closetypedeclaration);
return buffer.toString();
}
private void disassembleModule(IModuleAttribute moduleAttribute, StringBuilder buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber);
char[] moduleVersion = moduleAttribute.getModuleVersionValue();
if (moduleVersion == null) {
moduleVersion = Messages.disassembler_module_version_none.toCharArray();
}
buffer.append(Messages.bind(Messages.disassembler_module_version, new String(moduleVersion)));
IRequiresInfo[] requiresInfo = moduleAttribute.getRequiresInfo();
if (requiresInfo.length > 0) {
writeNewLine(buffer, lineSeparator, 0);
for (int i = 0, max = requiresInfo.length; i < max; i++) {
writeNewLine(buffer, lineSeparator, tabNumber);
disassemble(requiresInfo[i], buffer, lineSeparator, tabNumber);
}
}
IPackageVisibilityInfo[] exportInfos = moduleAttribute.getExportsInfo();
if (exportInfos.length > 0) {
writeNewLine(buffer, lineSeparator, 0);
for (int i = 0, max = exportInfos.length; i < max; i++) {
writeNewLine(buffer, lineSeparator, tabNumber);
disassemble(exportInfos[i], buffer, lineSeparator, tabNumber, true);
}
}
IPackageVisibilityInfo[] opensInfos = moduleAttribute.getOpensInfo();
if (opensInfos.length > 0) {
writeNewLine(buffer, lineSeparator, 0);
for (int i = 0, max = opensInfos.length; i < max; i++) {
writeNewLine(buffer, lineSeparator, tabNumber);
disassemble(opensInfos[i], buffer, lineSeparator, tabNumber, false);
}
}
char[][] usesNames = moduleAttribute.getUsesClassNames();
if (usesNames.length > 0) {
writeNewLine(buffer, lineSeparator, 0);
for (int i = 0, max = usesNames.length; i < max; i++) {
writeNewLine(buffer, lineSeparator, tabNumber);
buffer.append("uses " + CharOperation.charToString(CharOperation.replaceOnCopy(usesNames[i], '/','.'))); //$NON-NLS-1$
}
}
IProvidesInfo[] providesInfos = moduleAttribute.getProvidesInfo();
if (providesInfos.length > 0) {
writeNewLine(buffer, lineSeparator, 0);
for (int i = 0, max = providesInfos.length; i < max; i++) {
writeNewLine(buffer, lineSeparator, tabNumber);
disassemble(providesInfos[i], buffer, lineSeparator, tabNumber);
}
}
}
private void convertModuleNames(StringBuilder buffer, char[] name) {
buffer.append(CharOperation.replaceOnCopy(CharOperation.replaceOnCopy(name, '$','.'), '/','.'));
}
private void disassembleModule(IModulePackagesAttribute modulePackagesAttribute, StringBuilder buffer, String lineSeparator, int tabNumber) {
if (modulePackagesAttribute == null) return;
writeNewLine(buffer, lineSeparator, tabNumber);
writeNewLine(buffer, lineSeparator, tabNumber);
buffer.append(Messages.disassembler_modulepackagesattributeheader);
char[][] names = modulePackagesAttribute.getPackageNames();
for (int i = 0, l = modulePackagesAttribute.getPackagesCount(); i < l; ++i) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
convertModuleNames(buffer, names[i]);
}
writeNewLine(buffer, lineSeparator, 0);
}
private void disassembleModule(IModuleMainClassAttribute moduleMainClassAttribute, StringBuilder buffer, String lineSeparator, int tabNumber) {
if (moduleMainClassAttribute == null) return;
writeNewLine(buffer, lineSeparator, tabNumber);
buffer.append(Messages.disassembler_modulemainclassattributeheader);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
convertModuleNames(buffer, moduleMainClassAttribute.getMainClassName());
writeNewLine(buffer, lineSeparator, 0);
}
private void disassemble(IProvidesInfo iProvidesInfo, StringBuilder buffer, String lineSeparator, int tabNumber) {
buffer.append("provides"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
convertModuleNames(buffer, iProvidesInfo.getServiceName());
buffer.append(Messages.disassembler_space);
char[][] implementations = iProvidesInfo.getImplementationNames();
if (implementations.length > 0) {
buffer.append( "with"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
for (int i = 0, l = implementations.length; i < l; ++i) {
if (i != 0) {
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space);
}
convertModuleNames(buffer, implementations[i]);
}
}
buffer.append(';');
}
private void disassemble(INestHostAttribute nestHostAttribute, StringBuilder buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber);
writeNewLine(buffer, lineSeparator, tabNumber); // additional line
buffer.append(Messages.disassembler_nesthost);
buffer
.append(Messages.disassembler_constantpoolindex)
.append(nestHostAttribute.getNestHostIndex())
.append(" ")//$NON-NLS-1$
.append(nestHostAttribute.getNestHostName());
}
private void disassemble(IRecordAttribute recordAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber);
writeNewLine(buffer, lineSeparator, tabNumber); // additional line
buffer.append(Messages.disassembler_record);
buffer
.append(Messages.disassembler_constantpoolindex)
.append(recordAttribute.getAttributeName());
writeNewLine(buffer, lineSeparator, tabNumber);
buffer.append(Messages.disassembler_components);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
IComponentInfo[] entries = recordAttribute.getComponentInfos();
for (IComponentInfo e : entries) {
disassemble(e, buffer, lineSeparator, tabNumber, mode);
}
}
private void disassemble(IComponentInfo componentInfo, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber);
final char[] descriptor = componentInfo.getDescriptor();
final ISignatureAttribute signatureAttribute = (ISignatureAttribute) Util.getAttribute(componentInfo, IAttributeNamesConstants.SIGNATURE);
if (checkMode(mode, SYSTEM | DETAILED)) {
buffer.append(Messages.bind(Messages.classfileformat_componentdescriptor,
new String[] {
Integer.toString(componentInfo.getDescriptorIndex()),
new String(descriptor)
}));
writeNewLine(buffer, lineSeparator, tabNumber);
if (signatureAttribute != null) {
buffer.append(Messages.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature())));
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(componentInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(componentInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
final IClassFileAttribute runtimeVisibleTypeAnnotationsAttribute = Util.getAttribute(componentInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleTypeAnnotationsAttribute = Util.getAttribute(componentInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
if (checkMode(mode, DETAILED)) {
// disassemble compact version of annotations
if (runtimeInvisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
if (checkMode(mode, WORKING_COPY)) {
if (signatureAttribute != null) {
buffer.append(returnClassName(getSignatureForComponent(signatureAttribute.getSignature()), '.', mode));
} else {
buffer.append(returnClassName(getSignatureForComponent(descriptor), '.', mode));
}
} else {
buffer.append(returnClassName(getSignatureForComponent(descriptor), '.', mode));
}
buffer.append(' ');
buffer.append(new String(componentInfo.getName()));
buffer.append(Messages.disassembler_endofcomponent);
if (checkMode(mode, SYSTEM)) {
IClassFileAttribute[] attributes = componentInfo.getAttributes();
int length = attributes.length;
if (length != 0) {
for (int i = 0; i < length; i++) {
IClassFileAttribute attribute = attributes[i];
if (attribute != signatureAttribute
&& attribute != runtimeInvisibleAnnotationsAttribute
&& attribute != runtimeVisibleAnnotationsAttribute
&& attribute != runtimeInvisibleTypeAnnotationsAttribute
&& attribute != runtimeVisibleTypeAnnotationsAttribute) {
disassemble(attribute, buffer, lineSeparator, tabNumber, mode);
}
}
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeInvisibleAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeVisibleTypeAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleTypeAnnotationsAttribute) runtimeVisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeInvisibleTypeAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) runtimeInvisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
}
}
private void disassemble(INestMembersAttribute nestMembersAttribute, StringBuilder buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber);
writeNewLine(buffer, lineSeparator, tabNumber); // additional line
buffer.append(Messages.disassembler_nestmembers);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
INestMemberAttributeEntry[] entries = nestMembersAttribute.getNestMemberAttributesEntries();
int length = entries.length;
int nestMemberIndex;
INestMemberAttributeEntry entry;
for (int i = 0; i < length; i++) {
if (i != 0) {
buffer.append(Messages.disassembler_comma);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
}
entry = entries[i];
nestMemberIndex = entry.getNestMemberIndex();
buffer
.append(Messages.disassembler_constantpoolindex)
.append(nestMemberIndex);
if (nestMemberIndex != 0) {
buffer
.append(Messages.disassembler_space)
.append(entry.getNestMemberName());
}
}
}
private void disassemble(IPermittedSubclassesAttribute permittedSubclassesAttribute, StringBuilder buffer, String lineSeparator, int tabNumber) {
writeNewLine(buffer, lineSeparator, tabNumber);
writeNewLine(buffer, lineSeparator, tabNumber); // additional line
buffer.append(Messages.disassembler_permittedsubclasses);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
IPermittedSubclassesAttributeEntry[] entries = permittedSubclassesAttribute.getPermittedSubclassAttributesEntries();
int length = entries.length;
int permittedSubclassesIndex;
IPermittedSubclassesAttributeEntry entry;
for (int i = 0; i < length; i++) {
if (i != 0) {
buffer.append(Messages.disassembler_comma);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
}
entry = entries[i];
permittedSubclassesIndex = entry.gePermittedSubclassIndex();
buffer
.append(Messages.disassembler_constantpoolindex)
.append(permittedSubclassesIndex);
if (permittedSubclassesIndex != 0) {
buffer
.append(Messages.disassembler_space)
.append(entry.getPermittedSubclassName());
}
}
}
private void disassemble(IPackageVisibilityInfo iPackageVisibilityInfo, StringBuilder buffer, String lineSeparator,
int tabNumber, boolean isExports) {
buffer.append(isExports ? "exports" : "opens"); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(Messages.disassembler_space);
convertModuleNames(buffer, iPackageVisibilityInfo.getPackageName());
char[][] targets = iPackageVisibilityInfo.getTargetModuleNames();
if (targets.length > 0) {
buffer.append(Messages.disassembler_space);
buffer.append( "to"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
for (int i = 0, l = targets.length; i < l; ++i) {
if (i != 0) {
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space);
}
buffer.append(targets[i]);
}
}
buffer.append(';');
}
private void disassemble(IRequiresInfo iRequiresInfo, StringBuilder buffer, String lineSeparator, int tabNumber) {
buffer.append("requires "); //$NON-NLS-1$
decodeModifiersForModuleRequires(buffer, iRequiresInfo.getRequiresFlags());
buffer.append(iRequiresInfo.getRequiresModuleName());
buffer.append(';');
}
private void disassembleGenericSignature(int mode, StringBuilder buffer, final char[] signature) {
CharOperation.replace(signature, '/', '.');
final char[][] typeParameters = Signature.getTypeParameters(signature);
final int typeParametersLength = typeParameters.length;
if (typeParametersLength != 0) {
buffer.append('<');
for (int i = 0; i < typeParametersLength; i++) {
if (i != 0) {
buffer.append(Messages.disassembler_comma);
}
// extract the name
buffer.append(typeParameters[i], 0, CharOperation.indexOf(':', typeParameters[i]));
final char[][] bounds = Signature.getTypeParameterBounds(typeParameters[i]);
final int boundsLength = bounds.length;
if (boundsLength != 0) {
if (boundsLength == 1) {
final char[] bound = bounds[0];
// check if this is java.lang.Object
if (!isJavaLangObject(Signature.toCharArray(bound))) {
buffer.append(" extends "); //$NON-NLS-1$
buffer.append(returnClassName(Signature.toCharArray(bound), '.', mode));
}
} else {
buffer.append(" extends "); //$NON-NLS-1$
for (int j= 0; j < boundsLength; j++) {
if (j != 0) {
buffer.append(" & "); //$NON-NLS-1$
}
buffer.append(returnClassName(Signature.toCharArray(bounds[j]), '.', mode));
}
}
}
}
buffer.append('>');
}
}
private boolean isJavaLangObject(final char[] className) {
return CharOperation.equals(TypeConstants.JAVA_LANG_OBJECT, CharOperation.splitOn('.', className));
}
private boolean isVarArgs(IMethodInfo methodInfo) {
int accessFlags = methodInfo.getAccessFlags();
if ((accessFlags & IModifierConstants.ACC_VARARGS) != 0) return true;
// check the presence of the unspecified Varargs attribute
return Util.getAttribute(methodInfo, AttributeNamesConstants.VarargsName) != null;
}
private void disassemble(ICodeAttribute codeAttribute, char[][] parameterNames, char[] methodDescriptor, boolean isStatic, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber - 1);
DefaultBytecodeVisitor visitor = new DefaultBytecodeVisitor(codeAttribute, parameterNames, methodDescriptor, isStatic, buffer, lineSeparator, tabNumber, mode);
try {
codeAttribute.traverse(visitor);
} catch(ClassFormatException e) {
dumpTab(tabNumber + 3, buffer);
buffer.append(Messages.classformat_classformatexception);
writeNewLine(buffer, lineSeparator, tabNumber - 1);
}
final int exceptionTableLength = codeAttribute.getExceptionTableLength();
boolean isFirstAttribute = true;
if (exceptionTableLength != 0) {
final int tabNumberForExceptionAttribute = tabNumber + 2;
isFirstAttribute = false;
dumpTab(tabNumberForExceptionAttribute, buffer);
final IExceptionTableEntry[] exceptionTableEntries = codeAttribute.getExceptionTable();
buffer.append(Messages.disassembler_exceptiontableheader);
writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
for (int i = 0; i < exceptionTableLength; i++) {
if (i != 0) {
writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
}
IExceptionTableEntry exceptionTableEntry = exceptionTableEntries[i];
char[] catchType;
if (exceptionTableEntry.getCatchTypeIndex() != 0) {
catchType = exceptionTableEntry.getCatchType();
CharOperation.replace(catchType, '/', '.');
catchType = returnClassName(catchType, '.', mode);
} 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),
}));
}
}
final ILineNumberAttribute lineNumberAttribute = codeAttribute.getLineNumberAttribute();
final int lineAttributeLength = lineNumberAttribute == null ? 0 : lineNumberAttribute.getLineNumberTableLength();
if (lineAttributeLength != 0) {
int tabNumberForLineAttribute = tabNumber + 2;
if (!isFirstAttribute) {
writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute);
} else {
dumpTab(tabNumberForLineAttribute, buffer);
isFirstAttribute = false;
}
buffer.append(Messages.disassembler_linenumberattributeheader);
writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
int[][] lineattributesEntries = lineNumberAttribute.getLineNumberTable();
for (int i = 0; i < lineAttributeLength; i++) {
if (i != 0) {
writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
}
buffer.append(Messages.bind(Messages.classfileformat_linenumbertableentry,
new String[] {
Integer.toString(lineattributesEntries[i][0]),
Integer.toString(lineattributesEntries[i][1])
}));
}
}
final ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute();
final int localVariableAttributeLength = localVariableAttribute == null ? 0 : localVariableAttribute.getLocalVariableTableLength();
if (localVariableAttributeLength != 0) {
int tabNumberForLocalVariableAttribute = tabNumber + 2;
if (!isFirstAttribute) {
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
} else {
isFirstAttribute = false;
dumpTab(tabNumberForLocalVariableAttribute, buffer);
}
buffer.append(Messages.disassembler_localvariabletableattributeheader);
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
ILocalVariableTableEntry[] localVariableTableEntries = localVariableAttribute.getLocalVariableTable();
for (int i = 0; i < localVariableAttributeLength; i++) {
if (i != 0) {
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
}
ILocalVariableTableEntry localVariableTableEntry = localVariableTableEntries[i];
int index= localVariableTableEntry.getIndex();
int startPC = localVariableTableEntry.getStartPC();
int length = localVariableTableEntry.getLength();
final char[] typeName = Signature.toCharArray(localVariableTableEntry.getDescriptor());
CharOperation.replace(typeName, '/', '.');
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(returnClassName(typeName, '.', mode))
}));
}
}
final ILocalVariableTypeTableAttribute localVariableTypeAttribute= (ILocalVariableTypeTableAttribute) Util.getAttribute(codeAttribute, IAttributeNamesConstants.LOCAL_VARIABLE_TYPE_TABLE);
final int localVariableTypeTableLength = localVariableTypeAttribute == null ? 0 : localVariableTypeAttribute.getLocalVariableTypeTableLength();
if (localVariableTypeTableLength != 0) {
int tabNumberForLocalVariableAttribute = tabNumber + 2;
if (!isFirstAttribute) {
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
} else {
isFirstAttribute = false;
dumpTab(tabNumberForLocalVariableAttribute, buffer);
}
buffer.append(Messages.disassembler_localvariabletypetableattributeheader);
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
ILocalVariableTypeTableEntry[] localVariableTypeTableEntries = localVariableTypeAttribute.getLocalVariableTypeTable();
for (int i = 0; i < localVariableTypeTableLength; i++) {
if (i != 0) {
writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
}
ILocalVariableTypeTableEntry localVariableTypeTableEntry = localVariableTypeTableEntries[i];
int index= localVariableTypeTableEntry.getIndex();
int startPC = localVariableTypeTableEntry.getStartPC();
int length = localVariableTypeTableEntry.getLength();
final char[] typeName = Signature.toCharArray(localVariableTypeTableEntry.getSignature());
CharOperation.replace(typeName, '/', '.');
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(returnClassName(typeName, '.', mode))
}));
}
}
final int length = codeAttribute.getAttributesCount();
if (length != 0) {
IClassFileAttribute[] attributes = codeAttribute.getAttributes();
for (int i = 0; i < length; i++) {
IClassFileAttribute attribute = attributes[i];
if (CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.STACK_MAP_TABLE)) {
IStackMapTableAttribute stackMapTableAttribute = (IStackMapTableAttribute) attribute;
if (!isFirstAttribute) {
writeNewLine(buffer, lineSeparator, tabNumber + 2);
} else {
isFirstAttribute = false;
dumpTab(tabNumber + 1, buffer);
}
int numberOfEntries = stackMapTableAttribute.getNumberOfEntries();
buffer.append(Messages.bind(Messages.disassembler_stackmaptableattributeheader, Integer.toString(numberOfEntries)));
if (numberOfEntries != 0) {
disassemble(stackMapTableAttribute, buffer, lineSeparator, tabNumber, mode);
}
} else if (CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.STACK_MAP)) {
IStackMapAttribute stackMapAttribute = (IStackMapAttribute) attribute;
if (!isFirstAttribute) {
writeNewLine(buffer, lineSeparator, tabNumber + 2);
} else {
isFirstAttribute = false;
dumpTab(tabNumber + 1, buffer);
}
int numberOfEntries = stackMapAttribute.getNumberOfEntries();
buffer.append(Messages.bind(Messages.disassembler_stackmapattributeheader, Integer.toString(numberOfEntries)));
if (numberOfEntries != 0) {
disassemble(stackMapAttribute, buffer, lineSeparator, tabNumber, mode);
}
} else if (CharOperation.equals(attribute.getAttributeName(),IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS)) {
disassemble((IRuntimeVisibleTypeAnnotationsAttribute) attribute, buffer, lineSeparator, tabNumber, mode);
} else if (CharOperation.equals(attribute.getAttributeName(),IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS)) {
disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) attribute, buffer, lineSeparator, tabNumber, mode);
} else if (attribute != lineNumberAttribute
&& attribute != localVariableAttribute
&& attribute != localVariableTypeAttribute) {
if (!isFirstAttribute) {
writeNewLine(buffer, lineSeparator, tabNumber + 2);
} else {
isFirstAttribute = false;
dumpTab(tabNumber + 1, buffer);
}
buffer.append(Messages.bind(Messages.disassembler_genericattributeheader,
new String[] {
new String(attribute.getAttributeName()),
Long.toString(attribute.getAttributeLength())
}));
}
}
}
}
private void disassemble(IStackMapTableAttribute attribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber + 3);
int numberOfEntries = attribute.getNumberOfEntries();
final IStackMapFrame[] stackMapFrames = attribute.getStackMapFrame();
int absolutePC = -1;
for (int j = 0; j < numberOfEntries; j++) {
if (j > 0) {
writeNewLine(buffer, lineSeparator, tabNumber + 3);
}
final IStackMapFrame frame = stackMapFrames[j];
// disassemble each frame
int type = frame.getFrameType();
int offsetDelta = frame.getOffsetDelta();
if (absolutePC == -1) {
absolutePC = offsetDelta;
} else {
absolutePC += (offsetDelta + 1);
}
switch(type) {
case 247 : // SAME_LOCALS_1_STACK_ITEM_EXTENDED
buffer.append(
Messages.bind(
Messages.disassembler_frame_same_locals_1_stack_item_extended,
Integer.toString(absolutePC),
disassemble(frame.getStackItems(), mode)));
break;
case 248 :
case 249 :
case 250:
// CHOP
buffer.append(
Messages.bind(
Messages.disassembler_frame_chop,
Integer.toString(absolutePC),
Integer.toString(251 - type)));
break;
case 251 :
// SAME_FRAME_EXTENDED
buffer.append(
Messages.bind(
Messages.disassembler_frame_same_frame_extended,
Integer.toString(absolutePC)));
break;
case 252 :
case 253 :
case 254 :
// APPEND
buffer.append(
Messages.bind(
Messages.disassembler_frame_append,
Integer.toString(absolutePC),
disassemble(frame.getLocals(), mode)));
break;
case 255 :
// FULL_FRAME
buffer.append(
Messages.bind(
Messages.disassembler_frame_full_frame,
new String[] {
Integer.toString(absolutePC),
Integer.toString(frame.getNumberOfLocals()),
disassemble(frame.getLocals(), mode),
Integer.toString(frame.getNumberOfStackItems()),
disassemble(frame.getStackItems(), mode),
dumpNewLineWithTabs(lineSeparator, tabNumber + 5)
}));
break;
default:
if (type <= 63) {
// SAME_FRAME
offsetDelta = type;
buffer.append(
Messages.bind(
Messages.disassembler_frame_same_frame,
Integer.toString(absolutePC)));
} else if (type <= 127) {
// SAME_LOCALS_1_STACK_ITEM
offsetDelta = type - 64;
buffer.append(
Messages.bind(
Messages.disassembler_frame_same_locals_1_stack_item,
Integer.toString(absolutePC),
disassemble(frame.getStackItems(), mode)));
}
}
}
}
private void disassemble(IStackMapAttribute attribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber + 3);
int numberOfEntries = attribute.getNumberOfEntries();
final IStackMapFrame[] stackMapFrames = attribute.getStackMapFrame();
for (int j = 0; j < numberOfEntries; j++) {
if (j > 0) {
writeNewLine(buffer, lineSeparator, tabNumber + 3);
}
final IStackMapFrame frame = stackMapFrames[j];
// disassemble each frame
buffer.append(
Messages.bind(
Messages.disassembler_frame_full_frame,
new String[] {
Integer.toString(frame.getOffsetDelta()),
Integer.toString(frame.getNumberOfLocals()),
disassemble(frame.getLocals(), mode),
Integer.toString(frame.getNumberOfStackItems()),
disassemble(frame.getStackItems(), mode),
dumpNewLineWithTabs(lineSeparator, tabNumber + 5)
}));
}
}
private String bootstrapMethodDescription(IBootstrapMethodsEntry entry, IConstantPool constantPool) {
// http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
// The BootstrapMethods attribute records bootstrap method specifiers referenced by invokedynamic instructions.
// The value of the bootstrap_method_ref item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_MethodHandle_info structure (§4.4.8).
// http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.8
// constantpoolentry.getKind() = IConstantPoolConstant.CONSTANT_MethodHandle
ConstantPoolEntry2 constantPoolEntry2 = (ConstantPoolEntry2) constantPool.decodeEntry(entry.getBootstrapMethodReference());
// The reference_kind item of the CONSTANT_MethodHandle_info structure should have the value 6 (REF_invokeStatic) or 8 (REF_newInvokeSpecial)
// (§5.4.3.5) or else invocation of the bootstrap method handle during call site specifier resolution for an invokedynamic instruction will complete abruptly.
// If the value of the reference_kind item is 5 (REF_invokeVirtual), 6 (REF_invokeStatic), 7 (REF_invokeSpecial),
// or 9 (REF_invokeInterface), the name of the method represented by a CONSTANT_Methodref_info structure must not be or .
if (constantPoolEntry2.getReferenceKind() != 6)
return null;
ConstantPoolEntry constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(constantPoolEntry2.getReferenceIndex());
StringBuilder builder = new StringBuilder();
//String[] methodMsg = methodDescription(constantPoolEntry);
builder.append(Messages.bind("invokestatic {0}.{1}:{2}", methodDescription(constantPoolEntry))); //$NON-NLS-1$
return builder.toString();
}
private String[] bootstrapArgumentsDescription(IBootstrapMethodsEntry entry, IConstantPool constantPool) {
// http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.21
// bootstrap_arguments
// Each entry in the bootstrap_arguments array must be a valid index into the constant_pool table.
// The constant_pool entry at that index must be a CONSTANT_String_info, CONSTANT_Class_info, CONSTANT_Integer_info
// CONSTANT_Long_info, CONSTANT_Float_info, CONSTANT_Double_info, CONSTANT_MethodHandle_info, or
// CONSTANT_MethodType_info structure (§4.4.3, §4.4.1, §4.4.4, §4.4.5), §4.4.8, §4.4.9).
if (entry.getBootstrapArguments().length == 0)
return null;
int[] bootstrapArguments = entry.getBootstrapArguments();
String[] arguments = new String[bootstrapArguments.length];
for (int i = 0, length = bootstrapArguments.length; i < length; i++) {
ConstantPoolEntry constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(bootstrapArguments[i]);
switch(constantPoolEntry.getKind()) {
case IConstantPoolConstant.CONSTANT_Integer:
arguments[i] = Integer.toString(constantPoolEntry.getIntegerValue());
break;
case IConstantPoolConstant.CONSTANT_MethodHandle:
// http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.8
// If the value of the reference_kind item is 5 (REF_invokeVirtual), 6 (REF_invokeStatic),
// 7 (REF_invokeSpecial), or 8 (REF_newInvokeSpecial), then the constant_pool entry at that
// index must be a CONSTANT_Methodref_info structure (§4.4.2) representing a class's method or
// constructor (§2.9) for which a method handle is to be created.
ConstantPoolEntry2 constantPoolEntry2 = (ConstantPoolEntry2) constantPoolEntry;
StringBuilder builder = new StringBuilder(10);
switch(constantPoolEntry2.getReferenceKind()) {
case IConstantPoolConstant.METHOD_TYPE_REF_GetField:
builder.append("REF_getField "); //$NON-NLS-1$
constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(constantPoolEntry2.getReferenceIndex());
builder.append(Messages.bind("{0}:{1}", fieldDescription(constantPoolEntry))); //$NON-NLS-1$
arguments[i] = builder.toString();
break;
case IConstantPoolConstant.METHOD_TYPE_REF_InvokeStatic:
builder.append("invokestatic "); //$NON-NLS-1$
//$FALL-THROUGH$
case IConstantPoolConstant.METHOD_TYPE_REF_InvokeVirtual:
case IConstantPoolConstant.METHOD_TYPE_REF_NewInvokeSpecial:
constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(constantPoolEntry2.getReferenceIndex());
builder.append(Messages.bind("{0}.{1}:{2}", methodDescription(constantPoolEntry))); //$NON-NLS-1$
arguments[i] = builder.toString();
break;
}
break;
case IConstantPoolConstant.CONSTANT_MethodType:
arguments[i] = new String(((ConstantPoolEntry2) constantPoolEntry).getMethodDescriptor());
break;
case IConstantPoolConstant.CONSTANT_Class:
arguments[i] = new String(constantPoolEntry.getClassInfoName());
break;
case IConstantPoolConstant.CONSTANT_String:
arguments[i] = constantPoolEntry.getStringValue();
break;
}
}
return arguments;
}
private String[] fieldDescription(IConstantPoolEntry constantPoolEntry) {
return new String[] { new String(constantPoolEntry.getFieldName()),
new String(constantPoolEntry.getFieldDescriptor())};
}
private String[] methodDescription(IConstantPoolEntry constantPoolEntry) {
return new String[] { new String(constantPoolEntry.getClassName()),
new String(constantPoolEntry.getMethodName()),
new String(constantPoolEntry.getMethodDescriptor())};
}
private void disassemble(IConstantPool constantPool, StringBuilder 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++) {
if (i != 1) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
}
IConstantPoolEntry constantPoolEntry = constantPool.decodeEntry(i);
String[] methodDescription;
int kind = constantPool.getEntryKind(i);
switch (kind) {
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 :
methodDescription = methodDescription(constantPoolEntry);
buffer.append(
Messages.bind(Messages.disassembler_constantpool_interfacemethodref,
new String[] {
Integer.toString(i),
Integer.toString(constantPoolEntry.getClassIndex()),
Integer.toString(constantPoolEntry.getNameAndTypeIndex()),
methodDescription[0], methodDescription[1], methodDescription[2]}));
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 :
methodDescription = methodDescription(constantPoolEntry);
buffer.append(
Messages.bind(Messages.disassembler_constantpool_methodref,
new String[] {
Integer.toString(i),
Integer.toString(constantPoolEntry.getClassIndex()),
Integer.toString(constantPoolEntry.getNameAndTypeIndex()),
methodDescription[0], methodDescription[1], methodDescription[2]}));
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()),
decodeStringValue(constantPoolEntry.getStringValue())}));
break;
case IConstantPoolConstant.CONSTANT_Utf8 :
buffer.append(
Messages.bind(Messages.disassembler_constantpool_utf8,
new String[] {
Integer.toString(i),
decodeStringValue(new String(constantPoolEntry.getUtf8Value()))}));
break;
case IConstantPoolConstant.CONSTANT_MethodHandle :
IConstantPoolEntry2 entry2 = (IConstantPoolEntry2) constantPoolEntry;
buffer.append(
Messages.bind(Messages.disassembler_constantpool_methodhandle,
new String[] {
Integer.toString(i),
getReferenceKind(entry2.getReferenceKind()),
Integer.toString(entry2.getReferenceIndex()),
}));
break;
case IConstantPoolConstant.CONSTANT_MethodType :
entry2 = (IConstantPoolEntry2) constantPoolEntry;
buffer.append(
Messages.bind(Messages.disassembler_constantpool_methodtype,
new String[] {
Integer.toString(i),
Integer.toString(entry2.getDescriptorIndex()),
String.valueOf(entry2.getMethodDescriptor()),
}));
break;
case IConstantPoolConstant.CONSTANT_InvokeDynamic :
entry2 = (IConstantPoolEntry2) constantPoolEntry;
buffer.append(
Messages.bind(Messages.disassembler_constantpool_invokedynamic,
new String[] {
Integer.toString(i),
Integer.toString(entry2.getBootstrapMethodAttributeIndex()),
Integer.toString(entry2.getNameAndTypeIndex()),
new String(constantPoolEntry.getMethodName()),
new String(constantPoolEntry.getMethodDescriptor())
}));
break;
case IConstantPoolConstant.CONSTANT_Dynamic :
entry2 = (IConstantPoolEntry2) constantPoolEntry;
buffer.append(
Messages.bind(Messages.disassembler_constantpool_dynamic,
new String[] {
Integer.toString(i),
Integer.toString(entry2.getBootstrapMethodAttributeIndex()),
Integer.toString(entry2.getNameAndTypeIndex()),
new String(constantPoolEntry.getFieldName()),
new String(constantPoolEntry.getFieldDescriptor())
}));
break;
}
}
}
private String getReferenceKind(int referenceKind) {
String message = null;
switch(referenceKind) {
case IConstantPoolConstant.METHOD_TYPE_REF_GetField :
message = Messages.disassembler_method_type_ref_getfield;
break;
case IConstantPoolConstant.METHOD_TYPE_REF_GetStatic :
message = Messages.disassembler_method_type_ref_getstatic;
break;
case IConstantPoolConstant.METHOD_TYPE_REF_PutField :
message = Messages.disassembler_method_type_ref_putfield;
break;
case IConstantPoolConstant.METHOD_TYPE_REF_PutStatic :
message = Messages.disassembler_method_type_ref_putstatic;
break;
case IConstantPoolConstant.METHOD_TYPE_REF_InvokeInterface :
message = Messages.disassembler_method_type_ref_invokeinterface;
break;
case IConstantPoolConstant.METHOD_TYPE_REF_InvokeSpecial :
message = Messages.disassembler_method_type_ref_invokespecial;
break;
case IConstantPoolConstant.METHOD_TYPE_REF_InvokeStatic :
message = Messages.disassembler_method_type_ref_invokestatic;
break;
case IConstantPoolConstant.METHOD_TYPE_REF_InvokeVirtual :
message = Messages.disassembler_method_type_ref_invokevirtual;
break;
default :
message = Messages.disassembler_method_type_ref_newinvokespecial;
}
return Messages.bind(message, new String[] { Integer.toString(referenceKind) });
}
private void disassemble(IEnclosingMethodAttribute enclosingMethodAttribute, StringBuilder 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());
if (enclosingMethodAttribute.getMethodNameAndTypeIndex() != 0) {
buffer
.append(".")//$NON-NLS-1$
.append(enclosingMethodAttribute.getMethodName())
.append(enclosingMethodAttribute.getMethodDescriptor());
}
}
private void disassembleEnumConstants(IFieldInfo fieldInfo, StringBuilder buffer, String lineSeparator, int tabNumber, char[][] argumentTypes, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber);
final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
// disassemble compact version of annotations
if (runtimeInvisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
buffer.append(new String(fieldInfo.getName()));
buffer.append('(');
final int length = argumentTypes.length;
if (length != 0) {
// insert default value for corresponding argument types
for (int i = 0; i < length; i++) {
if (i != 0) {
buffer.append(Messages.disassembler_comma);
}
final char[] type = argumentTypes[i];
switch(type.length) {
case 1 :
switch(type[0]) {
case 'B' :
case 'I' :
case 'J' :
case 'D' :
case 'F' :
case 'S' :
buffer.append('0');
break;
case 'Z' :
buffer.append("false"); //$NON-NLS-1$
break;
case 'C' :
buffer.append("\' \'"); //$NON-NLS-1$
break;
}
break;
default :
buffer.append("null"); //$NON-NLS-1$
}
}
}
buffer.append(')').append(Messages.disassembler_comma);
}
/**
* Disassemble a field info
*/
private void disassemble(IFieldInfo fieldInfo, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber);
final char[] fieldDescriptor = fieldInfo.getDescriptor();
final ISignatureAttribute signatureAttribute = (ISignatureAttribute) Util.getAttribute(fieldInfo, IAttributeNamesConstants.SIGNATURE);
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);
}
}
final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
final IClassFileAttribute runtimeVisibleTypeAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
final IClassFileAttribute runtimeInvisibleTypeAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
if (checkMode(mode, DETAILED)) {
// disassemble compact version of annotations
if (runtimeInvisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
writeNewLine(buffer, lineSeparator, tabNumber);
}
}
if (checkMode(mode, WORKING_COPY)) {
decodeModifiersForFieldForWorkingCopy(buffer, fieldInfo.getAccessFlags());
if (signatureAttribute != null) {
buffer.append(returnClassName(getSignatureForField(signatureAttribute.getSignature()), '.', mode));
} else {
buffer.append(returnClassName(getSignatureForField(fieldDescriptor), '.', mode));
}
} else {
decodeModifiersForField(buffer, fieldInfo.getAccessFlags());
if (fieldInfo.isSynthetic()) {
buffer.append("synthetic"); //$NON-NLS-1$
buffer.append(Messages.disassembler_space);
}
buffer.append(returnClassName(getSignatureForField(fieldDescriptor), '.', mode));
}
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 :
final double doubleValue = constantPoolEntry.getDoubleValue();
if (checkMode(mode, ClassFileBytesDisassembler.WORKING_COPY)) {
if (doubleValue == Double.POSITIVE_INFINITY) {
buffer.append("1.0 / 0.0"); //$NON-NLS-1$
} else if (doubleValue == Double.NEGATIVE_INFINITY) {
buffer.append("-1.0 / 0.0"); //$NON-NLS-1$
} else {
buffer.append(constantPoolEntry.getDoubleValue());
}
} else {
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
&& attribute != runtimeInvisibleTypeAnnotationsAttribute
&& attribute != runtimeVisibleTypeAnnotationsAttribute
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
disassemble(attribute, buffer, lineSeparator, tabNumber, mode);
}
}
}
if (runtimeVisibleAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeInvisibleAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeVisibleTypeAnnotationsAttribute != null) {
disassemble((IRuntimeVisibleTypeAnnotationsAttribute) runtimeVisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
if (runtimeInvisibleTypeAnnotationsAttribute != null) {
disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) runtimeInvisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
}
}
}
private void disassemble(IInnerClassesAttribute innerClassesAttribute, StringBuilder 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; i++) {
if (i != 0) {
buffer.append(Messages.disassembler_comma);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
}
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, true);
buffer
.append(Messages.disassembler_closeinnerclassentry);
}
}
private void disassemble(IBootstrapMethodsAttribute bootstrapMethodsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, IConstantPool constantPool) {
writeNewLine(buffer, lineSeparator, tabNumber);
buffer.append(Messages.disassembler_bootstrapmethodattributesheader);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
IBootstrapMethodsEntry[] entries = bootstrapMethodsAttribute.getBootstrapMethods();
int length = entries.length;
for (int i = 0; i < length; i++) {
if (i != 0) {
buffer.append(Messages.disassembler_comma);
writeNewLine(buffer, lineSeparator, tabNumber + 1);
}
IBootstrapMethodsEntry entry = entries[i];
String[] argumentsName = bootstrapArgumentsDescription(entry, constantPool);
buffer.append(
Messages.bind(
Messages.disassembler_bootstrapmethodentry,
new String[] {
Integer.toString(i),
Integer.toString(entry.getBootstrapMethodReference()),
bootstrapMethodDescription(entry, constantPool),
getArguments(entry.getBootstrapArguments(), argumentsName)
}));
}
}
private String getArguments(int[] arguments, String[] argumentsName) {
StringBuilder buffer = new StringBuilder();
for (int i = 0, max = arguments.length; i < max; i++) {
buffer.append(
Messages.bind(
Messages.disassembler_bootstrapmethodentry_argument,
new String[] {
Integer.toString(arguments[i]),
argumentsName[i]
}));
if (i != arguments.length - 1)
buffer.append("\n\t\t"); //$NON-NLS-1$
}
return String.valueOf(buffer);
}
private void disassemble(int index, IParameterAnnotation parameterAnnotation, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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, mode);
}
}
private void disassemble(IRuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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, mode);
}
}
private void disassemble(IRuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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, mode);
}
}
private void disassemble(IRuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_runtimeinvisibletypeannotationsattributeheader);
IExtendedAnnotation[] extendedAnnotations = runtimeInvisibleTypeAnnotationsAttribute.getExtendedAnnotations();
for (int i = 0, max = extendedAnnotations.length; i < max; i++) {
disassemble(extendedAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode);
}
}
private void disassemble(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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, mode);
}
}
private void disassemble(IRuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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, mode);
}
}
private void disassemble(IRuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
writeNewLine(buffer, lineSeparator, tabNumber + 1);
buffer.append(Messages.disassembler_runtimevisibletypeannotationsattributeheader);
IExtendedAnnotation[] extendedAnnotations = runtimeVisibleTypeAnnotationsAttribute.getExtendedAnnotations();
for (int i = 0, max = extendedAnnotations.length; i < max; i++) {
disassemble(extendedAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode);
}
}
private String disassemble(IVerificationTypeInfo[] infos, int mode) {
StringBuilder buffer = new StringBuilder();
buffer.append('{');
for (int i = 0, max = infos.length; i < max; i++) {
if(i != 0) {
buffer
.append(Messages.disassembler_comma)
.append(Messages.disassembler_space);
}
switch(infos[i].getTag()) {
case IVerificationTypeInfo.ITEM_DOUBLE :
buffer.append("double"); //$NON-NLS-1$
break;
case IVerificationTypeInfo.ITEM_FLOAT :
buffer.append("float"); //$NON-NLS-1$
break;
case IVerificationTypeInfo.ITEM_INTEGER :
buffer.append("int"); //$NON-NLS-1$
break;
case IVerificationTypeInfo.ITEM_LONG :
buffer.append("long"); //$NON-NLS-1$
break;
case IVerificationTypeInfo.ITEM_NULL :
buffer.append("null"); //$NON-NLS-1$
break;
case IVerificationTypeInfo.ITEM_OBJECT :
char[] classTypeName = infos[i].getClassTypeName();
CharOperation.replace(classTypeName, '/', '.');
if (classTypeName.length > 0 && classTypeName[0] == '[') { // length check for resilience
classTypeName = Signature.toCharArray(classTypeName);
}
buffer.append(returnClassName(classTypeName, '.', mode));
break;
case IVerificationTypeInfo.ITEM_TOP :
buffer.append("_"); //$NON-NLS-1$
break;
case IVerificationTypeInfo.ITEM_UNINITIALIZED :
buffer.append("uninitialized("); //$NON-NLS-1$
buffer.append(infos[i].getOffset());
buffer.append(')');
break;
case IVerificationTypeInfo.ITEM_UNINITIALIZED_THIS :
buffer.append("uninitialized_this"); //$NON-NLS-1$
}
}
buffer.append('}');
return String.valueOf(buffer);
}
private void disassembleAsModifier(IAnnotation annotation, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.');
buffer.append('@').append(returnClassName(Signature.toCharArray(typeName), '.', mode));
final IAnnotationComponent[] components = annotation.getComponents();
final int length = components.length;
if (length != 0) {
buffer.append('(');
for (int i = 0; i < length; i++) {
if (i > 0) {
buffer.append(',');
writeNewLine(buffer, lineSeparator, tabNumber);
}
disassembleAsModifier(components[i], buffer, lineSeparator, tabNumber + 1, mode);
}
buffer.append(')');
}
}
private void disassembleAsModifier(IAnnotationComponent annotationComponent, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
buffer.append(annotationComponent.getComponentName()).append('=');
disassembleAsModifier(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1, mode);
}
private void disassembleAsModifier(IAnnotationComponentValue annotationComponentValue, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
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:
StringBuilder temp = new StringBuilder();
switch(annotationComponentValue.getTag()) {
case IAnnotationComponentValue.CHAR_TAG :
temp.append('\'');
escapeChar(temp, (char) constantPoolEntry.getIntegerValue());
temp.append('\'');
break;
case IAnnotationComponentValue.BOOLEAN_TAG :
temp.append(constantPoolEntry.getIntegerValue() == 1 ? "true" : "false");//$NON-NLS-1$//$NON-NLS-2$
break;
case IAnnotationComponentValue.BYTE_TAG :
temp.append("(byte) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$
break;
case IAnnotationComponentValue.SHORT_TAG :
temp.append("(short) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$
break;
case IAnnotationComponentValue.INTEGER_TAG :
temp.append("(int) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$
}
value = String.valueOf(temp);
break;
case IConstantPoolConstant.CONSTANT_Utf8:
value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$
}
buffer.append(value);
break;
case IAnnotationComponentValue.ENUM_TAG:
final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.');
final char[] constantName = annotationComponentValue.getEnumConstantName();
buffer.append(returnClassName(Signature.toCharArray(typeName), '.', mode)).append('.').append(constantName);
break;
case IAnnotationComponentValue.CLASS_TAG:
constantPoolEntry = annotationComponentValue.getClassInfo();
final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.');
buffer.append(returnClassName(Signature.toCharArray(className), '.', mode));
break;
case IAnnotationComponentValue.ANNOTATION_TAG:
IAnnotation annotation = annotationComponentValue.getAnnotationValue();
disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1, mode);
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, mode);
}
buffer.append('}');
}
}
private void disassembleAsModifier(IAnnotationDefaultAttribute annotationDefaultAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
IAnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue();
disassembleAsModifier(componentValue, buffer, lineSeparator, tabNumber + 1, mode);
}
private void disassembleAsModifier(IRuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
IAnnotation[] annotations = runtimeInvisibleAnnotationsAttribute.getAnnotations();
for (int i = 0, max = annotations.length; i < max; i++) {
disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode);
}
}
private void disassembleAsModifier(IParameterAnnotation[] parameterAnnotations, StringBuilder buffer, int index, String lineSeparator, int tabNumber, int mode) {
if (parameterAnnotations.length > index) {
disassembleAsModifier(parameterAnnotations[index], buffer, lineSeparator, tabNumber + 1, mode);
}
}
private void disassembleAsModifier(IParameterAnnotation parameterAnnotation, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
if (parameterAnnotation == null) return;
IAnnotation[] annotations = parameterAnnotation.getAnnotations();
for (int i = 0, max = annotations.length; i < max; i++) {
if (i > 0) {
buffer.append(' ');
}
disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode);
}
}
private void disassembleAsModifier(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuilder buffer, String lineSeparator, int tabNumber, int mode) {
IAnnotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations();
for (int i = 0, max = annotations.length; i < max; i++) {
if (i > 0) {
writeNewLine(buffer, lineSeparator, tabNumber);
}
disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode);
}
}
private void disassembleTypeMembers(IClassFileReader classFileReader, char[] className, StringBuilder buffer, String lineSeparator, int tabNumber, int mode, boolean isEnum) {
IFieldInfo[] fields = classFileReader.getFieldInfos();
if (isEnum && checkMode(mode, WORKING_COPY)) {
int index = 0;
final int fieldsLength = fields.length;
IMethodInfo[] methods = classFileReader.getMethodInfos();
char[][] constructorArguments = getConstructorArgumentsForEnum(methods);
enumConstantLoop: for (; index < fieldsLength; index++) {
final IFieldInfo fieldInfo = fields[index];
final int accessFlags = fieldInfo.getAccessFlags();
if ((accessFlags & IModifierConstants.ACC_ENUM) != 0) {
writeNewLine(buffer, lineSeparator, tabNumber);
disassembleEnumConstants(fields[index], buffer, lineSeparator, tabNumber, constructorArguments, mode);
} else {
break enumConstantLoop;
}
}
buffer.append(';');
boolean foundSyntheticField = false;
fieldLoop: for (; index < fieldsLength; index++) {
if (!foundSyntheticField && CharOperation.equals(TypeConstants.SYNTHETIC_ENUM_VALUES, fields[index].getName())) {
foundSyntheticField = true;
continue fieldLoop;
}
writeNewLine(buffer, lineSeparator, tabNumber);
disassemble(fields[index], buffer, lineSeparator, tabNumber, mode);
}
methodLoop: for (int i = 0, max = methods.length; i < max; i++) {
final IMethodInfo methodInfo = methods[i];
if (CharOperation.equals(methodInfo.getName(), TypeConstants.VALUES)) {
final char[] descriptor = methodInfo.getDescriptor();
CharOperation.replace(descriptor, '/', '.');
if (Signature.getParameterCount(descriptor) == 0) {
if (CharOperation.equals(returnClassName(Signature.getReturnType(descriptor), '.', mode),
CharOperation.concat(new char[] {'[', 'L'}, className, new char[] {';'}))) {
continue methodLoop;
}
}
} else if (CharOperation.equals(methodInfo.getName(), TypeConstants.VALUEOF)) {
final char[] descriptor = methodInfo.getDescriptor();
CharOperation.replace(descriptor, '/', '.');
final char[][] parameterTypes = Signature.getParameterTypes(descriptor);
if (parameterTypes.length == 1
&& CharOperation.equals(parameterTypes[0], "Ljava.lang.String;".toCharArray())) { //$NON-NLS-1$
if (CharOperation.equals(returnClassName(Signature.getReturnType(descriptor), '.', mode),
CharOperation.concat('L', className, ';'))) {
continue methodLoop;
}
}
} else if (methodInfo.isClinit() || methodInfo.isSynthetic()) {
continue methodLoop;
} else if (methodInfo.isConstructor()) {
writeNewLine(buffer, lineSeparator, tabNumber);
disassembleEnumConstructor(classFileReader, className, methodInfo, buffer, lineSeparator, tabNumber, mode);
} else {
writeNewLine(buffer, lineSeparator, tabNumber);
disassemble(classFileReader, className, methodInfo, buffer, lineSeparator, tabNumber, mode);
}
}
} else {
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, className, methods[i], buffer, lineSeparator, tabNumber, mode);
}
}
}
private char[][] getConstructorArgumentsForEnum(final IMethodInfo[] methods) {
loop: for (int i = 0, max = methods.length; i < max; i++) {
IMethodInfo methodInfo = methods[i];
if (methodInfo.isConstructor()) {
char[][] parameterTypes = Signature.getParameterTypes(methodInfo.getDescriptor());
final int length = parameterTypes.length;
if (length >= 2) {
return CharOperation.subarray(parameterTypes, 2, length);
}
} else {
continue loop;
}
}
return null;
}
private final void dumpTab(int tabNumber, StringBuilder buffer) {
for (int i = 0; i < tabNumber; i++) {
buffer.append(Messages.disassembler_indentation);
}
}
private final String dumpNewLineWithTabs(String lineSeparator, int tabNumber) {
StringBuilder buffer = new StringBuilder();
writeNewLine(buffer, lineSeparator, tabNumber);
return String.valueOf(buffer);
}
/**
* @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#getDescription()
*/
@Override
public String getDescription() {
return Messages.disassembler_description;
}
private char[][] getParameterNames(char[] methodDescriptor, ICodeAttribute codeAttribute, IMethodParametersAttribute parametersAttribute, int accessFlags) {
int paramCount = Signature.getParameterCount(methodDescriptor);
char[][] parameterNames = new char[paramCount][];
// check if the code attribute has debug info for this method
if (parametersAttribute != null) {
int parameterCount = parametersAttribute.getMethodParameterLength();
for (int i = 0; i < paramCount; i++) {
if (i < parameterCount && parametersAttribute.getParameterName(i) != null) {
parameterNames[i] = parametersAttribute.getParameterName(i);
} else {
parameterNames[i] = Messages.disassembler_anonymousparametername.toCharArray();
}
}
} else if (codeAttribute != null) {
ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute();
if (localVariableAttribute != null) {
ILocalVariableTableEntry[] entries = localVariableAttribute.getLocalVariableTable();
final int startingIndex = (accessFlags & IModifierConstants.ACC_STATIC) != 0 ? 0 : 1;
for (int i = 0; i < paramCount; i++) {
ILocalVariableTableEntry searchedEntry = getEntryFor(getLocalIndex(startingIndex, i, methodDescriptor), entries);
if (searchedEntry != null) {
parameterNames[i] = searchedEntry.getName();
} else {
parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray());
}
}
} else {
for (int i = 0; i < paramCount; i++) {
parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray());
}
}
} else {
for (int i = 0; i < paramCount; i++) {
parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray());
}
}
return parameterNames;
}
private int getLocalIndex(final int startingSlot, final int index, final char[] methodDescriptor) {
int slot = startingSlot;
final char[][] types = Signature.getParameterTypes(methodDescriptor);
for (int i = 0; i < index; i++) {
final char[] type = types[i];
switch(type.length) {
case 1 :
switch(type[0]) {
case 'D' :
case 'J' :
slot += 2;
break;
default :
slot++;
}
break;
default :
slot++;
}
}
return slot;
}
private ILocalVariableTableEntry getEntryFor(final int index, final ILocalVariableTableEntry[] entries) {
for (int i = 0, max = entries.length; i < max; i++) {
ILocalVariableTableEntry entry = entries[i];
if (index == entry.getIndex()) {
return entry;
}
}
return null;
}
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 char[] getSignatureForComponent(char[] componentDescriptor) {
char[] newComponentDescriptor = CharOperation.replaceOnCopy(componentDescriptor, '/', '.');
newComponentDescriptor = CharOperation.replaceOnCopy(newComponentDescriptor, '$', '%');
char[] componentDescriptorSignature = Signature.toCharArray(newComponentDescriptor);
CharOperation.replace(componentDescriptorSignature, '%', '$');
return componentDescriptorSignature;
}
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 boolean isCompact(int mode) {
return (mode & ClassFileBytesDisassembler.COMPACT) != 0;
}
private char[] returnClassName(char[] classInfoName, char separator, int mode) {
if (classInfoName.length == 0) {
return CharOperation.NO_CHAR;
} else if (isCompact(mode)) {
int lastIndexOfSlash = CharOperation.lastIndexOf(separator, classInfoName);
if (lastIndexOfSlash != -1) {
return CharOperation.subarray(classInfoName, lastIndexOfSlash + 1, classInfoName.length);
}
}
return classInfoName;
}
private void writeNewLine(StringBuilder buffer, String lineSeparator, int tabNumber) {
buffer.append(lineSeparator);
dumpTab(tabNumber, buffer);
}
private String toTypePathString(int[][] typepath) {
StringBuilder buffer = new StringBuilder();
buffer.append('[');
for (int i = 0, max = typepath.length; i < max; i++) {
int[] typepathElement = typepath[i];
if (i > 0) {
buffer.append(',').append(' ');
}
switch (typepathElement[0]) {
case IExtendedAnnotationConstants.TYPE_PATH_DEEPER_IN_ARRAY:
buffer.append(Messages.disassembler_extendedannotation_typepath_array);
break;
case IExtendedAnnotationConstants.TYPE_PATH_DEEPER_IN_INNER_TYPE:
buffer.append(Messages.disassembler_extendedannotation_typepath_innertype);
break;
case IExtendedAnnotationConstants.TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND:
buffer.append(Messages.disassembler_extendedannotation_typepath_wildcard);
break;
case IExtendedAnnotationConstants.TYPE_PATH_TYPE_ARGUMENT_INDEX:
buffer.append(
Messages.bind(Messages.disassembler_extendedannotation_typepath_typeargument,
new String[] {
Integer.toString(typepathElement[1])
}));
break;
default:
throw new IllegalStateException("Unrecognized type_path_kind: "+typepathElement[0]); //$NON-NLS-1$
}
}
buffer.append(']');
return String.valueOf(buffer);
}
}