Copyright (c) 2000, 2019 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 Stephan Herrmann - Contribution for Bug 365992 - [builder] [null] Change of nullness for a parameter doesn't trigger a build for the files that call the method Bug 440477 - [null] Infrastructure for feeding external annotations into compilation Bug 440687 - [compiler][batch][null] improve command line option for external annotations Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for bug 407191 - [1.8] Binary access support for type annotations
/******************************************************************************* * Copyright (c) 2000, 2019 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 * Stephan Herrmann - Contribution for * Bug 365992 - [builder] [null] Change of nullness for a parameter doesn't trigger a build for the files that call the method * Bug 440477 - [null] Infrastructure for feeding external annotations into compilation * Bug 440687 - [compiler][batch][null] improve command line option for external annotations * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * bug 407191 - [1.8] Binary access support for type annotations *******************************************************************************/
package org.eclipse.jdt.internal.compiler.classfmt; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.function.Predicate; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants; import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants; import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation; import org.eclipse.jdt.internal.compiler.env.IBinaryElementValuePair; import org.eclipse.jdt.internal.compiler.env.IBinaryField; import org.eclipse.jdt.internal.compiler.env.IBinaryMethod; import org.eclipse.jdt.internal.compiler.env.IBinaryModule; import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType; import org.eclipse.jdt.internal.compiler.env.IBinaryType; import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation; import org.eclipse.jdt.internal.compiler.env.IModule; import org.eclipse.jdt.internal.compiler.env.ITypeAnnotationWalker; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.util.JRTUtil; import org.eclipse.jdt.internal.compiler.util.Util; public class ClassFileReader extends ClassFileStruct implements IBinaryType { private int accessFlags; private char[] classFileName; private char[] className; private int classNameIndex; private int constantPoolCount; private AnnotationInfo[] annotations; private TypeAnnotationInfo[] typeAnnotations; private FieldInfo[] fields; private ModuleInfo moduleDeclaration; public char[] moduleName; private int fieldsCount; // initialized in case the .class file is a nested type private InnerClassInfo innerInfo; private InnerClassInfo[] innerInfos; private char[][] interfaceNames; private int interfacesCount; private MethodInfo[] methods; private int methodsCount; private char[] signature; private char[] sourceName; private char[] sourceFileName; private char[] superclassName; private long tagBits; private long version; private char[] enclosingTypeName; private char[][][] missingTypeNames; private int enclosingNameAndTypeIndex; private char[] enclosingMethod; private char[] nestHost; private int nestMembersCount; private char[][] nestMembers; private static String printTypeModifiers(int modifiers) { java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); java.io.PrintWriter print = new java.io.PrintWriter(out); if ((modifiers & ClassFileConstants.AccPublic) != 0) print.print("public "); //$NON-NLS-1$ if ((modifiers & ClassFileConstants.AccPrivate) != 0) print.print("private "); //$NON-NLS-1$ if ((modifiers & ClassFileConstants.AccFinal) != 0) print.print("final "); //$NON-NLS-1$ if ((modifiers & ClassFileConstants.AccSuper) != 0) print.print("super "); //$NON-NLS-1$ if ((modifiers & ClassFileConstants.AccInterface) != 0) print.print("interface "); //$NON-NLS-1$ if ((modifiers & ClassFileConstants.AccAbstract) != 0) print.print("abstract "); //$NON-NLS-1$ print.flush(); return out.toString(); } public static ClassFileReader read(File file) throws ClassFormatException, IOException { return read(file, false); } public static ClassFileReader read(File file, boolean fullyInitialize) throws ClassFormatException, IOException { byte classFileBytes[] = Util.getFileByteContent(file); ClassFileReader classFileReader = new ClassFileReader(classFileBytes, file.getAbsolutePath().toCharArray()); if (fullyInitialize) { classFileReader.initialize(); } return classFileReader; } public static ClassFileReader read(InputStream stream, String fileName) throws ClassFormatException, IOException { return read(stream, fileName, false); } public static ClassFileReader read(InputStream stream, String fileName, boolean fullyInitialize) throws ClassFormatException, IOException { byte classFileBytes[] = Util.getInputStreamAsByteArray(stream, -1); ClassFileReader classFileReader = new ClassFileReader(classFileBytes, fileName.toCharArray()); if (fullyInitialize) { classFileReader.initialize(); } return classFileReader; } public static ClassFileReader read( java.util.zip.ZipFile zip, String filename) throws ClassFormatException, java.io.IOException { return read(zip, filename, false); } public static ClassFileReader readFromJrt( File jrt, IModule module, String filename) throws ClassFormatException, java.io.IOException { return JRTUtil.getClassfile(jrt, filename, module); } public static ClassFileReader readFromModule( File jrt, String moduleName, String filename, Predicate<String> moduleNameFilter) throws ClassFormatException, java.io.IOException { return JRTUtil.getClassfile(jrt, filename, moduleName, moduleNameFilter); } public static ClassFileReader read( java.util.zip.ZipFile zip, String filename, boolean fullyInitialize) throws ClassFormatException, java.io.IOException { java.util.zip.ZipEntry ze = zip.getEntry(filename); if (ze == null) return null; byte classFileBytes[] = Util.getZipEntryByteContent(ze, zip); ClassFileReader classFileReader = new ClassFileReader(classFileBytes, filename.toCharArray()); if (fullyInitialize) { classFileReader.initialize(); } return classFileReader; } public static ClassFileReader read(String fileName) throws ClassFormatException, java.io.IOException { return read(fileName, false); } public static ClassFileReader read(String fileName, boolean fullyInitialize) throws ClassFormatException, java.io.IOException { return read(new File(fileName), fullyInitialize); }
Params:
  • classFileBytes – Actual bytes of a .class file
  • fileName – Actual name of the file that contains the bytes, can be null
Throws:
/** * @param classFileBytes Actual bytes of a .class file * @param fileName Actual name of the file that contains the bytes, can be null * * @exception ClassFormatException */
public ClassFileReader(byte classFileBytes[], char[] fileName) throws ClassFormatException { this(classFileBytes, fileName, false); }
Params:
  • classFileBytes – byte[] Actual bytes of a .class file
  • fileName – char[] Actual name of the file that contains the bytes, can be null
  • fullyInitialize – boolean Flag to fully initialize the new object
Throws:
/** * @param classFileBytes byte[] * Actual bytes of a .class file * * @param fileName char[] * Actual name of the file that contains the bytes, can be null * * @param fullyInitialize boolean * Flag to fully initialize the new object * @exception ClassFormatException */
public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInitialize) throws ClassFormatException { // This method looks ugly but is actually quite simple, the constantPool is constructed // in 3 passes. All non-primitive constant pool members that usually refer to other members // by index are tweaked to have their value in inst vars, this minor cost at read-time makes // all subsequent uses of the constant pool element faster. super(classFileBytes, null, 0); this.classFileName = fileName; int readOffset = 10; try { this.version = ((long)u2At(6) << 16) + u2At(4); // major<<16 + minor this.constantPoolCount = u2At(8); // Pass #1 - Fill in all primitive constants this.constantPoolOffsets = new int[this.constantPoolCount]; for (int i = 1; i < this.constantPoolCount; i++) { int tag = u1At(readOffset); switch (tag) { case ClassFileConstants.Utf8Tag : this.constantPoolOffsets[i] = readOffset; readOffset += u2At(readOffset + 1); readOffset += ClassFileConstants.ConstantUtf8FixedSize; break; case ClassFileConstants.IntegerTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantIntegerFixedSize; break; case ClassFileConstants.FloatTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantFloatFixedSize; break; case ClassFileConstants.LongTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantLongFixedSize; i++; break; case ClassFileConstants.DoubleTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantDoubleFixedSize; i++; break; case ClassFileConstants.ClassTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantClassFixedSize; break; case ClassFileConstants.StringTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantStringFixedSize; break; case ClassFileConstants.FieldRefTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantFieldRefFixedSize; break; case ClassFileConstants.MethodRefTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantMethodRefFixedSize; break; case ClassFileConstants.InterfaceMethodRefTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantInterfaceMethodRefFixedSize; break; case ClassFileConstants.NameAndTypeTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantNameAndTypeFixedSize; break; case ClassFileConstants.MethodHandleTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantMethodHandleFixedSize; break; case ClassFileConstants.MethodTypeTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantMethodTypeFixedSize; break; case ClassFileConstants.DynamicTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantDynamicFixedSize; break; case ClassFileConstants.InvokeDynamicTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantInvokeDynamicFixedSize; break; case ClassFileConstants.ModuleTag: this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantModuleFixedSize; break; case ClassFileConstants.PackageTag: this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantPackageFixedSize; break; } } // Read and validate access flags this.accessFlags = u2At(readOffset); readOffset += 2; // Read the classname, use exception handlers to catch bad format this.classNameIndex = u2At(readOffset); if (this.classNameIndex != 0) { this.className = getConstantClassNameAt(this.classNameIndex); } readOffset += 2; // Read the superclass name, can be null for java.lang.Object int superclassNameIndex = u2At(readOffset); readOffset += 2; // if superclassNameIndex is equals to 0 there is no need to set a value for the // field this.superclassName. null is fine. if (superclassNameIndex != 0) { this.superclassName = getConstantClassNameAt(superclassNameIndex); } // Read the interfaces, use exception handlers to catch bad format this.interfacesCount = u2At(readOffset); readOffset += 2; if (this.interfacesCount != 0) { this.interfaceNames = new char[this.interfacesCount][]; for (int i = 0; i < this.interfacesCount; i++) { this.interfaceNames[i] = getConstantClassNameAt(u2At(readOffset)); readOffset += 2; } } // Read the fields, use exception handlers to catch bad format this.fieldsCount = u2At(readOffset); readOffset += 2; if (this.fieldsCount != 0) { FieldInfo field; this.fields = new FieldInfo[this.fieldsCount]; for (int i = 0; i < this.fieldsCount; i++) { field = FieldInfo.createField(this.reference, this.constantPoolOffsets, readOffset, this.version); this.fields[i] = field; readOffset += field.sizeInBytes(); } } // Read the methods this.methodsCount = u2At(readOffset); readOffset += 2; if (this.methodsCount != 0) { this.methods = new MethodInfo[this.methodsCount]; boolean isAnnotationType = (this.accessFlags & ClassFileConstants.AccAnnotation) != 0; for (int i = 0; i < this.methodsCount; i++) { this.methods[i] = isAnnotationType ? AnnotationMethodInfo.createAnnotationMethod(this.reference, this.constantPoolOffsets, readOffset, this.version) : MethodInfo.createMethod(this.reference, this.constantPoolOffsets, readOffset, this.version); readOffset += this.methods[i].sizeInBytes(); } } // Read the attributes int attributesCount = u2At(readOffset); readOffset += 2; for (int i = 0; i < attributesCount; i++) { int utf8Offset = this.constantPoolOffsets[u2At(readOffset)]; char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); if (attributeName.length == 0) { readOffset += (6 + u4At(readOffset + 2)); continue; } switch(attributeName[0] ) { case 'E' : if (CharOperation.equals(attributeName, AttributeNamesConstants.EnclosingMethodName)) { utf8Offset = this.constantPoolOffsets[u2At(this.constantPoolOffsets[u2At(readOffset + 6)] + 1)]; this.enclosingTypeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); this.enclosingNameAndTypeIndex = u2At(readOffset + 8); } break; case 'D' : if (CharOperation.equals(attributeName, AttributeNamesConstants.DeprecatedName)) { this.accessFlags |= ClassFileConstants.AccDeprecated; } break; case 'I' : if (CharOperation.equals(attributeName, AttributeNamesConstants.InnerClassName)) { int innerOffset = readOffset + 6; int number_of_classes = u2At(innerOffset); if (number_of_classes != 0) { innerOffset+= 2; this.innerInfos = new InnerClassInfo[number_of_classes]; for (int j = 0; j < number_of_classes; j++) { this.innerInfos[j] = new InnerClassInfo(this.reference, this.constantPoolOffsets, innerOffset); if (this.classNameIndex == this.innerInfos[j].innerClassNameIndex) { this.innerInfo = this.innerInfos[j]; } innerOffset += 8; } if (this.innerInfo != null) { char[] enclosingType = this.innerInfo.getEnclosingTypeName(); if (enclosingType != null) { this.enclosingTypeName = enclosingType; } } } } else if (CharOperation.equals(attributeName, AttributeNamesConstants.InconsistentHierarchy)) { this.tagBits |= TagBits.HierarchyHasProblems; } break; case 'S' : if (attributeName.length > 2) { switch(attributeName[1]) { case 'o' : if (CharOperation.equals(attributeName, AttributeNamesConstants.SourceName)) { utf8Offset = this.constantPoolOffsets[u2At(readOffset + 6)]; this.sourceFileName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); } break; case 'y' : if (CharOperation.equals(attributeName, AttributeNamesConstants.SyntheticName)) { this.accessFlags |= ClassFileConstants.AccSynthetic; } break; case 'i' : if (CharOperation.equals(attributeName, AttributeNamesConstants.SignatureName)) { utf8Offset = this.constantPoolOffsets[u2At(readOffset + 6)]; this.signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); } } } break; case 'R' : if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeVisibleAnnotationsName)) { decodeAnnotations(readOffset, true); } else if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeInvisibleAnnotationsName)) { decodeAnnotations(readOffset, false); } else if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeVisibleTypeAnnotationsName)) { decodeTypeAnnotations(readOffset, true); } else if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeInvisibleTypeAnnotationsName)) { decodeTypeAnnotations(readOffset, false); } break; case 'M' : if (CharOperation.equals(attributeName, AttributeNamesConstants.MissingTypesName)) { // decode the missing types int missingTypeOffset = readOffset + 6; int numberOfMissingTypes = u2At(missingTypeOffset); if (numberOfMissingTypes != 0) { this.missingTypeNames = new char[numberOfMissingTypes][][]; missingTypeOffset += 2; for (int j = 0; j < numberOfMissingTypes; j++) { utf8Offset = this.constantPoolOffsets[u2At(this.constantPoolOffsets[u2At(missingTypeOffset)] + 1)]; char[] missingTypeConstantPoolName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); this.missingTypeNames[j] = CharOperation.splitOn('/', missingTypeConstantPoolName); missingTypeOffset += 2; } } } else if (CharOperation.equals(attributeName, AttributeNamesConstants.ModuleName)) { this.moduleDeclaration = ModuleInfo.createModule(this.reference, this.constantPoolOffsets, readOffset); this.moduleName = this.moduleDeclaration.name(); } break; case 'N' : if (CharOperation.equals(attributeName, AttributeNamesConstants.NestHost)) { utf8Offset = this.constantPoolOffsets[u2At(this.constantPoolOffsets[u2At(readOffset + 6)] + 1)]; this.nestHost = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); } else if (CharOperation.equals(attributeName, AttributeNamesConstants.NestMembers)) { int offset = readOffset + 6; this.nestMembersCount = u2At(offset); if (this.nestMembersCount != 0) { offset += 2; this.nestMembers = new char[this.nestMembersCount][]; for (int j = 0; j < this.nestMembersCount; j++) { utf8Offset = this.constantPoolOffsets[u2At(this.constantPoolOffsets[u2At(offset)] + 1)]; this.nestMembers[j] = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); offset += 2; } } } break; } readOffset += (6 + u4At(readOffset + 2)); } if (this.moduleDeclaration != null && this.annotations != null) { this.moduleDeclaration.setAnnotations(this.annotations, this.tagBits, fullyInitialize); this.annotations = null; } if (fullyInitialize) { initialize(); } } catch(ClassFormatException e) { throw e; } catch (Exception e) { throw new ClassFormatException(e, this.classFileName, ClassFormatException.ErrTruncatedInput, readOffset); } } public char[] getNestHost() { return this.nestHost; } @Override public ExternalAnnotationStatus getExternalAnnotationStatus() { return ExternalAnnotationStatus.NOT_EEA_CONFIGURED; }
Conditionally add external annotations to the mix. If 'member' is given it must be either of IBinaryField or IBinaryMethod, in which case we're seeking annotations for that member. Otherwise we're seeking annotations for top-level elements of a type (type parameters & super types).
/** * Conditionally add external annotations to the mix. * If 'member' is given it must be either of IBinaryField or IBinaryMethod, in which case we're seeking annotations for that member. * Otherwise we're seeking annotations for top-level elements of a type (type parameters & super types). */
@Override public ITypeAnnotationWalker enrichWithExternalAnnotationsFor(ITypeAnnotationWalker walker, Object member, LookupEnvironment environment) { return walker; }
Answer the receiver's access flags. The value of the access_flags item is a mask of modifiers used with class and interface declarations. @return int
/** * Answer the receiver's access flags. The value of the access_flags * item is a mask of modifiers used with class and interface declarations. * @return int */
public int accessFlags() { return this.accessFlags; } private void decodeAnnotations(int offset, boolean runtimeVisible) { int numberOfAnnotations = u2At(offset + 6); if (numberOfAnnotations > 0) { int readOffset = offset + 8; AnnotationInfo[] newInfos = null; int newInfoCount = 0; for (int i = 0; i < numberOfAnnotations; i++) { // With the last parameter being 'false', the data structure will not be flushed out AnnotationInfo newInfo = new AnnotationInfo(this.reference, this.constantPoolOffsets, readOffset, runtimeVisible, false); readOffset += newInfo.readOffset; long standardTagBits = newInfo.standardAnnotationTagBits; if (standardTagBits != 0) { this.tagBits |= standardTagBits; if (this.version < ClassFileConstants.JDK9 || (standardTagBits & TagBits.AnnotationDeprecated) == 0) continue; } if (newInfos == null) newInfos = new AnnotationInfo[numberOfAnnotations - i]; newInfos[newInfoCount++] = newInfo; } if (newInfos == null) return; // nothing to record in this.annotations if (this.annotations == null) { if (newInfoCount != newInfos.length) System.arraycopy(newInfos, 0, newInfos = new AnnotationInfo[newInfoCount], 0, newInfoCount); this.annotations = newInfos; } else { int length = this.annotations.length; AnnotationInfo[] temp = new AnnotationInfo[length + newInfoCount]; System.arraycopy(this.annotations, 0, temp, 0, length); System.arraycopy(newInfos, 0, temp, length, newInfoCount); this.annotations = temp; } } } private void decodeTypeAnnotations(int offset, boolean runtimeVisible) { int numberOfAnnotations = u2At(offset + 6); if (numberOfAnnotations > 0) { int readOffset = offset + 8; TypeAnnotationInfo[] newInfos = null; newInfos = new TypeAnnotationInfo[numberOfAnnotations]; for (int i = 0; i < numberOfAnnotations; i++) { // With the last parameter being 'false', the data structure will not be flushed out TypeAnnotationInfo newInfo = new TypeAnnotationInfo(this.reference, this.constantPoolOffsets, readOffset, runtimeVisible, false); readOffset += newInfo.readOffset; newInfos[i] = newInfo; } if (this.typeAnnotations == null) { this.typeAnnotations = newInfos; } else { int length = this.typeAnnotations.length; TypeAnnotationInfo[] temp = new TypeAnnotationInfo[length + numberOfAnnotations]; System.arraycopy(this.typeAnnotations, 0, temp, 0, length); System.arraycopy(newInfos, 0, temp, length, numberOfAnnotations); this.typeAnnotations = temp; } } }
Returns:the annotations or null if there is none.
/** * @return the annotations or null if there is none. */
@Override public IBinaryAnnotation[] getAnnotations() { return this.annotations; }
Returns:the type annotations or null if there is none.
/** * @return the type annotations or null if there is none. */
@Override public IBinaryTypeAnnotation[] getTypeAnnotations() { return this.typeAnnotations; }
Answer the char array that corresponds to the class name of the constant class. constantPoolIndex is the index in the constant pool that is a constant class entry.
Params:
  • constantPoolIndex – int
Returns:char[]
/** * Answer the char array that corresponds to the class name of the constant class. * constantPoolIndex is the index in the constant pool that is a constant class entry. * * @param constantPoolIndex int * @return char[] */
private char[] getConstantClassNameAt(int constantPoolIndex) { int utf8Offset = this.constantPoolOffsets[u2At(this.constantPoolOffsets[constantPoolIndex] + 1)]; return utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); }
Answer the int array that corresponds to all the offsets of each entry in the constant pool
Returns:int[]
/** * Answer the int array that corresponds to all the offsets of each entry in the constant pool * * @return int[] */
public int[] getConstantPoolOffsets() { return this.constantPoolOffsets; } @Override public char[] getEnclosingMethod() { if (this.enclosingNameAndTypeIndex <= 0) { return null; } if (this.enclosingMethod == null) { // read the name StringBuffer buffer = new StringBuffer(); int nameAndTypeOffset = this.constantPoolOffsets[this.enclosingNameAndTypeIndex]; int utf8Offset = this.constantPoolOffsets[u2At(nameAndTypeOffset + 1)]; buffer.append(utf8At(utf8Offset + 3, u2At(utf8Offset + 1))); utf8Offset = this.constantPoolOffsets[u2At(nameAndTypeOffset + 3)]; buffer.append(utf8At(utf8Offset + 3, u2At(utf8Offset + 1))); this.enclosingMethod = String.valueOf(buffer).toCharArray(); } return this.enclosingMethod; } /* * Answer the resolved compoundName of the enclosing type * or null if the receiver is a top level type. */ @Override public char[] getEnclosingTypeName() { return this.enclosingTypeName; }
Answer the receiver's this.fields or null if the array is empty.
Returns:org.eclipse.jdt.internal.compiler.api.IBinaryField[]
/** * Answer the receiver's this.fields or null if the array is empty. * @return org.eclipse.jdt.internal.compiler.api.IBinaryField[] */
@Override public IBinaryField[] getFields() { return this.fields; }
See Also:
  • getModule.getModule()
/** * @see IBinaryType#getModule() */
@Override public char[] getModule() { return this.moduleName; }
Returns the module declaration that this class file represents. This will be null for non module-info class files.
Returns:the module declaration this represents
/** * Returns the module declaration that this class file represents. This will be * null for non module-info class files. * * @return the module declaration this represents */
public IBinaryModule getModuleDeclaration() { return this.moduleDeclaration; }
See Also:
  • getFileName.getFileName()
/** * @see org.eclipse.jdt.internal.compiler.env.IDependent#getFileName() */
@Override public char[] getFileName() { return this.classFileName; } @Override public char[] getGenericSignature() { return this.signature; }
Answer the source name if the receiver is a inner type. Return null if it is an anonymous class or if the receiver is a top-level class. e.g. public class A { public class B { } public void foo() { class C {} } public Runnable bar() { return new Runnable() { public void run() {} }; } } It returns {'B'} for the member A$B It returns null for A It returns {'C'} for the local class A$1$C It returns null for the anonymous A$1
Returns:char[]
/** * Answer the source name if the receiver is a inner type. Return null if it is an anonymous class or if the receiver is a top-level class. * e.g. * public class A { * public class B { * } * public void foo() { * class C {} * } * public Runnable bar() { * return new Runnable() { * public void run() {} * }; * } * } * It returns {'B'} for the member A$B * It returns null for A * It returns {'C'} for the local class A$1$C * It returns null for the anonymous A$1 * @return char[] */
public char[] getInnerSourceName() { if (this.innerInfo != null) return this.innerInfo.getSourceName(); return null; } @Override public char[][] getInterfaceNames() { return this.interfaceNames; } @Override public IBinaryNestedType[] getMemberTypes() { // we might have some member types of the current type if (this.innerInfos == null) return null; int length = this.innerInfos.length - (this.innerInfo != null ? 1 : 0); if (length != 0) { IBinaryNestedType[] memberTypes = new IBinaryNestedType[length]; int memberTypeIndex = 0; for (InnerClassInfo currentInnerInfo : this.innerInfos) { int outerClassNameIdx = currentInnerInfo.outerClassNameIndex; int innerNameIndex = currentInnerInfo.innerNameIndex; /* * Checking that outerClassNameIDx is different from 0 should be enough to determine if an inner class * attribute entry is a member class, but due to the bug: * http://dev.eclipse.org/bugs/show_bug.cgi?id=14592 * we needed to add an extra check. So we check that innerNameIndex is different from 0 as well. * * https://bugs.eclipse.org/bugs/show_bug.cgi?id=49879 * From JavaMail 1.2, the class javax.mail.Folder contains an anonymous class in the * terminateQueue() method for which the inner attribute is boggus. * outerClassNameIdx is not 0, innerNameIndex is not 0, but the sourceName length is 0. * So I added this extra check to filter out this anonymous class from the * member types. */ if (outerClassNameIdx != 0 && innerNameIndex != 0 && outerClassNameIdx == this.classNameIndex && currentInnerInfo.getSourceName().length != 0) { memberTypes[memberTypeIndex++] = currentInnerInfo; } } if (memberTypeIndex == 0) return null; if (memberTypeIndex != memberTypes.length) { // we need to resize the memberTypes array. Some local or anonymous classes // are present in the current class. System.arraycopy( memberTypes, 0, (memberTypes = new IBinaryNestedType[memberTypeIndex]), 0, memberTypeIndex); } return memberTypes; } return null; }
Answer the receiver's this.methods or null if the array is empty.
Returns:org.eclipse.jdt.internal.compiler.api.env.IBinaryMethod[]
/** * Answer the receiver's this.methods or null if the array is empty. * @return org.eclipse.jdt.internal.compiler.api.env.IBinaryMethod[] */
@Override public IBinaryMethod[] getMethods() { return this.methods; } /* public static void main(String[] args) throws ClassFormatException, IOException { if (args == null || args.length != 1) { System.err.println("ClassFileReader <filename>"); //$NON-NLS-1$ System.exit(1); } File file = new File(args[0]); ClassFileReader reader = read(file, true); if (reader.annotations != null) { System.err.println(); for (int i = 0; i < reader.annotations.length; i++) System.err.println(reader.annotations[i]); } System.err.print("class "); //$NON-NLS-1$ System.err.print(reader.getName()); char[] superclass = reader.getSuperclassName(); if (superclass != null) { System.err.print(" extends "); //$NON-NLS-1$ System.err.print(superclass); } System.err.println(); char[][] interfaces = reader.getInterfaceNames(); if (interfaces != null && interfaces.length > 0) { System.err.print(" implements "); //$NON-NLS-1$ for (int i = 0; i < interfaces.length; i++) { if (i != 0) System.err.print(", "); //$NON-NLS-1$ System.err.println(interfaces[i]); } } System.err.println(); System.err.println('{'); if (reader.fields != null) { for (int i = 0; i < reader.fields.length; i++) { System.err.println(reader.fields[i]); System.err.println(); } } if (reader.methods != null) { for (int i = 0; i < reader.methods.length; i++) { System.err.println(reader.methods[i]); System.err.println(); } } System.err.println(); System.err.println('}'); } */ @Override public char[][][] getMissingTypeNames() { return this.missingTypeNames; }
Answer an int whose bits are set according the access constants defined by the VM spec. Set the AccDeprecated and AccSynthetic bits if necessary
Returns:int
/** * Answer an int whose bits are set according the access constants * defined by the VM spec. * Set the AccDeprecated and AccSynthetic bits if necessary * @return int */
@Override public int getModifiers() { int modifiers; if (this.innerInfo != null) { modifiers = this.innerInfo.getModifiers() | (this.accessFlags & ClassFileConstants.AccDeprecated) | (this.accessFlags & ClassFileConstants.AccSynthetic); } else { modifiers = this.accessFlags; } return modifiers; } @Override public char[] getName() { return this.className; } @Override public char[] getSourceName() { if (this.sourceName != null) return this.sourceName; char[] name = getInnerSourceName(); // member or local scenario if (name == null) { name = getName(); // extract from full name int start; if (isAnonymous()) { start = CharOperation.indexOf('$', name, CharOperation.lastIndexOf('/', name) + 1) + 1; } else { start = CharOperation.lastIndexOf('/', name) + 1; } if (start > 0) { char[] newName = new char[name.length - start]; System.arraycopy(name, start, newName, 0, newName.length); name = newName; } } return this.sourceName = name; } @Override public char[] getSuperclassName() { return this.superclassName; } @Override public long getTagBits() { return this.tagBits; }
Answer the major/minor version defined in this class file according to the VM spec. as a long: (major<<16)+minor
Returns:the major/minor version found
/** * Answer the major/minor version defined in this class file according to the VM spec. * as a long: (major<<16)+minor * @return the major/minor version found */
public long getVersion() { return this.version; } private boolean hasNonSyntheticFieldChanges(FieldInfo[] currentFieldInfos, FieldInfo[] otherFieldInfos) { int length1 = currentFieldInfos == null ? 0 : currentFieldInfos.length; int length2 = otherFieldInfos == null ? 0 : otherFieldInfos.length; int index1 = 0; int index2 = 0; end : while (index1 < length1 && index2 < length2) { while (currentFieldInfos[index1].isSynthetic()) { if (++index1 >= length1) break end; } while (otherFieldInfos[index2].isSynthetic()) { if (++index2 >= length2) break end; } if (hasStructuralFieldChanges(currentFieldInfos[index1++], otherFieldInfos[index2++])) return true; } while (index1 < length1) { if (!currentFieldInfos[index1++].isSynthetic()) return true; } while (index2 < length2) { if (!otherFieldInfos[index2++].isSynthetic()) return true; } return false; } private boolean hasNonSyntheticMethodChanges(MethodInfo[] currentMethodInfos, MethodInfo[] otherMethodInfos) { int length1 = currentMethodInfos == null ? 0 : currentMethodInfos.length; int length2 = otherMethodInfos == null ? 0 : otherMethodInfos.length; int index1 = 0; int index2 = 0; MethodInfo m; end : while (index1 < length1 && index2 < length2) { while ((m = currentMethodInfos[index1]).isSynthetic() || m.isClinit()) { if (++index1 >= length1) break end; } while ((m = otherMethodInfos[index2]).isSynthetic() || m.isClinit()) { if (++index2 >= length2) break end; } if (hasStructuralMethodChanges(currentMethodInfos[index1++], otherMethodInfos[index2++])) return true; } while (index1 < length1) { if (!((m = currentMethodInfos[index1++]).isSynthetic() || m.isClinit())) return true; } while (index2 < length2) { if (!((m = otherMethodInfos[index2++]).isSynthetic() || m.isClinit())) return true; } return false; }
Check if the receiver has structural changes compare to the byte array in argument. Structural changes are: - modifiers changes for the class, the this.fields or the this.methods - signature changes for this.fields or this.methods. - changes in the number of this.fields or this.methods - changes for field constants - changes for thrown exceptions - change for the super class or any super interfaces. - changes for member types name or modifiers If any of these changes occurs, the method returns true. false otherwise. The synthetic fields are included and the members are not required to be sorted.
Params:
  • newBytes – the bytes of the .class file we want to compare the receiver to
Returns:boolean Returns true is there is a structural change between the two .class files, false otherwise
/** * Check if the receiver has structural changes compare to the byte array in argument. * Structural changes are: * - modifiers changes for the class, the this.fields or the this.methods * - signature changes for this.fields or this.methods. * - changes in the number of this.fields or this.methods * - changes for field constants * - changes for thrown exceptions * - change for the super class or any super interfaces. * - changes for member types name or modifiers * If any of these changes occurs, the method returns true. false otherwise. * The synthetic fields are included and the members are not required to be sorted. * @param newBytes the bytes of the .class file we want to compare the receiver to * @return boolean Returns true is there is a structural change between the two .class files, false otherwise */
public boolean hasStructuralChanges(byte[] newBytes) { return hasStructuralChanges(newBytes, true, true); }
Check if the receiver has structural changes compare to the byte array in argument. Structural changes are: - modifiers changes for the class, the this.fields or the this.methods - signature changes for this.fields or this.methods. - changes in the number of this.fields or this.methods - changes for field constants - changes for thrown exceptions - change for the super class or any super interfaces. - changes for member types name or modifiers If any of these changes occurs, the method returns true. false otherwise.
Params:
  • newBytes – the bytes of the .class file we want to compare the receiver to
  • orderRequired – a boolean indicating whether the members should be sorted or not
  • excludesSynthetic – a boolean indicating whether the synthetic members should be used in the comparison
Returns:boolean Returns true is there is a structural change between the two .class files, false otherwise
/** * Check if the receiver has structural changes compare to the byte array in argument. * Structural changes are: * - modifiers changes for the class, the this.fields or the this.methods * - signature changes for this.fields or this.methods. * - changes in the number of this.fields or this.methods * - changes for field constants * - changes for thrown exceptions * - change for the super class or any super interfaces. * - changes for member types name or modifiers * If any of these changes occurs, the method returns true. false otherwise. * @param newBytes the bytes of the .class file we want to compare the receiver to * @param orderRequired a boolean indicating whether the members should be sorted or not * @param excludesSynthetic a boolean indicating whether the synthetic members should be used in the comparison * @return boolean Returns true is there is a structural change between the two .class files, false otherwise */
public boolean hasStructuralChanges(byte[] newBytes, boolean orderRequired, boolean excludesSynthetic) { try { ClassFileReader newClassFile = new ClassFileReader(newBytes, this.classFileName); // type level comparison // modifiers if (getModifiers() != newClassFile.getModifiers()) return true; // only consider a portion of the tagbits which indicate a structural change for dependents // e.g. @Override change has no influence outside long OnlyStructuralTagBits = TagBits.AnnotationTargetMASK // different @Target status ? | TagBits.AnnotationDeprecated // different @Deprecated status ? | TagBits.AnnotationRetentionMASK // different @Retention status ? | TagBits.HierarchyHasProblems; // different hierarchy status ? // meta-annotations if ((getTagBits() & OnlyStructuralTagBits) != (newClassFile.getTagBits() & OnlyStructuralTagBits)) return true; // annotations if (hasStructuralAnnotationChanges(getAnnotations(), newClassFile.getAnnotations())) return true; if (this.version >= ClassFileConstants.JDK1_8 && hasStructuralTypeAnnotationChanges(getTypeAnnotations(), newClassFile.getTypeAnnotations())) return true; // generic signature if (!CharOperation.equals(getGenericSignature(), newClassFile.getGenericSignature())) return true; // superclass if (!CharOperation.equals(getSuperclassName(), newClassFile.getSuperclassName())) return true; // interfaces char[][] newInterfacesNames = newClassFile.getInterfaceNames(); if (this.interfaceNames != newInterfacesNames) { // TypeConstants.NoSuperInterfaces int newInterfacesLength = newInterfacesNames == null ? 0 : newInterfacesNames.length; if (newInterfacesLength != this.interfacesCount) return true; for (int i = 0, max = this.interfacesCount; i < max; i++) if (!CharOperation.equals(this.interfaceNames[i], newInterfacesNames[i])) return true; } // member types IBinaryNestedType[] currentMemberTypes = getMemberTypes(); IBinaryNestedType[] otherMemberTypes = newClassFile.getMemberTypes(); if (currentMemberTypes != otherMemberTypes) { // TypeConstants.NoMemberTypes int currentMemberTypeLength = currentMemberTypes == null ? 0 : currentMemberTypes.length; int otherMemberTypeLength = otherMemberTypes == null ? 0 : otherMemberTypes.length; if (currentMemberTypeLength != otherMemberTypeLength) return true; for (int i = 0; i < currentMemberTypeLength; i++) if (!CharOperation.equals(currentMemberTypes[i].getName(), otherMemberTypes[i].getName()) || currentMemberTypes[i].getModifiers() != otherMemberTypes[i].getModifiers()) return true; } // fields FieldInfo[] otherFieldInfos = (FieldInfo[]) newClassFile.getFields(); int otherFieldInfosLength = otherFieldInfos == null ? 0 : otherFieldInfos.length; boolean compareFields = true; if (this.fieldsCount == otherFieldInfosLength) { int i = 0; for (; i < this.fieldsCount; i++) if (hasStructuralFieldChanges(this.fields[i], otherFieldInfos[i])) break; if ((compareFields = i != this.fieldsCount) && !orderRequired && !excludesSynthetic) return true; } if (compareFields) { if (this.fieldsCount != otherFieldInfosLength && !excludesSynthetic) return true; if (orderRequired) { if (this.fieldsCount != 0) Arrays.sort(this.fields); if (otherFieldInfosLength != 0) Arrays.sort(otherFieldInfos); } if (excludesSynthetic) { if (hasNonSyntheticFieldChanges(this.fields, otherFieldInfos)) return true; } else { for (int i = 0; i < this.fieldsCount; i++) if (hasStructuralFieldChanges(this.fields[i], otherFieldInfos[i])) return true; } } // methods MethodInfo[] otherMethodInfos = (MethodInfo[]) newClassFile.getMethods(); int otherMethodInfosLength = otherMethodInfos == null ? 0 : otherMethodInfos.length; boolean compareMethods = true; if (this.methodsCount == otherMethodInfosLength) { int i = 0; for (; i < this.methodsCount; i++) if (hasStructuralMethodChanges(this.methods[i], otherMethodInfos[i])) break; if ((compareMethods = i != this.methodsCount) && !orderRequired && !excludesSynthetic) return true; } if (compareMethods) { if (this.methodsCount != otherMethodInfosLength && !excludesSynthetic) return true; if (orderRequired) { if (this.methodsCount != 0) Arrays.sort(this.methods); if (otherMethodInfosLength != 0) Arrays.sort(otherMethodInfos); } if (excludesSynthetic) { if (hasNonSyntheticMethodChanges(this.methods, otherMethodInfos)) return true; } else { for (int i = 0; i < this.methodsCount; i++) if (hasStructuralMethodChanges(this.methods[i], otherMethodInfos[i])) return true; } } // missing types char[][][] missingTypes = getMissingTypeNames(); char[][][] newMissingTypes = newClassFile.getMissingTypeNames(); if (missingTypes != null) { if (newMissingTypes == null) { return true; } int length = missingTypes.length; if (length != newMissingTypes.length) { return true; } for (int i = 0; i < length; i++) { if (!CharOperation.equals(missingTypes[i], newMissingTypes[i])) { return true; } } } else if (newMissingTypes != null) { return true; } return false; } catch (ClassFormatException e) { return true; } } private boolean hasStructuralAnnotationChanges(IBinaryAnnotation[] currentAnnotations, IBinaryAnnotation[] otherAnnotations) { if (currentAnnotations == otherAnnotations) return false; int currentAnnotationsLength = currentAnnotations == null ? 0 : currentAnnotations.length; int otherAnnotationsLength = otherAnnotations == null ? 0 : otherAnnotations.length; if (currentAnnotationsLength != otherAnnotationsLength) return true; for (int i = 0; i < currentAnnotationsLength; i++) { Boolean match = matchAnnotations(currentAnnotations[i], otherAnnotations[i]); if (match != null) return match.booleanValue(); } return false; } private Boolean matchAnnotations(IBinaryAnnotation currentAnnotation, IBinaryAnnotation otherAnnotation) { if (!CharOperation.equals(currentAnnotation.getTypeName(), otherAnnotation.getTypeName())) return true; IBinaryElementValuePair[] currentPairs = currentAnnotation.getElementValuePairs(); IBinaryElementValuePair[] otherPairs = otherAnnotation.getElementValuePairs(); int currentPairsLength = currentPairs == null ? 0 : currentPairs.length; int otherPairsLength = otherPairs == null ? 0 : otherPairs.length; if (currentPairsLength != otherPairsLength) return Boolean.TRUE; for (int j = 0; j < currentPairsLength; j++) { if (!CharOperation.equals(currentPairs[j].getName(), otherPairs[j].getName())) return Boolean.TRUE; final Object value = currentPairs[j].getValue(); final Object value2 = otherPairs[j].getValue(); if (value instanceof Object[]) { Object[] currentValues = (Object[]) value; if (value2 instanceof Object[]) { Object[] currentValues2 = (Object[]) value2; final int length = currentValues.length; if (length != currentValues2.length) { return Boolean.TRUE; } for (int n = 0; n < length; n++) { if (!currentValues[n].equals(currentValues2[n])) { return Boolean.TRUE; } } return Boolean.FALSE; } return Boolean.TRUE; } else if (!value.equals(value2)) { return Boolean.TRUE; } } return null; } private boolean hasStructuralFieldChanges(FieldInfo currentFieldInfo, FieldInfo otherFieldInfo) { // generic signature if (!CharOperation.equals(currentFieldInfo.getGenericSignature(), otherFieldInfo.getGenericSignature())) return true; if (currentFieldInfo.getModifiers() != otherFieldInfo.getModifiers()) return true; if ((currentFieldInfo.getTagBits() & TagBits.AnnotationDeprecated) != (otherFieldInfo.getTagBits() & TagBits.AnnotationDeprecated)) return true; if (hasStructuralAnnotationChanges(currentFieldInfo.getAnnotations(), otherFieldInfo.getAnnotations())) return true; if (this.version >= ClassFileConstants.JDK1_8 && hasStructuralTypeAnnotationChanges(currentFieldInfo.getTypeAnnotations(), otherFieldInfo.getTypeAnnotations())) return true; if (!CharOperation.equals(currentFieldInfo.getName(), otherFieldInfo.getName())) return true; if (!CharOperation.equals(currentFieldInfo.getTypeName(), otherFieldInfo.getTypeName())) return true; if (currentFieldInfo.hasConstant() != otherFieldInfo.hasConstant()) return true; if (currentFieldInfo.hasConstant()) { Constant currentConstant = currentFieldInfo.getConstant(); Constant otherConstant = otherFieldInfo.getConstant(); if (currentConstant.typeID() != otherConstant.typeID()) return true; if (!currentConstant.getClass().equals(otherConstant.getClass())) return true; switch (currentConstant.typeID()) { case TypeIds.T_int : return currentConstant.intValue() != otherConstant.intValue(); case TypeIds.T_byte : return currentConstant.byteValue() != otherConstant.byteValue(); case TypeIds.T_short : return currentConstant.shortValue() != otherConstant.shortValue(); case TypeIds.T_char : return currentConstant.charValue() != otherConstant.charValue(); case TypeIds.T_long : return currentConstant.longValue() != otherConstant.longValue(); case TypeIds.T_float : return currentConstant.floatValue() != otherConstant.floatValue(); case TypeIds.T_double : return currentConstant.doubleValue() != otherConstant.doubleValue(); case TypeIds.T_boolean : return currentConstant.booleanValue() != otherConstant.booleanValue(); case TypeIds.T_JavaLangString : return !currentConstant.stringValue().equals(otherConstant.stringValue()); } } return false; } private boolean hasStructuralMethodChanges(MethodInfo currentMethodInfo, MethodInfo otherMethodInfo) { // generic signature if (!CharOperation.equals(currentMethodInfo.getGenericSignature(), otherMethodInfo.getGenericSignature())) return true; if (currentMethodInfo.getModifiers() != otherMethodInfo.getModifiers()) return true; if ((currentMethodInfo.getTagBits() & TagBits.AnnotationDeprecated) != (otherMethodInfo.getTagBits() & TagBits.AnnotationDeprecated)) return true; if (hasStructuralAnnotationChanges(currentMethodInfo.getAnnotations(), otherMethodInfo.getAnnotations())) return true; // parameter annotations: int currentAnnotatedParamsCount = currentMethodInfo.getAnnotatedParametersCount(); int otherAnnotatedParamsCount = otherMethodInfo.getAnnotatedParametersCount(); if (currentAnnotatedParamsCount != otherAnnotatedParamsCount) return true; for (int i=0; i<currentAnnotatedParamsCount; i++) { if (hasStructuralAnnotationChanges(currentMethodInfo.getParameterAnnotations(i, this.classFileName), otherMethodInfo.getParameterAnnotations(i, this.classFileName))) return true; } if (this.version >= ClassFileConstants.JDK1_8 && hasStructuralTypeAnnotationChanges(currentMethodInfo.getTypeAnnotations(), otherMethodInfo.getTypeAnnotations())) return true; if (!CharOperation.equals(currentMethodInfo.getSelector(), otherMethodInfo.getSelector())) return true; if (!CharOperation.equals(currentMethodInfo.getMethodDescriptor(), otherMethodInfo.getMethodDescriptor())) return true; if (!CharOperation.equals(currentMethodInfo.getGenericSignature(), otherMethodInfo.getGenericSignature())) return true; char[][] currentThrownExceptions = currentMethodInfo.getExceptionTypeNames(); char[][] otherThrownExceptions = otherMethodInfo.getExceptionTypeNames(); if (currentThrownExceptions != otherThrownExceptions) { // TypeConstants.NoExceptions int currentThrownExceptionsLength = currentThrownExceptions == null ? 0 : currentThrownExceptions.length; int otherThrownExceptionsLength = otherThrownExceptions == null ? 0 : otherThrownExceptions.length; if (currentThrownExceptionsLength != otherThrownExceptionsLength) return true; for (int k = 0; k < currentThrownExceptionsLength; k++) if (!CharOperation.equals(currentThrownExceptions[k], otherThrownExceptions[k])) return true; } return false; } private boolean hasStructuralTypeAnnotationChanges(IBinaryTypeAnnotation[] currentTypeAnnotations, IBinaryTypeAnnotation[] otherTypeAnnotations) { if (otherTypeAnnotations != null) { // copy so we can delete matched annotations: int len = otherTypeAnnotations.length; System.arraycopy(otherTypeAnnotations, 0, otherTypeAnnotations = new IBinaryTypeAnnotation[len], 0, len); } if (currentTypeAnnotations != null) { loopCurrent: for (IBinaryTypeAnnotation currentAnnotation : currentTypeAnnotations) { if (!affectsSignature(currentAnnotation)) continue; if (otherTypeAnnotations == null) return true; for (int i = 0; i < otherTypeAnnotations.length; i++) { IBinaryTypeAnnotation otherAnnotation = otherTypeAnnotations[i]; if (otherAnnotation != null && matchAnnotations(currentAnnotation.getAnnotation(), otherAnnotation.getAnnotation()) == Boolean.TRUE) { otherTypeAnnotations[i] = null; // matched continue loopCurrent; } } return true; // not matched } } if (otherTypeAnnotations != null) { for (IBinaryTypeAnnotation otherAnnotation : otherTypeAnnotations) { if (affectsSignature(otherAnnotation)) return true; } } return false; } private boolean affectsSignature(IBinaryTypeAnnotation typeAnnotation) { if (typeAnnotation == null) return false; int targetType = typeAnnotation.getTargetType(); if (targetType >= AnnotationTargetTypeConstants.LOCAL_VARIABLE && targetType <= AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT) return false; // affects detail within a block return true; }
This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos will be therefore fully initialized and we can get rid of the bytes.
/** * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos * will be therefore fully initialized and we can get rid of the bytes. */
private void initialize() throws ClassFormatException { try { for (int i = 0, max = this.fieldsCount; i < max; i++) { this.fields[i].initialize(); } for (int i = 0, max = this.methodsCount; i < max; i++) { this.methods[i].initialize(); } if (this.innerInfos != null) { for (int i = 0, max = this.innerInfos.length; i < max; i++) { this.innerInfos[i].initialize(); } } if (this.annotations != null) { for (int i = 0, max = this.annotations.length; i < max; i++) { this.annotations[i].initialize(); } } this.getEnclosingMethod(); reset(); } catch(RuntimeException e) { ClassFormatException exception = new ClassFormatException(e, this.classFileName); throw exception; } } @Override public boolean isAnonymous() { if (this.innerInfo == null) return false; char[] innerSourceName = this.innerInfo.getSourceName(); return (innerSourceName == null || innerSourceName.length == 0); } @Override public boolean isBinaryType() { return true; } @Override public boolean isLocal() { if (this.innerInfo == null) return false; if (this.innerInfo.getEnclosingTypeName() != null) return false; char[] innerSourceName = this.innerInfo.getSourceName(); return (innerSourceName != null && innerSourceName.length > 0); } @Override public boolean isMember() { if (this.innerInfo == null) return false; if (this.innerInfo.getEnclosingTypeName() == null) return false; char[] innerSourceName = this.innerInfo.getSourceName(); return (innerSourceName != null && innerSourceName.length > 0); // protection against ill-formed attributes (67600) }
Answer true if the receiver is a nested type, false otherwise
Returns:boolean
/** * Answer true if the receiver is a nested type, false otherwise * * @return <CODE>boolean</CODE> */
public boolean isNestedType() { return this.innerInfo != null; }
Answer the source file name attribute. Return null if there is no source file attribute for the receiver.
Returns:char[]
/** * Answer the source file name attribute. Return null if there is no source file attribute for the receiver. * * @return char[] */
@Override public char[] sourceFileName() { return this.sourceFileName; } @Override public String toString() { java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); java.io.PrintWriter print = new java.io.PrintWriter(out); print.println(getClass().getName() + "{"); //$NON-NLS-1$ print.println(" this.className: " + new String(getName())); //$NON-NLS-1$ print.println(" this.superclassName: " + (getSuperclassName() == null ? "null" : new String(getSuperclassName()))); //$NON-NLS-2$ //$NON-NLS-1$ if (this.moduleName != null) print.println(" this.moduleName: " + (new String(this.moduleName))); //$NON-NLS-1$ print.println(" access_flags: " + printTypeModifiers(accessFlags()) + "(" + accessFlags() + ")"); //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ print.flush(); return out.toString(); } }