1 /*******************************************************************************
2  * Copyright (c) 2009, 2017 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.equinox.p2.internal.repository.comparator.java;
15 
16 import java.util.Arrays;
17 import org.eclipse.osgi.util.NLS;
18 
19 /**
20  * Disassembler of .class files. It generates an output in the Writer that looks close to
21  * the javap output.
22  */
23 public class Disassembler {
24 	/**
25 	 * The mode is the detailed mode to disassemble ClassFileReader. It returns the magic
26 	 * numbers, the version numbers and field and method descriptors.
27 	 */
28 	public final static int DETAILED = 1;
29 
30 	/**
31 	 * This mode is used to compact the class name to a simple name instead of a qualified name.
32 	 * @since 3.1
33 	 */
34 	public final static int COMPACT = 8;
35 
36 	private static final char[] ANY_EXCEPTION = Messages.classfileformat_anyexceptionhandler.toCharArray();
37 	private static final String VERSION_UNKNOWN = Messages.classfileformat_versionUnknown;
38 
appendModifier(StringBuffer buffer, int accessFlags, int modifierConstant, String modifier, boolean firstModifier)39 	private boolean appendModifier(StringBuffer buffer, int accessFlags, int modifierConstant, String modifier, boolean firstModifier) {
40 		if ((accessFlags & modifierConstant) != 0) {
41 			if (!firstModifier) {
42 				buffer.append(Messages.disassembler_space);
43 			}
44 			if (firstModifier) {
45 				firstModifier = false;
46 			}
47 			buffer.append(modifier);
48 		}
49 		return firstModifier;
50 	}
51 
decodeModifiers(StringBuffer buffer, int accessFlags, int[] checkBits)52 	private void decodeModifiers(StringBuffer buffer, int accessFlags, int[] checkBits) {
53 		decodeModifiers(buffer, accessFlags, false, false, checkBits);
54 	}
55 
decodeModifiers(StringBuffer buffer, int accessFlags, boolean printDefault, boolean asBridge, int[] checkBits)56 	private void decodeModifiers(StringBuffer buffer, int accessFlags, boolean printDefault, boolean asBridge, int[] checkBits) {
57 		if (checkBits == null)
58 			return;
59 		boolean firstModifier = true;
60 		for (int checkBit : checkBits) {
61 			switch (checkBit) {
62 				case IModifierConstants.ACC_PUBLIC :
63 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
64 					break;
65 				case IModifierConstants.ACC_PROTECTED :
66 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
67 					break;
68 				case IModifierConstants.ACC_PRIVATE :
69 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
70 					break;
71 				case IModifierConstants.ACC_ABSTRACT :
72 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
73 					break;
74 				case IModifierConstants.ACC_STATIC :
75 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
76 					break;
77 				case IModifierConstants.ACC_FINAL :
78 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
79 					break;
80 				case IModifierConstants.ACC_SYNCHRONIZED :
81 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNCHRONIZED, "synchronized", firstModifier); //$NON-NLS-1$
82 					break;
83 				case IModifierConstants.ACC_NATIVE :
84 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_NATIVE, "native", firstModifier); //$NON-NLS-1$
85 					break;
86 				case IModifierConstants.ACC_STRICT :
87 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STRICT, "strictfp", firstModifier); //$NON-NLS-1$
88 					break;
89 				case IModifierConstants.ACC_TRANSIENT :
90 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_TRANSIENT, "transient", firstModifier); //$NON-NLS-1$
91 					break;
92 				case IModifierConstants.ACC_VOLATILE :
93 					// case IModifierConstants.ACC_BRIDGE :
94 					if (asBridge) {
95 						firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_BRIDGE, "bridge", firstModifier); //$NON-NLS-1$
96 					} else {
97 						firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_VOLATILE, "volatile", firstModifier); //$NON-NLS-1$
98 					}
99 					break;
100 				case IModifierConstants.ACC_ENUM :
101 					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ENUM, "enum", firstModifier); //$NON-NLS-1$
102 					break;
103 			}
104 		}
105 		if (!firstModifier) {
106 			if (!printDefault)
107 				buffer.append(Messages.disassembler_space);
108 		} else if (printDefault) {
109 			// no modifier: package default visibility
110 			buffer.append("default"); //$NON-NLS-1$
111 		}
112 	}
113 
decodeModifiersForField(StringBuffer buffer, int accessFlags)114 	private void decodeModifiersForField(StringBuffer buffer, int accessFlags) {
115 		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});
116 	}
117 
decodeModifiersForInnerClasses(StringBuffer buffer, int accessFlags, boolean printDefault)118 	private final void decodeModifiersForInnerClasses(StringBuffer buffer, int accessFlags, boolean printDefault) {
119 		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,});
120 	}
121 
decodeModifiersForMethod(StringBuffer buffer, int accessFlags)122 	private final void decodeModifiersForMethod(StringBuffer buffer, int accessFlags) {
123 		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,});
124 	}
125 
decodeModifiersForType(StringBuffer buffer, int accessFlags)126 	private final void decodeModifiersForType(StringBuffer buffer, int accessFlags) {
127 		decodeModifiers(buffer, accessFlags, new int[] {IModifierConstants.ACC_PUBLIC, IModifierConstants.ACC_ABSTRACT, IModifierConstants.ACC_FINAL,});
128 	}
129 
escapeString(String s)130 	public static String escapeString(String s) {
131 		StringBuilder buffer = new StringBuilder();
132 		for (int i = 0, max = s.length(); i < max; i++) {
133 			char c = s.charAt(i);
134 			switch (c) {
135 				case '\b' :
136 					buffer.append("\\b"); //$NON-NLS-1$
137 					break;
138 				case '\t' :
139 					buffer.append("\\t"); //$NON-NLS-1$
140 					break;
141 				case '\n' :
142 					buffer.append("\\n"); //$NON-NLS-1$
143 					break;
144 				case '\f' :
145 					buffer.append("\\f"); //$NON-NLS-1$
146 					break;
147 				case '\r' :
148 					buffer.append("\\r"); //$NON-NLS-1$
149 					break;
150 				case '\0' :
151 					buffer.append("\\0"); //$NON-NLS-1$
152 					break;
153 				case '\1' :
154 					buffer.append("\\1"); //$NON-NLS-1$
155 					break;
156 				case '\2' :
157 					buffer.append("\\2"); //$NON-NLS-1$
158 					break;
159 				case '\3' :
160 					buffer.append("\\3"); //$NON-NLS-1$
161 					break;
162 				case '\4' :
163 					buffer.append("\\4"); //$NON-NLS-1$
164 					break;
165 				case '\5' :
166 					buffer.append("\\5"); //$NON-NLS-1$
167 					break;
168 				case '\6' :
169 					buffer.append("\\6"); //$NON-NLS-1$
170 					break;
171 				case '\7' :
172 					buffer.append("\\7"); //$NON-NLS-1$
173 					break;
174 				default :
175 					buffer.append(c);
176 			}
177 		}
178 		return buffer.toString();
179 	}
180 
decodeStringValue(char[] chars)181 	static String decodeStringValue(char[] chars) {
182 		StringBuilder buffer = new StringBuilder();
183 		for (char c : chars) {
184 			switch (c) {
185 				case '\b' :
186 					buffer.append("\\b"); //$NON-NLS-1$
187 					break;
188 				case '\t' :
189 					buffer.append("\\t"); //$NON-NLS-1$
190 					break;
191 				case '\n' :
192 					buffer.append("\\n"); //$NON-NLS-1$
193 					break;
194 				case '\f' :
195 					buffer.append("\\f"); //$NON-NLS-1$
196 					break;
197 				case '\r' :
198 					buffer.append("\\r"); //$NON-NLS-1$
199 					break;
200 				case '\0' :
201 					buffer.append("\\0"); //$NON-NLS-1$
202 					break;
203 				case '\1' :
204 					buffer.append("\\1"); //$NON-NLS-1$
205 					break;
206 				case '\2' :
207 					buffer.append("\\2"); //$NON-NLS-1$
208 					break;
209 				case '\3' :
210 					buffer.append("\\3"); //$NON-NLS-1$
211 					break;
212 				case '\4' :
213 					buffer.append("\\4"); //$NON-NLS-1$
214 					break;
215 				case '\5' :
216 					buffer.append("\\5"); //$NON-NLS-1$
217 					break;
218 				case '\6' :
219 					buffer.append("\\6"); //$NON-NLS-1$
220 					break;
221 				case '\7' :
222 					buffer.append("\\7"); //$NON-NLS-1$
223 					break;
224 				default :
225 					buffer.append(c);
226 			}
227 		}
228 		return buffer.toString();
229 	}
230 
decodeStringValue(String s)231 	static String decodeStringValue(String s) {
232 		return decodeStringValue(s.toCharArray());
233 	}
234 
235 	/*
236 	 * @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String, int)
237 	 */
disassemble(byte[] classFileBytes, String lineSeparator, int mode)238 	public String disassemble(byte[] classFileBytes, String lineSeparator, int mode) throws ClassFormatException {
239 		try {
240 			return disassemble(new ClassFileReader(classFileBytes, ClassFileReader.ALL), lineSeparator, mode);
241 		} catch (ArrayIndexOutOfBoundsException e) {
242 			throw new ClassFormatException(e.getMessage(), e);
243 		}
244 	}
245 
disassemble(Annotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)246 	private void disassemble(Annotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
247 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
248 		final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.');
249 		buffer.append(NLS.bind(Messages.disassembler_annotationentrystart, new String[] {new String(returnClassName(Signature.toCharArray(typeName), '.', mode))}));
250 		for (AnnotationComponent component : annotation.getComponents()) {
251 			disassemble(component, buffer, lineSeparator, tabNumber + 1, mode);
252 		}
253 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
254 		buffer.append(Messages.disassembler_annotationentryend);
255 	}
256 
disassemble(AnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)257 	private void disassemble(AnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
258 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
259 		buffer.append(NLS.bind(Messages.disassembler_annotationcomponent, new String[] {new String(annotationComponent.getComponentName())}));
260 		disassemble(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1, mode);
261 	}
262 
disassemble(AnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)263 	private void disassemble(AnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
264 		switch (annotationComponentValue.getTag()) {
265 			case AnnotationComponentValue.BYTE_TAG :
266 			case AnnotationComponentValue.CHAR_TAG :
267 			case AnnotationComponentValue.DOUBLE_TAG :
268 			case AnnotationComponentValue.FLOAT_TAG :
269 			case AnnotationComponentValue.INTEGER_TAG :
270 			case AnnotationComponentValue.LONG_TAG :
271 			case AnnotationComponentValue.SHORT_TAG :
272 			case AnnotationComponentValue.BOOLEAN_TAG :
273 			case AnnotationComponentValue.STRING_TAG :
274 				ConstantPoolEntry constantPoolEntry = annotationComponentValue.getConstantValue();
275 				String value = null;
276 				switch (constantPoolEntry.getKind()) {
277 					case ConstantPoolConstant.CONSTANT_Long :
278 						value = constantPoolEntry.getLongValue() + "L"; //$NON-NLS-1$
279 						break;
280 					case ConstantPoolConstant.CONSTANT_Float :
281 						value = constantPoolEntry.getFloatValue() + "f"; //$NON-NLS-1$
282 						break;
283 					case ConstantPoolConstant.CONSTANT_Double :
284 						value = Double.toString(constantPoolEntry.getDoubleValue());
285 						break;
286 					case ConstantPoolConstant.CONSTANT_Integer :
287 						switch (annotationComponentValue.getTag()) {
288 							case AnnotationComponentValue.CHAR_TAG :
289 								value = "'" + (char) constantPoolEntry.getIntegerValue() + "'"; //$NON-NLS-1$//$NON-NLS-2$
290 								break;
291 							case AnnotationComponentValue.BOOLEAN_TAG :
292 								value = constantPoolEntry.getIntegerValue() == 1 ? "true" : "false";//$NON-NLS-1$//$NON-NLS-2$
293 								break;
294 							case AnnotationComponentValue.BYTE_TAG :
295 								value = "(byte) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
296 								break;
297 							case AnnotationComponentValue.SHORT_TAG :
298 								value = "(short) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
299 								break;
300 							case AnnotationComponentValue.INTEGER_TAG :
301 								value = "(int) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
302 						}
303 						break;
304 					case ConstantPoolConstant.CONSTANT_Utf8 :
305 						value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$
306 				}
307 				buffer.append(NLS.bind(Messages.disassembler_annotationdefaultvalue, value));
308 				break;
309 			case AnnotationComponentValue.ENUM_TAG :
310 				final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.');
311 				final char[] constantName = annotationComponentValue.getEnumConstantName();
312 				buffer.append(NLS.bind(Messages.disassembler_annotationenumvalue, new String[] {new String(returnClassName(Signature.toCharArray(typeName), '.', mode)), new String(constantName)}));
313 				break;
314 			case AnnotationComponentValue.CLASS_TAG :
315 				constantPoolEntry = annotationComponentValue.getClassInfo();
316 				final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.');
317 				buffer.append(NLS.bind(Messages.disassembler_annotationclassvalue, new String[] {new String(returnClassName(Signature.toCharArray(className), '.', mode))}));
318 				break;
319 			case AnnotationComponentValue.ANNOTATION_TAG :
320 				buffer.append(Messages.disassembler_annotationannotationvalue);
321 				Annotation annotation = annotationComponentValue.getAnnotationValue();
322 				disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode);
323 				break;
324 			case AnnotationComponentValue.ARRAY_TAG:
325 				buffer.append(Messages.disassembler_annotationarrayvaluestart);
326 				final AnnotationComponentValue[] annotationComponentValues = annotationComponentValue
327 					.getAnnotationComponentValues();
328 				for (AnnotationComponentValue annotationComponentValue2 : annotationComponentValues) {
329 					writeNewLine(buffer, lineSeparator, tabNumber + 1);
330 					disassemble(annotationComponentValue2, buffer, lineSeparator, tabNumber + 1, mode);
331 				}
332 				writeNewLine(buffer, lineSeparator, tabNumber + 1);
333 				buffer.append(Messages.disassembler_annotationarrayvalueend);
334 		}
335 	}
336 
disassemble(AnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)337 	private void disassemble(AnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
338 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
339 		buffer.append(Messages.disassembler_annotationdefaultheader);
340 		AnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue();
341 		writeNewLine(buffer, lineSeparator, tabNumber + 2);
342 		disassemble(componentValue, buffer, lineSeparator, tabNumber + 1, mode);
343 	}
344 
345 	/**
346 	 * Disassemble a method info header
347 	 */
disassemble(ClassFileReader classFileReader, char[] className, MethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)348 	private void disassemble(ClassFileReader classFileReader, char[] className, MethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
349 		writeNewLine(buffer, lineSeparator, tabNumber);
350 		final CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
351 		final char[] methodDescriptor = methodInfo.getDescriptor();
352 		final SignatureAttribute signatureAttribute = (SignatureAttribute) Utility.getAttribute(methodInfo, AttributeNamesConstants.SIGNATURE);
353 		final ClassFileAttribute runtimeVisibleAnnotationsAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
354 		final ClassFileAttribute runtimeInvisibleAnnotationsAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
355 		final ClassFileAttribute runtimeVisibleParameterAnnotationsAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
356 		final ClassFileAttribute runtimeInvisibleParameterAnnotationsAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
357 		final ClassFileAttribute annotationDefaultAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.ANNOTATION_DEFAULT);
358 		if (checkMode(mode, DETAILED)) {
359 			buffer.append(NLS.bind(Messages.classfileformat_methoddescriptor, new String[] {new String(methodDescriptor)}));
360 			if (methodInfo.isDeprecated()) {
361 				buffer.append(Messages.disassembler_deprecated);
362 			}
363 			writeNewLine(buffer, lineSeparator, tabNumber);
364 			if (signatureAttribute != null) {
365 				buffer.append(NLS.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature())));
366 				writeNewLine(buffer, lineSeparator, tabNumber);
367 			}
368 			if (codeAttribute != null) {
369 				buffer.append(NLS.bind(Messages.classfileformat_stacksAndLocals, new String[] {Integer.toString(codeAttribute.getMaxStack()), Integer.toString(codeAttribute.getMaxLocals())}));
370 				writeNewLine(buffer, lineSeparator, tabNumber);
371 			}
372 			// disassemble compact version of annotations
373 			if (runtimeInvisibleAnnotationsAttribute != null) {
374 				disassembleAsModifier((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
375 				writeNewLine(buffer, lineSeparator, tabNumber);
376 			}
377 			if (runtimeVisibleAnnotationsAttribute != null) {
378 				disassembleAsModifier((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
379 				writeNewLine(buffer, lineSeparator, tabNumber);
380 			}
381 		}
382 		final int accessFlags = methodInfo.getAccessFlags();
383 		decodeModifiersForMethod(buffer, accessFlags);
384 		if (methodInfo.isSynthetic()) {
385 			buffer.append("synthetic"); //$NON-NLS-1$
386 			buffer.append(Messages.disassembler_space);
387 		}
388 		CharOperation.replace(methodDescriptor, '/', '.');
389 		final boolean isVarArgs = isVarArgs(methodInfo);
390 		char[] methodHeader = null;
391 		if (methodInfo.isConstructor()) {
392 			methodHeader = Signature.toCharArray(methodDescriptor, returnClassName(className, '.', COMPACT), null, !checkMode(mode, COMPACT), false, isVarArgs);
393 		} else if (methodInfo.isClinit()) {
394 			methodHeader = Messages.classfileformat_clinitname.toCharArray();
395 		} else {
396 			methodHeader = Signature.toCharArray(methodDescriptor, methodInfo.getName(), null, !checkMode(mode, COMPACT), true, isVarArgs);
397 		}
398 		if (checkMode(mode, DETAILED) && (runtimeInvisibleParameterAnnotationsAttribute != null || runtimeVisibleParameterAnnotationsAttribute != null)) {
399 			ParameterAnnotation[] invisibleParameterAnnotations = null;
400 			ParameterAnnotation[] visibleParameterAnnotations = null;
401 			int length = -1;
402 			if (runtimeInvisibleParameterAnnotationsAttribute != null) {
403 				RuntimeInvisibleParameterAnnotationsAttribute attribute = (RuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute;
404 				invisibleParameterAnnotations = attribute.getParameterAnnotations();
405 				length = invisibleParameterAnnotations.length;
406 			}
407 			if (runtimeVisibleParameterAnnotationsAttribute != null) {
408 				RuntimeVisibleParameterAnnotationsAttribute attribute = (RuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute;
409 				visibleParameterAnnotations = attribute.getParameterAnnotations();
410 				length = visibleParameterAnnotations.length;
411 			}
412 			int insertionPosition = CharOperation.indexOf('(', methodHeader) + 1;
413 			int start = 0;
414 			StringBuffer stringBuffer = new StringBuffer();
415 			stringBuffer.append(methodHeader, 0, insertionPosition);
416 			for (int i = 0; i < length; i++) {
417 				if (i > 0) {
418 					stringBuffer.append(' ');
419 				}
420 				int stringBufferSize = stringBuffer.length();
421 				if (runtimeVisibleParameterAnnotationsAttribute != null) {
422 					disassembleAsModifier((RuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute, stringBuffer, i, lineSeparator, tabNumber, mode);
423 				}
424 				if (runtimeInvisibleParameterAnnotationsAttribute != null) {
425 					if (stringBuffer.length() != stringBufferSize) {
426 						stringBuffer.append(' ');
427 						stringBufferSize = stringBuffer.length();
428 					}
429 					disassembleAsModifier((RuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute, stringBuffer, i, lineSeparator, tabNumber, mode);
430 				}
431 				if (i == 0 && stringBuffer.length() != stringBufferSize) {
432 					stringBuffer.append(' ');
433 				}
434 				start = insertionPosition;
435 				insertionPosition = CharOperation.indexOf(',', methodHeader, start + 1) + 1;
436 				if (insertionPosition == 0) {
437 					stringBuffer.append(methodHeader, start, methodHeader.length - start);
438 				} else {
439 					stringBuffer.append(methodHeader, start, insertionPosition - start);
440 				}
441 			}
442 			buffer.append(stringBuffer);
443 		} else {
444 			buffer.append(methodHeader);
445 		}
446 		ExceptionAttribute exceptionAttribute = methodInfo.getExceptionAttribute();
447 		if (exceptionAttribute != null) {
448 			buffer.append(" throws "); //$NON-NLS-1$
449 			char[][] exceptionNames = exceptionAttribute.getExceptionNames();
450 			int length = exceptionNames.length;
451 			for (int i = 0; i < length; i++) {
452 				if (i != 0) {
453 					buffer.append(Messages.disassembler_comma).append(Messages.disassembler_space);
454 				}
455 				char[] exceptionName = exceptionNames[i];
456 				CharOperation.replace(exceptionName, '/', '.');
457 				buffer.append(returnClassName(exceptionName, '.', mode));
458 			}
459 		}
460 		if (checkMode(mode, DETAILED)) {
461 			if (annotationDefaultAttribute != null) {
462 				buffer.append(" default "); //$NON-NLS-1$
463 				disassembleAsModifier((AnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode);
464 			}
465 		}
466 		buffer.append(Messages.disassembler_endofmethodheader);
467 
468 		if (checkMode(mode, DETAILED)) {
469 			if (codeAttribute != null) {
470 				disassemble(codeAttribute, methodDescriptor, (accessFlags & IModifierConstants.ACC_STATIC) != 0, buffer, lineSeparator, tabNumber, mode);
471 			}
472 			if (annotationDefaultAttribute != null) {
473 				disassemble((AnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode);
474 			}
475 			if (runtimeVisibleAnnotationsAttribute != null) {
476 				disassemble((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
477 			}
478 			if (runtimeInvisibleAnnotationsAttribute != null) {
479 				disassemble((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
480 			}
481 			if (runtimeVisibleParameterAnnotationsAttribute != null) {
482 				disassemble((RuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
483 			}
484 			if (runtimeInvisibleParameterAnnotationsAttribute != null) {
485 				disassemble((RuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
486 			}
487 		}
488 	}
489 
490 	/**
491 	 * Answers back the disassembled string of the ClassFileReader according to the
492 	 * mode.
493 	 * This is an output quite similar to the javap tool.
494 	 *
495 	 * @param classFileReader The classFileReader to be disassembled
496 	 * @param lineSeparator the line separator to use.
497 	 * @param mode the mode used to disassemble the ClassFileReader
498 	 *
499 	 * @return the disassembled string of the ClassFileReader according to the mode
500 	 */
disassemble(ClassFileReader classFileReader, String lineSeparator, int mode)501 	private String disassemble(ClassFileReader classFileReader, String lineSeparator, int mode) {
502 		if (classFileReader == null)
503 			return Utility.EMPTY_STRING;
504 		char[] className = classFileReader.getClassName();
505 		if (className == null) {
506 			// incomplete initialization. We cannot go further.
507 			return Utility.EMPTY_STRING;
508 		}
509 		className = CharOperation.replaceOnCopy(className, '/', '.');
510 		final int accessFlags = classFileReader.getAccessFlags();
511 		final boolean isEnum = (accessFlags & IModifierConstants.ACC_ENUM) != 0;
512 
513 		StringBuffer buffer = new StringBuffer();
514 		SourceFileAttribute sourceAttribute = classFileReader.getSourceFileAttribute();
515 		ClassFileAttribute classFileAttribute = Utility.getAttribute(classFileReader, AttributeNamesConstants.SIGNATURE);
516 		SignatureAttribute signatureAttribute = (SignatureAttribute) classFileAttribute;
517 		if (checkMode(mode, DETAILED)) {
518 			int minorVersion = classFileReader.getMinorVersion();
519 			int majorVersion = classFileReader.getMajorVersion();
520 			buffer.append(Messages.disassembler_begincommentline);
521 			if (sourceAttribute != null) {
522 				buffer.append(Messages.disassembler_sourceattributeheader);
523 				buffer.append(sourceAttribute.getSourceFileName());
524 			}
525 			String versionNumber = VERSION_UNKNOWN;
526 			if (minorVersion == 3 && majorVersion == 45) {
527 				versionNumber = IModifierConstants.VERSION_1_1;
528 			} else if (minorVersion == 0 && majorVersion == 46) {
529 				versionNumber = IModifierConstants.VERSION_1_2;
530 			} else if (minorVersion == 0 && majorVersion == 47) {
531 				versionNumber = IModifierConstants.VERSION_1_3;
532 			} else if (minorVersion == 0 && majorVersion == 48) {
533 				versionNumber = IModifierConstants.VERSION_1_4;
534 			} else if (minorVersion == 0 && majorVersion == 49) {
535 				versionNumber = IModifierConstants.VERSION_1_5;
536 			} else if (minorVersion == 0 && majorVersion == 50) {
537 				versionNumber = IModifierConstants.VERSION_1_6;
538 			} else if (minorVersion == 0 && majorVersion == 51) {
539 				versionNumber = IModifierConstants.VERSION_1_7;
540 			}
541 			buffer.append(NLS.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" : Utility.EMPTY_STRING)//$NON-NLS-1$
542 			}));
543 			writeNewLine(buffer, lineSeparator, 0);
544 			if (signatureAttribute != null) {
545 				buffer.append(NLS.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature())));
546 				writeNewLine(buffer, lineSeparator, 0);
547 			}
548 		}
549 
550 		InnerClassesAttribute innerClassesAttribute = classFileReader.getInnerClassesAttribute();
551 		ClassFileAttribute runtimeVisibleAnnotationsAttribute = Utility.getAttribute(classFileReader, AttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
552 		ClassFileAttribute runtimeInvisibleAnnotationsAttribute = Utility.getAttribute(classFileReader, AttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
553 
554 		if (checkMode(mode, DETAILED)) {
555 			// disassemble compact version of annotations
556 			if (runtimeInvisibleAnnotationsAttribute != null) {
557 				disassembleAsModifier((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode);
558 				writeNewLine(buffer, lineSeparator, 0);
559 			}
560 			if (runtimeVisibleAnnotationsAttribute != null) {
561 				disassembleAsModifier((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode);
562 				writeNewLine(buffer, lineSeparator, 0);
563 			}
564 		}
565 		boolean decoded = false;
566 		if (innerClassesAttribute != null) {
567 			// search the right entry
568 			InnerClassesAttributeEntry[] entries = innerClassesAttribute.getInnerClassAttributesEntries();
569 			for (InnerClassesAttributeEntry entry : entries) {
570 				char[] innerClassName = entry.getInnerClassName();
571 				if (innerClassName != null) {
572 					if (Arrays.equals(classFileReader.getClassName(), innerClassName)) {
573 						decodeModifiersForInnerClasses(buffer, entry.getAccessFlags(), false);
574 						decoded = true;
575 					}
576 				}
577 			}
578 		}
579 		if (!decoded) {
580 			decodeModifiersForType(buffer, accessFlags);
581 			if (isSynthetic(classFileReader)) {
582 				buffer.append("synthetic"); //$NON-NLS-1$
583 				buffer.append(Messages.disassembler_space);
584 			}
585 		}
586 
587 		final boolean isAnnotation = (accessFlags & IModifierConstants.ACC_ANNOTATION) != 0;
588 		boolean isInterface = false;
589 		if (isEnum) {
590 			buffer.append("enum "); //$NON-NLS-1$
591 		} else if (classFileReader.isClass()) {
592 			buffer.append("class "); //$NON-NLS-1$
593 		} else {
594 			if (isAnnotation) {
595 				buffer.append("@"); //$NON-NLS-1$
596 			}
597 			buffer.append("interface "); //$NON-NLS-1$
598 			isInterface = true;
599 		}
600 
601 		buffer.append(className);
602 
603 		char[] superclassName = classFileReader.getSuperclassName();
604 		if (superclassName != null) {
605 			CharOperation.replace(superclassName, '/', '.');
606 			if (!isJavaLangObject(superclassName) && !isEnum) {
607 				buffer.append(" extends "); //$NON-NLS-1$
608 				buffer.append(returnClassName(superclassName, '.', mode));
609 			}
610 		}
611 		if (!isAnnotation) {
612 			char[][] superclassInterfaces = classFileReader.getInterfaceNames();
613 			int length = superclassInterfaces.length;
614 			if (length != 0) {
615 				if (isInterface) {
616 					buffer.append(" extends "); //$NON-NLS-1$
617 				} else {
618 					buffer.append(" implements "); //$NON-NLS-1$
619 				}
620 				for (int i = 0; i < length; i++) {
621 					if (i != 0) {
622 						buffer.append(Messages.disassembler_comma).append(Messages.disassembler_space);
623 					}
624 					char[] superinterface = superclassInterfaces[i];
625 					CharOperation.replace(superinterface, '/', '.');
626 					buffer.append(returnClassName(superinterface, '.', mode));
627 				}
628 			}
629 		}
630 		buffer.append(Messages.disassembler_opentypedeclaration);
631 		disassembleTypeMembers(classFileReader, className, buffer, lineSeparator, 1, mode, isEnum);
632 		if (checkMode(mode, DETAILED)) {
633 			ClassFileAttribute[] attributes = classFileReader.getAttributes();
634 			int length = attributes.length;
635 			EnclosingMethodAttribute enclosingMethodAttribute = getEnclosingMethodAttribute(classFileReader);
636 			int remainingAttributesLength = length;
637 			if (innerClassesAttribute != null) {
638 				remainingAttributesLength--;
639 			}
640 			if (enclosingMethodAttribute != null) {
641 				remainingAttributesLength--;
642 			}
643 			if (sourceAttribute != null) {
644 				remainingAttributesLength--;
645 			}
646 			if (signatureAttribute != null) {
647 				remainingAttributesLength--;
648 			}
649 			if (innerClassesAttribute != null || enclosingMethodAttribute != null || remainingAttributesLength != 0) {
650 				writeNewLine(buffer, lineSeparator, 0);
651 			}
652 			if (innerClassesAttribute != null) {
653 				disassemble(innerClassesAttribute, buffer, lineSeparator, 1);
654 			}
655 			if (enclosingMethodAttribute != null) {
656 				disassemble(enclosingMethodAttribute, buffer, lineSeparator, 0);
657 			}
658 			if (runtimeVisibleAnnotationsAttribute != null) {
659 				disassemble((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode);
660 			}
661 			if (runtimeInvisibleAnnotationsAttribute != null) {
662 				disassemble((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode);
663 			}
664 		}
665 		writeNewLine(buffer, lineSeparator, 0);
666 		buffer.append(Messages.disassembler_closetypedeclaration);
667 		return buffer.toString();
668 	}
669 
isJavaLangObject(final char[] className)670 	private boolean isJavaLangObject(final char[] className) {
671 		return Arrays.equals(TypeConstants.JAVA_LANG_OBJECT, CharOperation.splitOn('.', className));
672 	}
673 
isVarArgs(MethodInfo methodInfo)674 	private boolean isVarArgs(MethodInfo methodInfo) {
675 		int accessFlags = methodInfo.getAccessFlags();
676 		if ((accessFlags & IModifierConstants.ACC_VARARGS) != 0)
677 			return true;
678 		// check the presence of the unspecified Varargs attribute
679 		return Utility.getAttribute(methodInfo, AttributeNamesConstants.VAR_ARGS) != null;
680 	}
681 
disassemble(CodeAttribute codeAttribute, char[] methodDescriptor, boolean isStatic, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)682 	private void disassemble(CodeAttribute codeAttribute, char[] methodDescriptor, boolean isStatic, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
683 		writeNewLine(buffer, lineSeparator, tabNumber - 1);
684 		DefaultBytecodeVisitor visitor = new DefaultBytecodeVisitor(codeAttribute, methodDescriptor, isStatic, buffer, lineSeparator, tabNumber, mode);
685 		try {
686 			codeAttribute.traverse(visitor);
687 		} catch (ClassFormatException e) {
688 			dumpTab(tabNumber + 2, buffer);
689 			buffer.append(Messages.classformat_classformatexception);
690 			writeNewLine(buffer, lineSeparator, tabNumber + 1);
691 		}
692 		final int exceptionTableLength = codeAttribute.getExceptionTableLength();
693 		if (exceptionTableLength != 0) {
694 			final int tabNumberForExceptionAttribute = tabNumber + 2;
695 			dumpTab(tabNumberForExceptionAttribute, buffer);
696 			final ExceptionTableEntry[] exceptionTableEntries = codeAttribute.getExceptionTable();
697 			buffer.append(Messages.disassembler_exceptiontableheader);
698 			writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
699 			for (int i = 0; i < exceptionTableLength; i++) {
700 				if (i != 0) {
701 					writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
702 				}
703 				ExceptionTableEntry exceptionTableEntry = exceptionTableEntries[i];
704 				char[] catchType;
705 				if (exceptionTableEntry.getCatchTypeIndex() != 0) {
706 					catchType = exceptionTableEntry.getCatchType();
707 					CharOperation.replace(catchType, '/', '.');
708 					catchType = returnClassName(catchType, '.', mode);
709 				} else {
710 					catchType = ANY_EXCEPTION;
711 				}
712 				buffer.append(NLS.bind(Messages.classfileformat_exceptiontableentry, new String[] {Integer.toString(exceptionTableEntry.getStartPC()), Integer.toString(exceptionTableEntry.getEndPC()), Integer.toString(exceptionTableEntry.getHandlerPC()), new String(catchType),}));
713 			}
714 		}
715 	}
716 
disassemble(EnclosingMethodAttribute enclosingMethodAttribute, StringBuffer buffer, String lineSeparator, int tabNumber)717 	private void disassemble(EnclosingMethodAttribute enclosingMethodAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
718 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
719 		buffer.append(Messages.disassembler_enclosingmethodheader);
720 		buffer.append(" ")//$NON-NLS-1$
721 				.append(enclosingMethodAttribute.getEnclosingClass());
722 		if (enclosingMethodAttribute.getMethodNameAndTypeIndex() != 0) {
723 			buffer.append(".")//$NON-NLS-1$
724 					.append(enclosingMethodAttribute.getMethodName()).append(enclosingMethodAttribute.getMethodDescriptor());
725 		}
726 	}
727 
728 	/**
729 	 * Disassemble a field info
730 	 */
disassemble(FieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)731 	private void disassemble(FieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
732 		writeNewLine(buffer, lineSeparator, tabNumber);
733 		final char[] fieldDescriptor = fieldInfo.getDescriptor();
734 		final SignatureAttribute signatureAttribute = (SignatureAttribute) Utility.getAttribute(fieldInfo, AttributeNamesConstants.SIGNATURE);
735 		if (checkMode(mode, DETAILED)) {
736 			buffer.append(NLS.bind(Messages.classfileformat_fieldddescriptor, new String[] {new String(fieldDescriptor)}));
737 			if (fieldInfo.isDeprecated()) {
738 				buffer.append(Messages.disassembler_deprecated);
739 			}
740 			writeNewLine(buffer, lineSeparator, tabNumber);
741 			if (signatureAttribute != null) {
742 				buffer.append(NLS.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature())));
743 				writeNewLine(buffer, lineSeparator, tabNumber);
744 			}
745 		}
746 		final ClassFileAttribute runtimeVisibleAnnotationsAttribute = Utility.getAttribute(fieldInfo, AttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
747 		final ClassFileAttribute runtimeInvisibleAnnotationsAttribute = Utility.getAttribute(fieldInfo, AttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
748 		if (checkMode(mode, DETAILED)) {
749 			// disassemble compact version of annotations
750 			if (runtimeInvisibleAnnotationsAttribute != null) {
751 				disassembleAsModifier((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
752 				writeNewLine(buffer, lineSeparator, tabNumber);
753 			}
754 			if (runtimeVisibleAnnotationsAttribute != null) {
755 				disassembleAsModifier((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
756 				writeNewLine(buffer, lineSeparator, tabNumber);
757 			}
758 		}
759 		decodeModifiersForField(buffer, fieldInfo.getAccessFlags());
760 		if (fieldInfo.isSynthetic()) {
761 			buffer.append("synthetic"); //$NON-NLS-1$
762 			buffer.append(Messages.disassembler_space);
763 		}
764 		buffer.append(returnClassName(getSignatureForField(fieldDescriptor), '.', mode));
765 		buffer.append(' ');
766 		buffer.append(new String(fieldInfo.getName()));
767 		ConstantValueAttribute constantValueAttribute = fieldInfo.getConstantValueAttribute();
768 		if (constantValueAttribute != null) {
769 			buffer.append(Messages.disassembler_fieldhasconstant);
770 			ConstantPoolEntry constantPoolEntry = constantValueAttribute.getConstantValue();
771 			switch (constantPoolEntry.getKind()) {
772 				case ConstantPoolConstant.CONSTANT_Long :
773 					buffer.append(constantPoolEntry.getLongValue() + "L"); //$NON-NLS-1$
774 					break;
775 				case ConstantPoolConstant.CONSTANT_Float :
776 					buffer.append(constantPoolEntry.getFloatValue() + "f"); //$NON-NLS-1$
777 					break;
778 				case ConstantPoolConstant.CONSTANT_Double :
779 					buffer.append(constantPoolEntry.getDoubleValue());
780 					break;
781 				case ConstantPoolConstant.CONSTANT_Integer :
782 					switch (fieldDescriptor[0]) {
783 						case 'C' :
784 							buffer.append("'" + (char) constantPoolEntry.getIntegerValue() + "'"); //$NON-NLS-1$//$NON-NLS-2$
785 							break;
786 						case 'Z' :
787 							buffer.append(constantPoolEntry.getIntegerValue() == 1 ? "true" : "false");//$NON-NLS-1$//$NON-NLS-2$
788 							break;
789 						case 'B' :
790 							buffer.append(constantPoolEntry.getIntegerValue());
791 							break;
792 						case 'S' :
793 							buffer.append(constantPoolEntry.getIntegerValue());
794 							break;
795 						case 'I' :
796 							buffer.append(constantPoolEntry.getIntegerValue());
797 					}
798 					break;
799 				case ConstantPoolConstant.CONSTANT_String :
800 					buffer.append("\"" + decodeStringValue(constantPoolEntry.getStringValue()) + "\"");//$NON-NLS-1$//$NON-NLS-2$
801 			}
802 		}
803 		buffer.append(Messages.disassembler_endoffieldheader);
804 		if (checkMode(mode, DETAILED)) {
805 			if (runtimeVisibleAnnotationsAttribute != null) {
806 				disassemble((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
807 			}
808 			if (runtimeInvisibleAnnotationsAttribute != null) {
809 				disassemble((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
810 			}
811 		}
812 	}
813 
disassemble(InnerClassesAttribute innerClassesAttribute, StringBuffer buffer, String lineSeparator, int tabNumber)814 	private void disassemble(InnerClassesAttribute innerClassesAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
815 		writeNewLine(buffer, lineSeparator, tabNumber);
816 		buffer.append(Messages.disassembler_innerattributesheader);
817 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
818 		InnerClassesAttributeEntry[] innerClassesAttributeEntries = innerClassesAttribute.getInnerClassAttributesEntries();
819 		int length = innerClassesAttributeEntries.length;
820 		int innerClassNameIndex, outerClassNameIndex, innerNameIndex, accessFlags;
821 		InnerClassesAttributeEntry innerClassesAttributeEntry;
822 		if (length > 1) {
823 			final char[] EMPTY_CHAR_ARRAY = Utility.EMPTY_STRING.toCharArray();
824 			Arrays.sort(innerClassesAttributeEntries, (o1, o2) -> {
825 				final char[] innerClassName1 = o1.getInnerClassName();
826 				final char[] innerClassName2 = o2.getInnerClassName();
827 				final char[] innerName1 = o1.getInnerName();
828 				final char[] innerName2 = o2.getInnerName();
829 				final char[] outerClassName1 = o1.getOuterClassName();
830 				final char[] outerClassName2 = o2.getOuterClassName();
831 				StringBuilder buffer1 = new StringBuilder();
832 				buffer1.append(innerClassName1 == null ? EMPTY_CHAR_ARRAY : innerClassName1);
833 				buffer1.append(innerName1 == null ? EMPTY_CHAR_ARRAY : innerName1);
834 				buffer1.append(outerClassName1 == null ? EMPTY_CHAR_ARRAY : outerClassName1);
835 				StringBuilder buffer2 = new StringBuilder();
836 				buffer2.append(innerClassName2 == null ? EMPTY_CHAR_ARRAY : innerClassName2);
837 				buffer2.append(innerName2 == null ? EMPTY_CHAR_ARRAY : innerName2);
838 				buffer2.append(outerClassName2 == null ? EMPTY_CHAR_ARRAY : outerClassName2);
839 				return buffer1.toString().compareTo(buffer2.toString());
840 			});
841 		}
842 		for (int i = 0; i < length; i++) {
843 			if (i != 0) {
844 				buffer.append(Messages.disassembler_comma);
845 				writeNewLine(buffer, lineSeparator, tabNumber + 1);
846 			}
847 			innerClassesAttributeEntry = innerClassesAttributeEntries[i];
848 			innerClassNameIndex = innerClassesAttributeEntry.getInnerClassNameIndex();
849 			outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex();
850 			innerNameIndex = innerClassesAttributeEntry.getInnerNameIndex();
851 			accessFlags = innerClassesAttributeEntry.getAccessFlags();
852 			buffer.append(Messages.disassembler_openinnerclassentry).append(Messages.disassembler_inner_class_info_name);
853 			if (innerClassNameIndex != 0) {
854 				buffer.append(Messages.disassembler_space).append(innerClassesAttributeEntry.getInnerClassName());
855 			}
856 			buffer.append(Messages.disassembler_comma).append(Messages.disassembler_space).append(Messages.disassembler_outer_class_info_name);
857 			if (outerClassNameIndex != 0) {
858 				buffer.append(Messages.disassembler_space).append(innerClassesAttributeEntry.getOuterClassName());
859 			}
860 			writeNewLine(buffer, lineSeparator, tabNumber);
861 			dumpTab(tabNumber, buffer);
862 			buffer.append(Messages.disassembler_space);
863 			buffer.append(Messages.disassembler_inner_name);
864 			if (innerNameIndex != 0) {
865 				buffer.append(Messages.disassembler_space).append(innerClassesAttributeEntry.getInnerName());
866 			}
867 			buffer.append(Messages.disassembler_comma).append(Messages.disassembler_space).append(Messages.disassembler_inner_accessflags).append(accessFlags).append(Messages.disassembler_space);
868 			decodeModifiersForInnerClasses(buffer, accessFlags, true);
869 			buffer.append(Messages.disassembler_closeinnerclassentry);
870 		}
871 	}
872 
disassemble(int index, ParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)873 	private void disassemble(int index, ParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
874 		Annotation[] annotations = parameterAnnotation.getAnnotations();
875 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
876 		buffer.append(NLS.bind(Messages.disassembler_parameterannotationentrystart, new String[] {Integer.toString(index), Integer.toString(annotations.length)}));
877 		for (Annotation annotation : annotations) {
878 			disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode);
879 		}
880 	}
881 
disassemble(RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)882 	private void disassemble(RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
883 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
884 		buffer.append(Messages.disassembler_runtimeinvisibleannotationsattributeheader);
885 		Annotation[] annotations = runtimeInvisibleAnnotationsAttribute.getAnnotations();
886 		for (Annotation annotation : annotations) {
887 			disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode);
888 		}
889 	}
890 
disassemble(RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)891 	private void disassemble(RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
892 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
893 		buffer.append(Messages.disassembler_runtimeinvisibleparameterannotationsattributeheader);
894 		ParameterAnnotation[] parameterAnnotations = runtimeInvisibleParameterAnnotationsAttribute.getParameterAnnotations();
895 		for (int i = 0, max = parameterAnnotations.length; i < max; i++) {
896 			disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode);
897 		}
898 	}
899 
disassemble(RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)900 	private void disassemble(RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
901 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
902 		buffer.append(Messages.disassembler_runtimevisibleannotationsattributeheader);
903 		Annotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations();
904 		for (Annotation annotation : annotations) {
905 			disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode);
906 		}
907 	}
908 
disassemble(RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)909 	private void disassemble(RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
910 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
911 		buffer.append(Messages.disassembler_runtimevisibleparameterannotationsattributeheader);
912 		ParameterAnnotation[] parameterAnnotations = runtimeVisibleParameterAnnotationsAttribute.getParameterAnnotations();
913 		for (int i = 0, max = parameterAnnotations.length; i < max; i++) {
914 			disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode);
915 		}
916 	}
917 
disassembleAsModifier(Annotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)918 	private void disassembleAsModifier(Annotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
919 		final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.');
920 		buffer.append('@').append(returnClassName(Signature.toCharArray(typeName), '.', mode));
921 		final AnnotationComponent[] components = annotation.getComponents();
922 		final int length = components.length;
923 		if (length != 0) {
924 			buffer.append('(');
925 			for (int i = 0; i < length; i++) {
926 				if (i > 0) {
927 					buffer.append(',');
928 					writeNewLine(buffer, lineSeparator, tabNumber);
929 				}
930 				disassembleAsModifier(components[i], buffer, lineSeparator, tabNumber + 1, mode);
931 			}
932 			buffer.append(')');
933 		}
934 	}
935 
disassembleAsModifier(AnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)936 	private void disassembleAsModifier(AnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
937 		buffer.append(annotationComponent.getComponentName()).append('=');
938 		disassembleAsModifier(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1, mode);
939 	}
940 
disassembleAsModifier(AnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)941 	private void disassembleAsModifier(AnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
942 		switch (annotationComponentValue.getTag()) {
943 			case AnnotationComponentValue.BYTE_TAG :
944 			case AnnotationComponentValue.CHAR_TAG :
945 			case AnnotationComponentValue.DOUBLE_TAG :
946 			case AnnotationComponentValue.FLOAT_TAG :
947 			case AnnotationComponentValue.INTEGER_TAG :
948 			case AnnotationComponentValue.LONG_TAG :
949 			case AnnotationComponentValue.SHORT_TAG :
950 			case AnnotationComponentValue.BOOLEAN_TAG :
951 			case AnnotationComponentValue.STRING_TAG :
952 				ConstantPoolEntry constantPoolEntry = annotationComponentValue.getConstantValue();
953 				String value = null;
954 				switch (constantPoolEntry.getKind()) {
955 					case ConstantPoolConstant.CONSTANT_Long :
956 						value = constantPoolEntry.getLongValue() + "L"; //$NON-NLS-1$
957 						break;
958 					case ConstantPoolConstant.CONSTANT_Float :
959 						value = constantPoolEntry.getFloatValue() + "f"; //$NON-NLS-1$
960 						break;
961 					case ConstantPoolConstant.CONSTANT_Double :
962 						value = Double.toString(constantPoolEntry.getDoubleValue());
963 						break;
964 					case ConstantPoolConstant.CONSTANT_Integer :
965 						switch (annotationComponentValue.getTag()) {
966 							case AnnotationComponentValue.CHAR_TAG :
967 								value = "'" + (char) constantPoolEntry.getIntegerValue() + "'"; //$NON-NLS-1$//$NON-NLS-2$
968 								break;
969 							case AnnotationComponentValue.BOOLEAN_TAG :
970 								value = constantPoolEntry.getIntegerValue() == 1 ? "true" : "false";//$NON-NLS-1$//$NON-NLS-2$
971 								break;
972 							case AnnotationComponentValue.BYTE_TAG :
973 								value = "(byte) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
974 								break;
975 							case AnnotationComponentValue.SHORT_TAG :
976 								value = "(short) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
977 								break;
978 							case AnnotationComponentValue.INTEGER_TAG :
979 								value = "(int) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$
980 						}
981 						break;
982 					case ConstantPoolConstant.CONSTANT_Utf8 :
983 						value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$
984 				}
985 				buffer.append(value);
986 				break;
987 			case AnnotationComponentValue.ENUM_TAG :
988 				final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.');
989 				final char[] constantName = annotationComponentValue.getEnumConstantName();
990 				buffer.append(returnClassName(Signature.toCharArray(typeName), '.', mode)).append('.').append(constantName);
991 				break;
992 			case AnnotationComponentValue.CLASS_TAG :
993 				constantPoolEntry = annotationComponentValue.getClassInfo();
994 				final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.');
995 				buffer.append(returnClassName(Signature.toCharArray(className), '.', mode));
996 				break;
997 			case AnnotationComponentValue.ANNOTATION_TAG :
998 				Annotation annotation = annotationComponentValue.getAnnotationValue();
999 				disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1, mode);
1000 				break;
1001 			case AnnotationComponentValue.ARRAY_TAG :
1002 				final AnnotationComponentValue[] annotationComponentValues = annotationComponentValue.getAnnotationComponentValues();
1003 				buffer.append('{');
1004 				for (int i = 0, max = annotationComponentValues.length; i < max; i++) {
1005 					if (i > 0) {
1006 						buffer.append(',');
1007 					}
1008 					disassembleAsModifier(annotationComponentValues[i], buffer, lineSeparator, tabNumber + 1, mode);
1009 				}
1010 				buffer.append('}');
1011 		}
1012 	}
1013 
disassembleAsModifier(AnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)1014 	private void disassembleAsModifier(AnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
1015 		AnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue();
1016 		disassembleAsModifier(componentValue, buffer, lineSeparator, tabNumber + 1, mode);
1017 	}
1018 
disassembleAsModifier(RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)1019 	private void disassembleAsModifier(RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
1020 		for (Annotation annotation : runtimeInvisibleAnnotationsAttribute.getAnnotations()) {
1021 			disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1, mode);
1022 		}
1023 	}
1024 
disassembleAsModifier(RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode)1025 	private void disassembleAsModifier(RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode) {
1026 		ParameterAnnotation[] parameterAnnotations = runtimeInvisibleParameterAnnotationsAttribute.getParameterAnnotations();
1027 		if (parameterAnnotations.length > index) {
1028 			disassembleAsModifier(parameterAnnotations[index], buffer, lineSeparator, tabNumber + 1, mode);
1029 		}
1030 	}
1031 
disassembleAsModifier(RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode)1032 	private void disassembleAsModifier(RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode) {
1033 		ParameterAnnotation[] parameterAnnotations = runtimeVisibleParameterAnnotationsAttribute.getParameterAnnotations();
1034 		if (parameterAnnotations.length > index) {
1035 			disassembleAsModifier(parameterAnnotations[index], buffer, lineSeparator, tabNumber + 1, mode);
1036 		}
1037 	}
1038 
disassembleAsModifier(ParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)1039 	private void disassembleAsModifier(ParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
1040 		Annotation[] annotations = parameterAnnotation.getAnnotations();
1041 		for (int i = 0, max = annotations.length; i < max; i++) {
1042 			if (i > 0) {
1043 				buffer.append(' ');
1044 			}
1045 			disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode);
1046 		}
1047 	}
1048 
disassembleAsModifier(RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)1049 	private void disassembleAsModifier(RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
1050 		Annotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations();
1051 		for (int i = 0, max = annotations.length; i < max; i++) {
1052 			if (i > 0) {
1053 				writeNewLine(buffer, lineSeparator, tabNumber);
1054 			}
1055 			disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode);
1056 		}
1057 	}
1058 
disassembleTypeMembers(ClassFileReader classFileReader, char[] className, StringBuffer buffer, String lineSeparator, int tabNumber, int mode, boolean isEnum)1059 	private void disassembleTypeMembers(ClassFileReader classFileReader, char[] className, StringBuffer buffer, String lineSeparator, int tabNumber, int mode, boolean isEnum) {
1060 		FieldInfo[] fields = classFileReader.getFieldInfos();
1061 		// sort fields
1062 		Arrays.sort(fields, (fieldInfo1, fieldInfo2) -> {
1063 			int compare = new String(fieldInfo1.getName()).compareTo(new String(fieldInfo2.getName()));
1064 			if (compare == 0) {
1065 				return new String(fieldInfo1.getDescriptor()).compareTo(new String(fieldInfo2.getDescriptor()));
1066 			}
1067 			return compare;
1068 		});
1069 		for (FieldInfo field : fields) {
1070 			writeNewLine(buffer, lineSeparator, tabNumber);
1071 			disassemble(field, buffer, lineSeparator, tabNumber, mode);
1072 		}
1073 		MethodInfo[] methods = classFileReader.getMethodInfos();
1074 		// sort methods
1075 		Arrays.sort(methods, (methodInfo1, methodInfo2) -> {
1076 			int compare = new String(methodInfo1.getName()).compareTo(new String(methodInfo2.getName()));
1077 			if (compare == 0) {
1078 				return new String(methodInfo1.getDescriptor()).compareTo(new String(methodInfo2.getDescriptor()));
1079 			}
1080 			return compare;
1081 		});
1082 		for (MethodInfo method : methods) {
1083 			writeNewLine(buffer, lineSeparator, tabNumber);
1084 			disassemble(classFileReader, className, method, buffer, lineSeparator, tabNumber, mode);
1085 		}
1086 	}
1087 
dumpTab(int tabNumber, StringBuffer buffer)1088 	private final void dumpTab(int tabNumber, StringBuffer buffer) {
1089 		for (int i = 0; i < tabNumber; i++) {
1090 			buffer.append(Messages.disassembler_indentation);
1091 		}
1092 	}
1093 
getEnclosingMethodAttribute(ClassFileReader classFileReader)1094 	private EnclosingMethodAttribute getEnclosingMethodAttribute(ClassFileReader classFileReader) {
1095 		for (ClassFileAttribute attribute : classFileReader.getAttributes()) {
1096 			if (Arrays.equals(attribute.getAttributeName(), AttributeNamesConstants.ENCLOSING_METHOD)) {
1097 				return (EnclosingMethodAttribute) attribute;
1098 			}
1099 		}
1100 		return null;
1101 	}
1102 
getSignatureForField(char[] fieldDescriptor)1103 	private char[] getSignatureForField(char[] fieldDescriptor) {
1104 		char[] newFieldDescriptor = CharOperation.replaceOnCopy(fieldDescriptor, '/', '.');
1105 		newFieldDescriptor = CharOperation.replaceOnCopy(newFieldDescriptor, '$', '%');
1106 		char[] fieldDescriptorSignature = Signature.toCharArray(newFieldDescriptor);
1107 		CharOperation.replace(fieldDescriptorSignature, '%', '$');
1108 		return fieldDescriptorSignature;
1109 	}
1110 
isDeprecated(ClassFileReader classFileReader)1111 	private boolean isDeprecated(ClassFileReader classFileReader) {
1112 		for (ClassFileAttribute attribute : classFileReader.getAttributes()) {
1113 			if (Arrays.equals(attribute.getAttributeName(), AttributeNamesConstants.DEPRECATED)) {
1114 				return true;
1115 			}
1116 		}
1117 		return false;
1118 	}
1119 
isSynthetic(ClassFileReader classFileReader)1120 	private boolean isSynthetic(ClassFileReader classFileReader) {
1121 		int flags = classFileReader.getAccessFlags();
1122 		if ((flags & IModifierConstants.ACC_SYNTHETIC) != 0) {
1123 			return true;
1124 		}
1125 		for (ClassFileAttribute attribute : classFileReader.getAttributes()) {
1126 			if (Arrays.equals(attribute.getAttributeName(), AttributeNamesConstants.SYNTHETIC)) {
1127 				return true;
1128 			}
1129 		}
1130 		return false;
1131 	}
1132 
checkMode(int mode, int flag)1133 	private boolean checkMode(int mode, int flag) {
1134 		return (mode & flag) != 0;
1135 	}
1136 
isCompact(int mode)1137 	private boolean isCompact(int mode) {
1138 		return (mode & Disassembler.COMPACT) != 0;
1139 	}
1140 
returnClassName(char[] classInfoName, char separator, int mode)1141 	private char[] returnClassName(char[] classInfoName, char separator, int mode) {
1142 		if (classInfoName.length == 0) {
1143 			return CharOperation.NO_CHAR;
1144 		} else if (isCompact(mode)) {
1145 			int lastIndexOfSlash = CharOperation.lastIndexOf(separator, classInfoName);
1146 			if (lastIndexOfSlash != -1) {
1147 				return CharOperation.subarray(classInfoName, lastIndexOfSlash + 1, classInfoName.length);
1148 			}
1149 		}
1150 		return classInfoName;
1151 	}
1152 
writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber)1153 	private void writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber) {
1154 		buffer.append(lineSeparator);
1155 		dumpTab(tabNumber, buffer);
1156 	}
1157 }
1158