import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.impl.StringConstant;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
*/
public class ClassFile
implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds {
- public SourceTypeBinding referenceBinding;
- public ConstantPool constantPool;
- public ClassFile enclosingClassFile;
- // used to generate private access methods
- public int produceDebugAttributes;
- public ReferenceBinding[] innerClassesBindings;
- public int numberOfInnerClasses;
- public byte[] header;
+ public static final int INITIAL_CONTENTS_SIZE = 400;
+ public static final int INITIAL_HEADER_SIZE = 1500;
+ public static final int INNER_CLASSES_SIZE = 5;
+
+ /**
+ * INTERNAL USE-ONLY
+ * Build all the directories and subdirectories corresponding to the packages names
+ * into the directory specified in parameters.
+ *
+ * outputPath is formed like:
+ * c:\temp\ the last character is a file separator
+ * relativeFileName is formed like:
+ * java\lang\String.class *
+ *
+ * @param outputPath java.lang.String
+ * @param relativeFileName java.lang.String
+ * @return java.lang.String
+ */
+ public static String buildAllDirectoriesInto(
+ String outputPath,
+ String relativeFileName)
+ throws IOException {
+ char fileSeparatorChar = File.separatorChar;
+ String fileSeparator = File.separator;
+ File f;
+ // First we ensure that the outputPath exists
+ outputPath = outputPath.replace('/', fileSeparatorChar);
+ // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
+ if (outputPath.endsWith(fileSeparator)) {
+ outputPath = outputPath.substring(0, outputPath.length() - 1);
+ }
+ f = new File(outputPath);
+ if (f.exists()) {
+ if (!f.isDirectory()) {
+ System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$
+ throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$
+ }
+ } else {
+ // we have to create that directory
+ if (!f.mkdirs()) {
+ System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$
+ throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$
+ }
+ }
+ StringBuffer outDir = new StringBuffer(outputPath);
+ outDir.append(fileSeparator);
+ StringTokenizer tokenizer =
+ new StringTokenizer(relativeFileName, fileSeparator);
+ String token = tokenizer.nextToken();
+ while (tokenizer.hasMoreTokens()) {
+ f = new File(outDir.append(token).append(fileSeparator).toString());
+ if (f.exists()) {
+ // The outDir already exists, so we proceed the next entry
+ // System.out.println("outDir: " + outDir + " already exists.");
+ } else {
+ // Need to add the outDir
+ if (!f.mkdir()) {
+ System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$
+ throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$
+ }
+ }
+ token = tokenizer.nextToken();
+ }
+ // token contains the last one
+ return outDir.append(token).toString();
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Request the creation of a ClassFile compatible representation of a problematic type
+ *
+ * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
+ * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
+ */
+ public static void createProblemType(
+ TypeDeclaration typeDeclaration,
+ CompilationResult unitResult) {
+ SourceTypeBinding typeBinding = typeDeclaration.binding;
+ ClassFile classFile = new ClassFile(typeBinding, null, true);
+
+ // TODO (olivier) handle cases where a field cannot be generated (name too long)
+ // TODO (olivier) handle too many methods
+ // inner attributes
+ if (typeBinding.isMemberType())
+ classFile.recordEnclosingTypeAttributes(typeBinding);
+
+ // add its fields
+ FieldBinding[] fields = typeBinding.fields;
+ if ((fields != null) && (fields != NoFields)) {
+ for (int i = 0, max = fields.length; i < max; i++) {
+ if (fields[i].constant() == null) {
+ FieldReference.getConstantFor(fields[i], null, false, null);
+ }
+ }
+ classFile.addFieldInfos();
+ } else {
+ // we have to set the number of fields to be equals to 0
+ classFile.contents[classFile.contentsOffset++] = 0;
+ classFile.contents[classFile.contentsOffset++] = 0;
+ }
+ // leave some space for the methodCount
+ classFile.setForMethodInfos();
+ // add its user defined methods
+ MethodBinding[] methods = typeBinding.methods;
+ AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
+ int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
+ int problemsLength;
+ IProblem[] problems = unitResult.getErrors();
+ if (problems == null) {
+ problems = new IProblem[0];
+ }
+ IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+ System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+ if (methods != null) {
+ if (typeBinding.isInterface()) {
+ // we cannot create problem methods for an interface. So we have to generate a clinit
+ // which should contain all the problem
+ classFile.addProblemClinit(problemsCopy);
+ for (int i = 0, max = methods.length; i < max; i++) {
+ MethodBinding methodBinding;
+ if ((methodBinding = methods[i]) != null) {
+ // find the corresponding method declaration
+ for (int j = 0; j < maxMethodDecl; j++) {
+ if ((methodDeclarations[j] != null)
+ && (methodDeclarations[j].binding == methods[i])) {
+ if (!methodBinding.isConstructor()) {
+ classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
+ }
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ for (int i = 0, max = methods.length; i < max; i++) {
+ MethodBinding methodBinding;
+ if ((methodBinding = methods[i]) != null) {
+ // find the corresponding method declaration
+ for (int j = 0; j < maxMethodDecl; j++) {
+ if ((methodDeclarations[j] != null)
+ && (methodDeclarations[j].binding == methods[i])) {
+ AbstractMethodDeclaration methodDecl;
+ if ((methodDecl = methodDeclarations[j]).isConstructor()) {
+ classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
+ } else {
+ classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ // add abstract methods
+ classFile.addDefaultAbstractMethods();
+ }
+ // propagate generation of (problem) member types
+ if (typeDeclaration.memberTypes != null) {
+ for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
+ TypeDeclaration memberType = typeDeclaration.memberTypes[i];
+ if (memberType.binding != null) {
+ classFile.recordNestedMemberAttribute(memberType.binding);
+ ClassFile.createProblemType(memberType, unitResult);
+ }
+ }
+ }
+ classFile.addAttributes();
+ unitResult.record(typeBinding.constantPoolName(), classFile);
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Search the line number corresponding to a specific position
+ */
+ public static final int searchLineNumber(
+ int[] startLineIndexes,
+ int position) {
+ // this code is completely useless, but it is the same implementation than
+ // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
+ // if (startLineIndexes == null)
+ // return 1;
+ int length = startLineIndexes.length;
+ if (length == 0)
+ return 1;
+ int g = 0, d = length - 1;
+ int m = 0;
+ while (g <= d) {
+ m = (g + d) / 2;
+ if (position < startLineIndexes[m]) {
+ d = m - 1;
+ } else
+ if (position > startLineIndexes[m]) {
+ g = m + 1;
+ } else {
+ return m + 1;
+ }
+ }
+ if (position < startLineIndexes[m]) {
+ return m + 1;
+ }
+ return m + 2;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * outputPath is formed like:
+ * c:\temp\ the last character is a file separator
+ * relativeFileName is formed like:
+ * java\lang\String.class
+ * @param generatePackagesStructure a flag to know if the packages structure has to be generated.
+ * @param outputPath the output directory
+ * @param relativeFileName java.lang.String
+ * @param contents byte[]
+ *
+ */
+ public static void writeToDisk(
+ boolean generatePackagesStructure,
+ String outputPath,
+ String relativeFileName,
+ byte[] contents)
+ throws IOException {
+
+ BufferedOutputStream output = null;
+ if (generatePackagesStructure) {
+ output = new BufferedOutputStream(
+ new FileOutputStream(
+ new File(buildAllDirectoriesInto(outputPath, relativeFileName))));
+ } else {
+ String fileName = null;
+ char fileSeparatorChar = File.separatorChar;
+ String fileSeparator = File.separator;
+ // First we ensure that the outputPath exists
+ outputPath = outputPath.replace('/', fileSeparatorChar);
+ // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
+ int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
+ if (indexOfPackageSeparator == -1) {
+ if (outputPath.endsWith(fileSeparator)) {
+ fileName = outputPath + relativeFileName;
+ } else {
+ fileName = outputPath + fileSeparator + relativeFileName;
+ }
+ } else {
+ int length = relativeFileName.length();
+ if (outputPath.endsWith(fileSeparator)) {
+ fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
+ } else {
+ fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
+ }
+ }
+ output = new BufferedOutputStream(
+ new FileOutputStream(
+ new File(fileName)));
+ }
+ try {
+ output.write(contents);
+ } finally {
+ output.flush();
+ output.close();
+ }
+ }
+ public CodeStream codeStream;
+ public ConstantPool constantPool;
+ public int constantPoolOffset;
// the header contains all the bytes till the end of the constant pool
public byte[] contents;
+ public int contentsOffset;
+ protected boolean creatingProblemType;
+ public ClassFile enclosingClassFile;
+ public byte[] header;
// that collection contains all the remaining bytes of the .class file
public int headerOffset;
- public int contentsOffset;
- public int constantPoolOffset;
- public int methodCountOffset;
+ public ReferenceBinding[] innerClassesBindings;
public int methodCount;
- protected boolean creatingProblemType;
- public static final int INITIAL_CONTENTS_SIZE = 400;
- public static final int INITIAL_HEADER_SIZE = 1500;
+ public int methodCountOffset;
+ public int numberOfInnerClasses;
public boolean ownSharedArrays = false; // flag set when header/contents are set to shared arrays
- public static final int INNER_CLASSES_SIZE = 5;
- public CodeStream codeStream;
- protected int problemLine; // used to create line number attributes for problem methods
+ // used to generate private access methods
+ public int produceDebugAttributes;
+ public SourceTypeBinding referenceBinding;
public long targetJDK;
/**
ClassFile enclosingClassFile,
boolean creatingProblemType) {
- referenceBinding = aType;
+ this.referenceBinding = aType;
initByteArrays();
// generate the magic numbers inside the header
header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
- this.targetJDK = referenceBinding.scope.environment().options.targetJDK;
+ final CompilerOptions options = aType.scope.environment().options;
+ this.targetJDK = options.targetJDK;
header[headerOffset++] = (byte) (this.targetJDK >> 8); // minor high
header[headerOffset++] = (byte) (this.targetJDK >> 0); // minor low
header[headerOffset++] = (byte) (this.targetJDK >> 24); // major high
// now we continue to generate the bytes inside the contents array
contents[contentsOffset++] = (byte) (accessFlags >> 8);
contents[contentsOffset++] = (byte) accessFlags;
- int classNameIndex = constantPool.literalIndex(aType);
+ int classNameIndex = constantPool.literalIndexForType(aType.constantPoolName());
contents[contentsOffset++] = (byte) (classNameIndex >> 8);
contents[contentsOffset++] = (byte) classNameIndex;
int superclassNameIndex;
if (aType.isInterface()) {
- superclassNameIndex = constantPool.literalIndexForJavaLangObject();
+ superclassNameIndex = constantPool.literalIndexForType(ConstantPool.JavaLangObjectConstantPoolName);
} else {
superclassNameIndex =
- (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass));
+ (aType.superclass == null ? 0 : constantPool.literalIndexForType(aType.superclass.constantPoolName()));
}
contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
contents[contentsOffset++] = (byte) superclassNameIndex;
contents[contentsOffset++] = (byte) (interfacesCount >> 8);
contents[contentsOffset++] = (byte) interfacesCount;
for (int i = 0; i < interfacesCount; i++) {
- int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]);
+ int interfaceIndex = constantPool.literalIndexForType(superInterfacesBinding[i].constantPoolName());
contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
contents[contentsOffset++] = (byte) interfaceIndex;
}
- produceDebugAttributes = referenceBinding.scope.environment().options.produceDebugAttributes;
+ produceDebugAttributes = options.produceDebugAttributes;
innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
this.creatingProblemType = creatingProblemType;
- codeStream = new CodeStream(this);
+ codeStream = new CodeStream(this, this.targetJDK);
// retrieve the enclosing one guaranteed to be the one matching the propagated flow info
// 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
for (int i = 0; i < numberOfInnerClasses; i++) {
ReferenceBinding innerClass = innerClassesBindings[i];
int accessFlags = innerClass.getAccessFlags();
- int innerClassIndex = constantPool.literalIndex(innerClass);
+ int innerClassIndex = constantPool.literalIndexForType(innerClass.constantPoolName());
// inner class index
contents[contentsOffset++] = (byte) (innerClassIndex >> 8);
contents[contentsOffset++] = (byte) innerClassIndex;
// outer class index: anonymous and local have no outer class index
if (innerClass.isMemberType()) {
// member or member of local
- int outerClassIndex = constantPool.literalIndex(innerClass.enclosingType());
+ int outerClassIndex = constantPool.literalIndexForType(innerClass.enclosingType().constantPoolName());
contents[contentsOffset++] = (byte) (outerClassIndex >> 8);
contents[contentsOffset++] = (byte) outerClassIndex;
} else {
// access flag
if (innerClass.isAnonymousType()) {
accessFlags |= AccPrivate;
- } else
- if (innerClass.isLocalType() && !innerClass.isMemberType()) {
- accessFlags |= AccPrivate;
- }
+ } else if (innerClass.isLocalType() && !innerClass.isMemberType()) {
+ accessFlags |= AccPrivate;
+ } else if (innerClass.isMemberType() && (innerClass.isInterface() || innerClass.isAnnotationType())) {
+ accessFlags |= AccStatic; // implicitely static
+ }
contents[contentsOffset++] = (byte) (accessFlags >> 8);
contents[contentsOffset++] = (byte) accessFlags;
}
attributeNumber++;
}
+ // add signature attribute
+ char[] genericSignature = referenceBinding.genericSignature();
+ if (genericSignature != null) {
+ // check that there is enough space to write all the bytes for the field info corresponding
+ // to the @fieldBinding
+ if (contentsOffset + 8 >= contents.length) {
+ resizeContents(8);
+ }
+ int signatureAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SignatureName);
+ contents[contentsOffset++] = (byte) (signatureAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) signatureAttributeNameIndex;
+ // the length of a signature attribute is equals to 2
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ int signatureIndex =
+ constantPool.literalIndex(genericSignature);
+ contents[contentsOffset++] = (byte) (signatureIndex >> 8);
+ contents[contentsOffset++] = (byte) signatureIndex;
+ attributeNumber++;
+ }
+ if (targetJDK >= ClassFileConstants.JDK1_5
+ && (this.referenceBinding.isAnonymousType() || this.referenceBinding.isLocalType())) {
+ // add enclosing method attribute (1.5 mode only)
+ if (contentsOffset + 10 >= contents.length) {
+ resizeContents(10);
+ }
+ int enclosingMethodAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.EnclosingMethodName);
+ contents[contentsOffset++] = (byte) (enclosingMethodAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) enclosingMethodAttributeNameIndex;
+ // the length of a signature attribute is equals to 2
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 4;
+
+ int enclosingTypeIndex = constantPool.literalIndexForType(this.referenceBinding.enclosingType().constantPoolName());
+ contents[contentsOffset++] = (byte) (enclosingTypeIndex >> 8);
+ contents[contentsOffset++] = (byte) enclosingTypeIndex;
+ byte methodIndexByte1 = 0;
+ byte methodIndexByte2 = 0;
+ if (this.referenceBinding.scope != null) {
+ MethodScope methodScope = this.referenceBinding.scope.methodScope();
+ if (methodScope != null) {
+ ReferenceContext referenceContext = methodScope.referenceContext;
+ if (referenceContext instanceof AbstractMethodDeclaration) {
+ AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) referenceContext;
+ MethodBinding methodBinding = methodDeclaration.binding;
+ int enclosingMethodIndex = constantPool.literalIndexForMethod(methodBinding.selector, methodBinding.signature());
+ methodIndexByte1 = (byte) (enclosingMethodIndex >> 8);
+ methodIndexByte2 = (byte) enclosingMethodIndex;
+ }
+ }
+ }
+ contents[contentsOffset++] = methodIndexByte1;
+ contents[contentsOffset++] = methodIndexByte2;
+ attributeNumber++;
+ }
+ if (this.targetJDK >= ClassFileConstants.JDK1_5 && !this.creatingProblemType) {
+ TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
+ if (typeDeclaration != null) {
+ final Annotation[] annotations = typeDeclaration.annotations;
+ if (annotations != null) {
+ attributeNumber += generateRuntimeAnnotations(annotations);
+ }
+ }
+ }
// update the number of attributes
if (attributeOffset + 2 >= this.contents.length) {
resizeContents(2);
header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
header[constantPoolOffset] = (byte) constantPoolCount;
}
-
+
/**
* INTERNAL USE-ONLY
* This methods generate all the default abstract method infos that correpond to
}
}
- /**
- * INTERNAL USE-ONLY
- * This methods generates the bytes for the field binding passed like a parameter
- * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding
- */
- public void addFieldInfo(FieldBinding fieldBinding) {
- int attributeNumber = 0;
- // check that there is enough space to write all the bytes for the field info corresponding
- // to the @fieldBinding
- if (contentsOffset + 30 >= contents.length) {
- resizeContents(30);
- }
- // Generate two attribute: constantValueAttribute and SyntheticAttribute
- // Now we can generate all entries into the byte array
- // First the accessFlags
- int accessFlags = fieldBinding.getAccessFlags();
- contents[contentsOffset++] = (byte) (accessFlags >> 8);
- contents[contentsOffset++] = (byte) accessFlags;
- // Then the nameIndex
- int nameIndex = constantPool.literalIndex(fieldBinding.name);
- contents[contentsOffset++] = (byte) (nameIndex >> 8);
- contents[contentsOffset++] = (byte) nameIndex;
- // Then the descriptorIndex
- int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
- contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
- contents[contentsOffset++] = (byte) descriptorIndex;
- // leave some space for the number of attributes
- int fieldAttributeOffset = contentsOffset;
- contentsOffset += 2;
+ private int addFieldAttributes(FieldBinding fieldBinding, int fieldAttributeOffset) {
+ int attributesNumber = 0;
// 4.7.2 only static constant fields get a ConstantAttribute
- if (fieldBinding.constant != Constant.NotAConstant){
+ // Generate the constantValueAttribute
+ if (fieldBinding.isConstantValue()){
+ if (contentsOffset + 8 >= contents.length) {
+ resizeContents(8);
+ }
// Now we generate the constant attribute corresponding to the fieldBinding
int constantValueNameIndex =
constantPool.literalIndex(AttributeNamesConstants.ConstantValueName);
contents[contentsOffset++] = 0;
contents[contentsOffset++] = 0;
contents[contentsOffset++] = 2;
- attributeNumber++;
+ attributesNumber++;
// Need to add the constant_value_index
- switch (fieldBinding.constant.typeID()) {
+ Constant fieldConstant = fieldBinding.constant();
+ switch (fieldConstant.typeID()) {
case T_boolean :
int booleanValueIndex =
- constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0);
+ constantPool.literalIndex(fieldConstant.booleanValue() ? 1 : 0);
contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
contents[contentsOffset++] = (byte) booleanValueIndex;
break;
case T_int :
case T_short :
int integerValueIndex =
- constantPool.literalIndex(fieldBinding.constant.intValue());
+ constantPool.literalIndex(fieldConstant.intValue());
contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
contents[contentsOffset++] = (byte) integerValueIndex;
break;
case T_float :
int floatValueIndex =
- constantPool.literalIndex(fieldBinding.constant.floatValue());
+ constantPool.literalIndex(fieldConstant.floatValue());
contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
contents[contentsOffset++] = (byte) floatValueIndex;
break;
case T_double :
int doubleValueIndex =
- constantPool.literalIndex(fieldBinding.constant.doubleValue());
+ constantPool.literalIndex(fieldConstant.doubleValue());
contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
contents[contentsOffset++] = (byte) doubleValueIndex;
break;
case T_long :
int longValueIndex =
- constantPool.literalIndex(fieldBinding.constant.longValue());
+ constantPool.literalIndex(fieldConstant.longValue());
contents[contentsOffset++] = (byte) (longValueIndex >> 8);
contents[contentsOffset++] = (byte) longValueIndex;
break;
- case T_String :
+ case T_JavaLangString :
int stringValueIndex =
constantPool.literalIndex(
- ((StringConstant) fieldBinding.constant).stringValue());
+ ((StringConstant) fieldConstant).stringValue());
if (stringValueIndex == -1) {
if (!creatingProblemType) {
// report an error and abort: will lead to a problem type classfile creation
}
} else {
// already inside a problem type creation : no constant for this field
- contentsOffset = fieldAttributeOffset + 2;
- // +2 is necessary to keep the two byte space for the attribute number
- attributeNumber--;
+ contentsOffset = fieldAttributeOffset;
}
} else {
contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
}
}
}
- if (fieldBinding.isSynthetic()) {
+ if (this.targetJDK < ClassFileConstants.JDK1_5 && fieldBinding.isSynthetic()) {
+ if (contentsOffset + 6 >= contents.length) {
+ resizeContents(6);
+ }
int syntheticAttributeNameIndex =
constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
contents[contentsOffset++] = 0;
contents[contentsOffset++] = 0;
contents[contentsOffset++] = 0;
- attributeNumber++;
+ attributesNumber++;
}
if (fieldBinding.isDeprecated()) {
+ if (contentsOffset + 6 >= contents.length) {
+ resizeContents(6);
+ }
int deprecatedAttributeNameIndex =
constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
contents[contentsOffset++] = 0;
contents[contentsOffset++] = 0;
contents[contentsOffset++] = 0;
- attributeNumber++;
+ attributesNumber++;
+ }
+ // add signature attribute
+ char[] genericSignature = fieldBinding.genericSignature();
+ if (genericSignature != null) {
+ // check that there is enough space to write all the bytes for the field info corresponding
+ // to the @fieldBinding
+ if (contentsOffset + 8 >= contents.length) {
+ resizeContents(8);
+ }
+ int signatureAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SignatureName);
+ contents[contentsOffset++] = (byte) (signatureAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) signatureAttributeNameIndex;
+ // the length of a signature attribute is equals to 2
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ int signatureIndex =
+ constantPool.literalIndex(genericSignature);
+ contents[contentsOffset++] = (byte) (signatureIndex >> 8);
+ contents[contentsOffset++] = (byte) signatureIndex;
+ attributesNumber++;
+ }
+ if (this.targetJDK >= ClassFileConstants.JDK1_5 && !this.creatingProblemType) {
+ FieldDeclaration fieldDeclaration = fieldBinding.sourceField();
+ if (fieldDeclaration != null) {
+ Annotation[] annotations = fieldDeclaration.annotations;
+ if (annotations != null) {
+ attributesNumber += generateRuntimeAnnotations(annotations);
+ }
+ }
+ }
+ return attributesNumber;
+ }
+ /**
+ * INTERNAL USE-ONLY
+ * This methods generates the bytes for the given field binding
+ * @param fieldBinding the given field binding
+ */
+ private void addFieldInfo(FieldBinding fieldBinding) {
+ // check that there is enough space to write all the bytes for the field info corresponding
+ // to the @fieldBinding
+ if (contentsOffset + 8 >= contents.length) {
+ resizeContents(8);
}
+ // Now we can generate all entries into the byte array
+ // First the accessFlags
+ int accessFlags = fieldBinding.getAccessFlags();
+ if (targetJDK < ClassFileConstants.JDK1_5) {
+ // pre 1.5, synthetic was an attribute, not a modifier
+ accessFlags &= ~AccSynthetic;
+ }
+ contents[contentsOffset++] = (byte) (accessFlags >> 8);
+ contents[contentsOffset++] = (byte) accessFlags;
+ // Then the nameIndex
+ int nameIndex = constantPool.literalIndex(fieldBinding.name);
+ contents[contentsOffset++] = (byte) (nameIndex >> 8);
+ contents[contentsOffset++] = (byte) nameIndex;
+ // Then the descriptorIndex
+ int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
+ contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
+ contents[contentsOffset++] = (byte) descriptorIndex;
+ int fieldAttributeOffset = contentsOffset;
+ int attributeNumber = 0;
+ // leave some space for the number of attributes
+ contentsOffset += 2;
+ attributeNumber += addFieldAttributes(fieldBinding, fieldAttributeOffset);
contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8);
contents[fieldAttributeOffset] = (byte) attributeNumber;
}
* - a field info for each defined field of that class
* - a field info for each synthetic field (e.g. this$0)
*/
+ /**
+ * INTERNAL USE-ONLY
+ * This methods generate all the fields infos for the receiver.
+ * This includes:
+ * - a field info for each defined field of that class
+ * - a field info for each synthetic field (e.g. this$0)
+ */
public void addFieldInfos() {
SourceTypeBinding currentBinding = referenceBinding;
FieldBinding[] syntheticFields = currentBinding.syntheticFields();
* have to be generated for the inner classes attributes.
* @param refBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
*/
- public void addInnerClasses(ReferenceBinding refBinding) {
+ private void addInnerClasses(ReferenceBinding refBinding) {
// check first if that reference binding is there
for (int i = 0; i < numberOfInnerClasses; i++) {
if (innerClassesBindings[i] == refBinding)
}
innerClassesBindings[numberOfInnerClasses++] = refBinding;
}
+
+ private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) {
+ // always clear the strictfp/native/abstract bit for a problem method
+ generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
+ int methodAttributeOffset = contentsOffset;
+ int attributeNumber = generateMethodInfoAttribute(methodBinding);
+
+ // Code attribute
+ attributeNumber++;
+
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ StringBuffer buffer = new StringBuffer(25);
+ buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
+ buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
+ String problemString = buffer.toString();
+
+ codeStream.init(this);
+ codeStream.preserveUnusedLocals = true;
+ codeStream.initializeMaxLocals(methodBinding);
+
+ // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
+ codeStream.generateCodeAttributeForProblemMethod(problemString);
+
+ completeCodeAttributeForMissingAbstractProblemMethod(
+ methodBinding,
+ codeAttributeOffset,
+ compilationResult.lineSeparatorPositions,
+ problem.getSourceLineNumber());
+
+ completeMethodInfo(methodAttributeOffset, attributeNumber);
+ }
/**
* INTERNAL USE-ONLY
generateCodeAttributeHeader();
codeStream.resetForProblemClinit(this);
String problemString = "" ; //$NON-NLS-1$
+ int problemLine = 0;
if (problems != null) {
int max = problems.length;
StringBuffer buffer = new StringBuffer(25);
.scope
.referenceCompilationUnit()
.compilationResult
- .lineSeparatorPositions);
+ .lineSeparatorPositions,
+ problemLine);
contents[attributeOffset++] = (byte) (attributeNumber >> 8);
contents[attributeOffset] = (byte) attributeNumber;
}
// always clear the strictfp/native/abstract bit for a problem method
generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(methodBinding);
+ int attributeNumber = generateMethodInfoAttribute(methodBinding, true);
// Code attribute
attributeNumber++;
generateCodeAttributeHeader();
codeStream.reset(method, this);
String problemString = "" ; //$NON-NLS-1$
+ int problemLine = 0;
if (problems != null) {
int max = problems.length;
StringBuffer buffer = new StringBuffer(25);
.scope
.referenceCompilationUnit()
.compilationResult
- .lineSeparatorPositions);
+ .lineSeparatorPositions,
+ problemLine);
completeMethodInfo(methodAttributeOffset, attributeNumber);
}
// always clear the strictfp/native/abstract bit for a problem method
generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(methodBinding);
+ int attributeNumber = generateMethodInfoAttribute(methodBinding, true);
// Code attribute
attributeNumber++;
generateCodeAttributeHeader();
codeStream.reset(method, this);
String problemString = "" ; //$NON-NLS-1$
+ int problemLine = 0;
if (problems != null) {
int max = problems.length;
StringBuffer buffer = new StringBuffer(25);
.scope
.referenceCompilationUnit()
.compilationResult
- .lineSeparatorPositions);
+ .lineSeparatorPositions,
+ problemLine);
completeMethodInfo(methodAttributeOffset, attributeNumber);
}
int savedOffset) {
// we need to move back the contentsOffset to the value at the beginning of the method
contentsOffset = savedOffset;
- methodCount--; // we need to remove the method that causes the problem
- addProblemMethod(method, methodBinding, problems);
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for all the special method infos.
- * They are:
- * - synthetic access methods
- * - default abstract methods
- */
- public void addSpecialMethods() {
- // add all methods (default abstract methods and synthetic)
-
- // default abstract methods
- SourceTypeBinding currentBinding = referenceBinding;
- MethodBinding[] defaultAbstractMethods =
- currentBinding.getDefaultAbstractMethods();
- for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
- generateMethodInfoHeader(defaultAbstractMethods[i]);
- int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
- completeMethodInfo(methodAttributeOffset, attributeNumber);
- }
- // add synthetic methods infos
- SyntheticAccessMethodBinding[] syntheticAccessMethods =
- currentBinding.syntheticAccessMethods();
- if (syntheticAccessMethods != null) {
- for (int i = 0, max = syntheticAccessMethods.length; i < max; i++) {
- SyntheticAccessMethodBinding accessMethodBinding = syntheticAccessMethods[i];
- switch (accessMethodBinding.accessType) {
- case SyntheticAccessMethodBinding.FieldReadAccess :
- // generate a method info to emulate an reading access to
- // a non-accessible field
- addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]);
- break;
- case SyntheticAccessMethodBinding.FieldWriteAccess :
- // generate a method info to emulate an writing access to
- // a non-accessible field
- addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]);
- break;
- case SyntheticAccessMethodBinding.MethodAccess :
- case SyntheticAccessMethodBinding.SuperMethodAccess :
- // generate a method info to emulate an access to a non-accessible method / super-method
- addSyntheticMethodAccessMethod(syntheticAccessMethods[i]);
- break;
- case SyntheticAccessMethodBinding.ConstructorAccess :
- // generate a method info to emulate an access to a non-accessible constructor
- addSyntheticConstructorAccessMethod(syntheticAccessMethods[i]);
- }
- }
- }
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for problem method infos that correspond to missing abstract methods.
- * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
- *
- * @param methodDeclarations Array of all missing abstract methods
- */
- public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) {
- if (methodDeclarations != null) {
- for (int i = 0, max = methodDeclarations.length; i < max; i++) {
- MethodDeclaration methodDeclaration = methodDeclarations[i];
- MethodBinding methodBinding = methodDeclaration.binding;
- String readableName = new String(methodBinding.readableName());
- IProblem[] problems = compilationResult.problems;
- int problemsCount = compilationResult.problemCount;
- for (int j = 0; j < problemsCount; j++) {
- IProblem problem = problems[j];
- if (problem != null
- && problem.getID() == IProblem.AbstractMethodMustBeImplemented
- && problem.getMessage().indexOf(readableName) != -1) {
- // we found a match
- addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult);
- }
- }
- }
- }
- }
-
- private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) {
- // always clear the strictfp/native/abstract bit for a problem method
- generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
- int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(methodBinding);
-
- // Code attribute
- attributeNumber++;
-
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- StringBuffer buffer = new StringBuffer(25);
- buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
- buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
- String problemString = buffer.toString();
- this.problemLine = problem.getSourceLineNumber();
-
- codeStream.init(this);
- codeStream.preserveUnusedLocals = true;
- codeStream.initializeMaxLocals(methodBinding);
-
- // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
- codeStream.generateCodeAttributeForProblemMethod(problemString);
-
- completeCodeAttributeForMissingAbstractProblemMethod(
- methodBinding,
- codeAttributeOffset,
- compilationResult.lineSeparatorPositions);
-
- completeMethodInfo(methodAttributeOffset, attributeNumber);
+ methodCount--; // we need to remove the method that causes the problem
+ addProblemMethod(method, methodBinding, problems);
}
/**
- *
+ * INTERNAL USE-ONLY
+ * Generate the byte for all the special method infos.
+ * They are:
+ * - synthetic access methods
+ * - default abstract methods
*/
- public void completeCodeAttributeForMissingAbstractProblemMethod(
- MethodBinding binding,
- int codeAttributeOffset,
- int[] startLineIndexes) {
- // reinitialize the localContents with the byte modified by the code stream
- this.contents = codeStream.bCodeStream;
- int localContentsOffset = codeStream.classFileOffset;
- // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
- int max_stack = codeStream.stackMax;
- this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
- this.contents[codeAttributeOffset + 7] = (byte) max_stack;
- int max_locals = codeStream.maxLocals;
- this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
- this.contents[codeAttributeOffset + 9] = (byte) max_locals;
- int code_length = codeStream.position;
- this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
- this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
- this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
- this.contents[codeAttributeOffset + 13] = (byte) code_length;
- // write the exception table
- if (localContentsOffset + 50 >= this.contents.length) {
- resizeContents(50);
- }
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- // debug attributes
- int codeAttributeAttributeOffset = localContentsOffset;
- int attributeNumber = 0; // leave two bytes for the attribute_length
- localContentsOffset += 2; // first we handle the linenumber attribute
+ public void addSpecialMethods() {
+
+ // add all methods (default abstract methods and synthetic)
- if (codeStream.generateLineNumberAttributes) {
- /* Create and add the line number attribute (used for debugging)
- * Build the pairs of:
- * (bytecodePC lineNumber)
- * according to the table of start line indexes and the pcToSourceMap table
- * contained into the codestream
- */
- int lineNumberNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
- this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 6;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 1;
- if (problemLine == 0) {
- problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
- }
- // first entry at pc = 0
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
- this.contents[localContentsOffset++] = (byte) problemLine;
- // now we change the size of the line number attribute
- attributeNumber++;
+ // default abstract methods
+ generateMissingAbstractMethods(referenceBinding.scope.referenceType().missingAbstractMethods, referenceBinding.scope.referenceCompilationUnit().compilationResult);
+
+ MethodBinding[] defaultAbstractMethods = this.referenceBinding.getDefaultAbstractMethods();
+ for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
+ generateMethodInfoHeader(defaultAbstractMethods[i]);
+ int methodAttributeOffset = contentsOffset;
+ int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
+ completeMethodInfo(methodAttributeOffset, attributeNumber);
}
-
- // then we do the local variable attribute
- // update the number of attributes// ensure first that there is enough space available inside the localContents array
- if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
- resizeContents(2);
+ // add synthetic methods infos
+ SyntheticMethodBinding[] syntheticMethods = this.referenceBinding.syntheticMethods();
+ if (syntheticMethods != null) {
+ for (int i = 0, max = syntheticMethods.length; i < max; i++) {
+ SyntheticMethodBinding syntheticMethod = syntheticMethods[i];
+ switch (syntheticMethod.kind) {
+ case SyntheticMethodBinding.FieldReadAccess :
+ // generate a method info to emulate an reading access to
+ // a non-accessible field
+ addSyntheticFieldReadAccessMethod(syntheticMethod);
+ break;
+ case SyntheticMethodBinding.FieldWriteAccess :
+ // generate a method info to emulate an writing access to
+ // a non-accessible field
+ addSyntheticFieldWriteAccessMethod(syntheticMethod);
+ break;
+ case SyntheticMethodBinding.MethodAccess :
+ case SyntheticMethodBinding.SuperMethodAccess :
+ case SyntheticMethodBinding.BridgeMethod :
+ // generate a method info to emulate an access to a non-accessible method / super-method or bridge method
+ addSyntheticMethodAccessMethod(syntheticMethod);
+ break;
+ case SyntheticMethodBinding.ConstructorAccess :
+ // generate a method info to emulate an access to a non-accessible constructor
+ addSyntheticConstructorAccessMethod(syntheticMethod);
+ break;
+ case SyntheticMethodBinding.EnumValues :
+ // generate a method info to define <enum>#values()
+ addSyntheticEnumValuesMethod(syntheticMethod);
+ break;
+ case SyntheticMethodBinding.EnumValueOf :
+ // generate a method info to define <enum>#valueOf(String)
+ addSyntheticEnumValueOfMethod(syntheticMethod);
+ break;
+ }
+ }
}
- this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
- this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
- // update the attribute length
- int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
- this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
- this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
- this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
- this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
- contentsOffset = localContentsOffset;
}
-
+
/**
* INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a synthetic method that
- * generate an access to a private constructor.
+ * Generate the bytes for a synthetic method that provides an access to a private constructor.
*
* @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
*/
- public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) {
+ public void addSyntheticConstructorAccessMethod(SyntheticMethodBinding methodBinding) {
generateMethodInfoHeader(methodBinding);
// We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
contents[contentsOffset++] = 0;
generateCodeAttributeHeader();
codeStream.init(this);
codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
- completeCodeAttributeForSyntheticAccessMethod(
+ completeCodeAttributeForSyntheticMethod(
methodBinding,
codeAttributeOffset,
((SourceTypeBinding) methodBinding.declaringClass)
/**
* INTERNAL USE-ONLY
+ * Generate the bytes for a synthetic method that implements Enum#valueOf(String) for a given enum type
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
+ */
+ public void addSyntheticEnumValueOfMethod(SyntheticMethodBinding methodBinding) {
+
+ generateMethodInfoHeader(methodBinding);
+ // We know that we won't get more than 1 attribute: the code attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 1;
+ // Code attribute
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ codeStream.init(this);
+ codeStream.generateSyntheticBodyForEnumValueOf(methodBinding);
+ completeCodeAttributeForSyntheticMethod(
+ methodBinding,
+ codeAttributeOffset,
+ ((SourceTypeBinding) methodBinding.declaringClass)
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+// // add the synthetic attribute
+// int syntheticAttributeNameIndex =
+// constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
+// contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
+// contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
+// // the length of a synthetic attribute is equals to 0
+// contents[contentsOffset++] = 0;
+// contents[contentsOffset++] = 0;
+// contents[contentsOffset++] = 0;
+// contents[contentsOffset++] = 0;
+
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the bytes for a synthetic method that implements Enum#values() for a given enum type
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
+ */
+ public void addSyntheticEnumValuesMethod(SyntheticMethodBinding methodBinding) {
+
+ generateMethodInfoHeader(methodBinding);
+ // We know that we won't get more than 1 attribute: the code attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 1;
+ // Code attribute
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ codeStream.init(this);
+ codeStream.generateSyntheticBodyForEnumValues(methodBinding);
+ completeCodeAttributeForSyntheticMethod(
+ methodBinding,
+ codeAttributeOffset,
+ ((SourceTypeBinding) methodBinding.declaringClass)
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+// // add the synthetic attribute
+// int syntheticAttributeNameIndex =
+// constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
+// contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
+// contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
+// // the length of a synthetic attribute is equals to 0
+// contents[contentsOffset++] = 0;
+// contents[contentsOffset++] = 0;
+// contents[contentsOffset++] = 0;
+// contents[contentsOffset++] = 0;
+
+ }
+
+ /**
+ * INTERNAL USE-ONLY
* Generate the byte for a problem method info that correspond to a synthetic method that
* generate an read access to a private field.
*
* @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
*/
- public void addSyntheticFieldReadAccessMethod(SyntheticAccessMethodBinding methodBinding) {
+ public void addSyntheticFieldReadAccessMethod(SyntheticMethodBinding methodBinding) {
generateMethodInfoHeader(methodBinding);
// We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
contents[contentsOffset++] = 0;
generateCodeAttributeHeader();
codeStream.init(this);
codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
- completeCodeAttributeForSyntheticAccessMethod(
+ completeCodeAttributeForSyntheticMethod(
methodBinding,
codeAttributeOffset,
((SourceTypeBinding) methodBinding.declaringClass)
*
* @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
*/
- public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) {
+ public void addSyntheticFieldWriteAccessMethod(SyntheticMethodBinding methodBinding) {
generateMethodInfoHeader(methodBinding);
// We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
contents[contentsOffset++] = 0;
generateCodeAttributeHeader();
codeStream.init(this);
codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
- completeCodeAttributeForSyntheticAccessMethod(
+ completeCodeAttributeForSyntheticMethod(
methodBinding,
codeAttributeOffset,
((SourceTypeBinding) methodBinding.declaringClass)
/**
* INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a synthetic method that
- * generate an access to a private method.
+ * Generate the bytes for a synthetic method that provides access to a private method.
*
* @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
*/
- public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) {
+ public void addSyntheticMethodAccessMethod(SyntheticMethodBinding methodBinding) {
generateMethodInfoHeader(methodBinding);
// We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
contents[contentsOffset++] = 0;
generateCodeAttributeHeader();
codeStream.init(this);
codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
- completeCodeAttributeForSyntheticAccessMethod(
+ completeCodeAttributeForSyntheticMethod(
methodBinding,
codeAttributeOffset,
((SourceTypeBinding) methodBinding.declaringClass)
/**
* INTERNAL USE-ONLY
- * Build all the directories and subdirectories corresponding to the packages names
- * into the directory specified in parameters.
- *
- * outputPath is formed like:
- * c:\temp\ the last character is a file separator
- * relativeFileName is formed like:
- * java\lang\String.class *
- *
- * @param outputPath java.lang.String
- * @param relativeFileName java.lang.String
- * @return java.lang.String
- */
- public static String buildAllDirectoriesInto(
- String outputPath,
- String relativeFileName)
- throws IOException {
- char fileSeparatorChar = File.separatorChar;
- String fileSeparator = File.separator;
- File f;
- // First we ensure that the outputPath exists
- outputPath = outputPath.replace('/', fileSeparatorChar);
- // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
- if (outputPath.endsWith(fileSeparator)) {
- outputPath = outputPath.substring(0, outputPath.length() - 1);
- }
- f = new File(outputPath);
- if (f.exists()) {
- if (!f.isDirectory()) {
- System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$
- throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$
- }
- } else {
- // we have to create that directory
- if (!f.mkdirs()) {
- System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$
- throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$
- }
- }
- StringBuffer outDir = new StringBuffer(outputPath);
- outDir.append(fileSeparator);
- StringTokenizer tokenizer =
- new StringTokenizer(relativeFileName, fileSeparator);
- String token = tokenizer.nextToken();
- while (tokenizer.hasMoreTokens()) {
- f = new File(outDir.append(token).append(fileSeparator).toString());
- if (f.exists()) {
- // The outDir already exists, so we proceed the next entry
- // System.out.println("outDir: " + outDir + " already exists.");
- } else {
- // Need to add the outDir
- if (!f.mkdir()) {
- System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$
- throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$
- }
- }
- token = tokenizer.nextToken();
- }
- // token contains the last one
- return outDir.append(token).toString();
- }
-
- /**
- * INTERNAL USE-ONLY
* That method completes the creation of the code attribute by setting
* - the attribute_length
* - max_stack
this.contents[codeAttributeOffset + 13] = (byte) code_length;
// write the exception table
- int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
+ int exceptionHandlersNumber = codeStream.exceptionHandlersCounter;
ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
int exSize = exceptionHandlersNumber * 8 + 2;
if (exSize + localContentsOffset >= this.contents.length) {
// on the attribute generation
this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
- for (int i = 0; i < exceptionHandlersNumber; i++) {
+ for (int i = 0, max = codeStream.exceptionHandlersIndex; i < max; i++) {
ExceptionLabel exceptionHandler = exceptionHandlers[i];
- int start = exceptionHandler.start;
- this.contents[localContentsOffset++] = (byte) (start >> 8);
- this.contents[localContentsOffset++] = (byte) start;
- int end = exceptionHandler.end;
- this.contents[localContentsOffset++] = (byte) (end >> 8);
- this.contents[localContentsOffset++] = (byte) end;
- int handlerPC = exceptionHandler.position;
- this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
- this.contents[localContentsOffset++] = (byte) handlerPC;
- if (exceptionHandler.exceptionType == null) {
- // any exception handler
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- } else {
- int nameIndex;
- if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
- /* represents ClassNotFoundException, see class literal access*/
- nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
+ if (exceptionHandler != null) {
+ int start = exceptionHandler.start;
+ this.contents[localContentsOffset++] = (byte) (start >> 8);
+ this.contents[localContentsOffset++] = (byte) start;
+ int end = exceptionHandler.end;
+ this.contents[localContentsOffset++] = (byte) (end >> 8);
+ this.contents[localContentsOffset++] = (byte) end;
+ int handlerPC = exceptionHandler.position;
+ this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
+ this.contents[localContentsOffset++] = (byte) handlerPC;
+ if (exceptionHandler.exceptionType == null) {
+ // any exception handler
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
} else {
- nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
+ int nameIndex;
+ if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
+ /* represents ClassNotFoundException, see class literal access*/
+ nameIndex = constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName);
+ } else {
+ nameIndex = constantPool.literalIndexForType(exceptionHandler.exceptionType.constantPoolName());
+ }
+ this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nameIndex;
}
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
}
}
// debug attributes
int numberOfEntries = 0;
int localVariableNameIndex =
constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
- if (localContentsOffset + 8 >= this.contents.length) {
- resizeContents(8);
+ final boolean methodDeclarationIsStatic = codeStream.methodDeclaration.isStatic();
+ int maxOfEntries = 8 + 10 * (methodDeclarationIsStatic ? 0 : 1);
+ for (int i = 0; i < codeStream.allLocalsCounter; i++) {
+ maxOfEntries += 10 * codeStream.locals[i].initializationCount;
+ }
+ // reserve enough space
+ if (localContentsOffset + maxOfEntries >= this.contents.length) {
+ resizeContents(maxOfEntries);
}
this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
// leave space for attribute_length and local_variable_table_length
int nameIndex;
int descriptorIndex;
- if (!codeStream.methodDeclaration.isStatic()) {
+ SourceTypeBinding declaringClassBinding = null;
+ if (!methodDeclarationIsStatic) {
numberOfEntries++;
- if (localContentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
this.contents[localContentsOffset++] = 0; // the startPC for this is always 0
this.contents[localContentsOffset++] = 0;
this.contents[localContentsOffset++] = (byte) (code_length >> 8);
this.contents[localContentsOffset++] = (byte) code_length;
- nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
+ nameIndex = constantPool.literalIndex(ConstantPool.This);
this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
this.contents[localContentsOffset++] = (byte) nameIndex;
+ declaringClassBinding = (SourceTypeBinding) codeStream.methodDeclaration.binding.declaringClass;
descriptorIndex =
constantPool.literalIndex(
- codeStream.methodDeclaration.binding.declaringClass.signature());
+ declaringClassBinding.signature());
this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
this.contents[localContentsOffset++] = (byte) descriptorIndex;
this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0
this.contents[localContentsOffset++] = 0;
}
- for (int i = 0; i < codeStream.allLocalsCounter; i++) {
+ // used to remember the local variable with a generic type
+ int genericLocalVariablesCounter = 0;
+ LocalVariableBinding[] genericLocalVariables = null;
+ int numberOfGenericEntries = 0;
+
+ for (int i = 0, max = codeStream.allLocalsCounter; i < max; i++) {
LocalVariableBinding localVariable = codeStream.locals[i];
+ final TypeBinding localVariableTypeBinding = localVariable.type;
+ boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
+ if (localVariable.initializationCount != 0 && isParameterizedType) {
+ if (genericLocalVariables == null) {
+ // we cannot have more than max locals
+ genericLocalVariables = new LocalVariableBinding[max];
+ }
+ genericLocalVariables[genericLocalVariablesCounter++] = localVariable;
+ }
for (int j = 0; j < localVariable.initializationCount; j++) {
int startPC = localVariable.initializationPCs[j << 1];
int endPC = localVariable.initializationPCs[(j << 1) + 1];
Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
(ASTNode) localVariable.declaringScope.methodScope().referenceContext);
}
- if (localContentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
+ if (isParameterizedType) {
+ numberOfGenericEntries++;
}
// now we can safely add the local entry
numberOfEntries++;
nameIndex = constantPool.literalIndex(localVariable.name);
this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
+ descriptorIndex = constantPool.literalIndex(localVariableTypeBinding.signature());
this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
this.contents[localContentsOffset++] = (byte) descriptorIndex;
int resolvedPosition = localVariable.resolvedPosition;
this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
this.contents[localVariableTableOffset] = (byte) numberOfEntries;
attributeNumber++;
+
+ final boolean currentInstanceIsGeneric =
+ !methodDeclarationIsStatic
+ && declaringClassBinding != null
+ && declaringClassBinding.typeVariables != NoTypeVariables;
+ if (genericLocalVariablesCounter != 0 || currentInstanceIsGeneric) {
+ // add the local variable type table attribute
+ numberOfGenericEntries += (currentInstanceIsGeneric ? 1 : 0);
+ maxOfEntries = 8 + numberOfGenericEntries * 10;
+ // reserve enough space
+ if (localContentsOffset + maxOfEntries >= this.contents.length) {
+ resizeContents(maxOfEntries);
+ }
+ int localVariableTypeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName);
+ this.contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) localVariableTypeNameIndex;
+ value = numberOfGenericEntries * 10 + 2;
+ this.contents[localContentsOffset++] = (byte) (value >> 24);
+ this.contents[localContentsOffset++] = (byte) (value >> 16);
+ this.contents[localContentsOffset++] = (byte) (value >> 8);
+ this.contents[localContentsOffset++] = (byte) value;
+ this.contents[localContentsOffset++] = (byte) (numberOfGenericEntries >> 8);
+ this.contents[localContentsOffset++] = (byte) numberOfGenericEntries;
+ if (currentInstanceIsGeneric) {
+ this.contents[localContentsOffset++] = 0; // the startPC for this is always 0
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = (byte) (code_length >> 8);
+ this.contents[localContentsOffset++] = (byte) code_length;
+ nameIndex = constantPool.literalIndex(ConstantPool.This);
+ this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(declaringClassBinding.genericTypeSignature());
+ this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) descriptorIndex;
+ this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0
+ this.contents[localContentsOffset++] = 0;
+ }
+
+ for (int i = 0; i < genericLocalVariablesCounter; i++) {
+ LocalVariableBinding localVariable = genericLocalVariables[i];
+ for (int j = 0; j < localVariable.initializationCount; j++) {
+ int startPC = localVariable.initializationPCs[j << 1];
+ int endPC = localVariable.initializationPCs[(j << 1) + 1];
+ if (startPC != endPC) {
+ // only entries for non zero length
+ // now we can safely add the local entry
+ this.contents[localContentsOffset++] = (byte) (startPC >> 8);
+ this.contents[localContentsOffset++] = (byte) startPC;
+ int length = endPC - startPC;
+ this.contents[localContentsOffset++] = (byte) (length >> 8);
+ this.contents[localContentsOffset++] = (byte) length;
+ nameIndex = constantPool.literalIndex(localVariable.name);
+ this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(localVariable.type.genericTypeSignature());
+ this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = localVariable.resolvedPosition;
+ this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ this.contents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ }
+ }
+ attributeNumber++;
+ }
}
// update the number of attributes
// ensure first that there is enough space available inside the localContents array
this.contents[codeAttributeOffset + 13] = (byte) code_length;
// write the exception table
- int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
+ int exceptionHandlersNumber = codeStream.exceptionHandlersCounter;
ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
int exSize = exceptionHandlersNumber * 8 + 2;
if (exSize + localContentsOffset >= this.contents.length) {
// on the attribute generation
this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
- for (int i = 0; i < exceptionHandlersNumber; i++) {
+ for (int i = 0, max = codeStream.exceptionHandlersIndex; i < max; i++) {
ExceptionLabel exceptionHandler = exceptionHandlers[i];
- int start = exceptionHandler.start;
- this.contents[localContentsOffset++] = (byte) (start >> 8);
- this.contents[localContentsOffset++] = (byte) start;
- int end = exceptionHandler.end;
- this.contents[localContentsOffset++] = (byte) (end >> 8);
- this.contents[localContentsOffset++] = (byte) end;
- int handlerPC = exceptionHandler.position;
- this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
- this.contents[localContentsOffset++] = (byte) handlerPC;
- if (exceptionHandler.exceptionType == null) {
- // any exception handler
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- } else {
- int nameIndex;
- if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
- /* represents denote ClassNotFoundException, see class literal access*/
- nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
+ if (exceptionHandler != null) {
+ int start = exceptionHandler.start;
+ this.contents[localContentsOffset++] = (byte) (start >> 8);
+ this.contents[localContentsOffset++] = (byte) start;
+ int end = exceptionHandler.end;
+ this.contents[localContentsOffset++] = (byte) (end >> 8);
+ this.contents[localContentsOffset++] = (byte) end;
+ int handlerPC = exceptionHandler.position;
+ this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
+ this.contents[localContentsOffset++] = (byte) handlerPC;
+ if (exceptionHandler.exceptionType == null) {
+ // any exception handler
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
} else {
- nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
+ int nameIndex;
+ if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
+ /* represents denote ClassNotFoundException, see class literal access*/
+ nameIndex = constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName);
+ } else {
+ nameIndex = constantPool.literalIndexForType(exceptionHandler.exceptionType.constantPoolName());
+ }
+ this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nameIndex;
}
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
}
}
// debug attributes
this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
localContentsOffset += 6;
+
// leave space for attribute_length and local_variable_table_length
int nameIndex;
int descriptorIndex;
- for (int i = 0; i < codeStream.allLocalsCounter; i++) {
+
+ // used to remember the local variable with a generic type
+ int genericLocalVariablesCounter = 0;
+ LocalVariableBinding[] genericLocalVariables = null;
+ int numberOfGenericEntries = 0;
+
+ for (int i = 0, max = codeStream.allLocalsCounter; i < max; i++) {
LocalVariableBinding localVariable = codeStream.locals[i];
+ final TypeBinding localVariableTypeBinding = localVariable.type;
+ boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
+ if (localVariable.initializationCount != 0 && isParameterizedType) {
+ if (genericLocalVariables == null) {
+ // we cannot have more than max locals
+ genericLocalVariables = new LocalVariableBinding[max];
+ }
+ genericLocalVariables[genericLocalVariablesCounter++] = localVariable;
+ }
for (int j = 0; j < localVariable.initializationCount; j++) {
int startPC = localVariable.initializationPCs[j << 1];
int endPC = localVariable.initializationPCs[(j << 1) + 1];
}
// now we can safely add the local entry
numberOfEntries++;
+ if (isParameterizedType) {
+ numberOfGenericEntries++;
+ }
this.contents[localContentsOffset++] = (byte) (startPC >> 8);
this.contents[localContentsOffset++] = (byte) startPC;
int length = endPC - startPC;
nameIndex = constantPool.literalIndex(localVariable.name);
this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
+ descriptorIndex = constantPool.literalIndex(localVariableTypeBinding.signature());
this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
this.contents[localContentsOffset++] = (byte) descriptorIndex;
int resolvedPosition = localVariable.resolvedPosition;
this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
this.contents[localVariableTableOffset] = (byte) numberOfEntries;
attributeNumber++;
+
+ if (genericLocalVariablesCounter != 0) {
+ // add the local variable type table attribute
+ // reserve enough space
+ int maxOfEntries = 8 + numberOfGenericEntries * 10;
+
+ if (localContentsOffset + maxOfEntries >= this.contents.length) {
+ resizeContents(maxOfEntries);
+ }
+ int localVariableTypeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName);
+ this.contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) localVariableTypeNameIndex;
+ value = numberOfGenericEntries * 10 + 2;
+ this.contents[localContentsOffset++] = (byte) (value >> 24);
+ this.contents[localContentsOffset++] = (byte) (value >> 16);
+ this.contents[localContentsOffset++] = (byte) (value >> 8);
+ this.contents[localContentsOffset++] = (byte) value;
+ this.contents[localContentsOffset++] = (byte) (numberOfGenericEntries >> 8);
+ this.contents[localContentsOffset++] = (byte) numberOfGenericEntries;
+ for (int i = 0; i < genericLocalVariablesCounter; i++) {
+ LocalVariableBinding localVariable = genericLocalVariables[i];
+ for (int j = 0; j < localVariable.initializationCount; j++) {
+ int startPC = localVariable.initializationPCs[j << 1];
+ int endPC = localVariable.initializationPCs[(j << 1) + 1];
+ if (startPC != endPC) { // only entries for non zero length
+ // now we can safely add the local entry
+ this.contents[localContentsOffset++] = (byte) (startPC >> 8);
+ this.contents[localContentsOffset++] = (byte) startPC;
+ int length = endPC - startPC;
+ this.contents[localContentsOffset++] = (byte) (length >> 8);
+ this.contents[localContentsOffset++] = (byte) length;
+ nameIndex = constantPool.literalIndex(localVariable.name);
+ this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(localVariable.type.genericTypeSignature());
+ this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = localVariable.resolvedPosition;
+ this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ this.contents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ }
+ }
+ attributeNumber++;
+ }
}
}
// update the number of attributes
*/
public void completeCodeAttributeForClinit(
int codeAttributeOffset,
- int[] startLineIndexes) {
+ int[] startLineIndexes,
+ int problemLine) {
// reinitialize the contents with the byte modified by the code stream
this.contents = codeStream.bCodeStream;
int localContentsOffset = codeStream.classFileOffset;
}
/**
+ *
+ */
+ public void completeCodeAttributeForMissingAbstractProblemMethod(
+ MethodBinding binding,
+ int codeAttributeOffset,
+ int[] startLineIndexes,
+ int problemLine) {
+ // reinitialize the localContents with the byte modified by the code stream
+ this.contents = codeStream.bCodeStream;
+ int localContentsOffset = codeStream.classFileOffset;
+ // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
+ int max_stack = codeStream.stackMax;
+ this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
+ this.contents[codeAttributeOffset + 7] = (byte) max_stack;
+ int max_locals = codeStream.maxLocals;
+ this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
+ this.contents[codeAttributeOffset + 9] = (byte) max_locals;
+ int code_length = codeStream.position;
+ this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
+ this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
+ this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
+ this.contents[codeAttributeOffset + 13] = (byte) code_length;
+ // write the exception table
+ if (localContentsOffset + 50 >= this.contents.length) {
+ resizeContents(50);
+ }
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ // debug attributes
+ int codeAttributeAttributeOffset = localContentsOffset;
+ int attributeNumber = 0; // leave two bytes for the attribute_length
+ localContentsOffset += 2; // first we handle the linenumber attribute
+
+ if (codeStream.generateLineNumberAttributes) {
+ /* Create and add the line number attribute (used for debugging)
+ * Build the pairs of:
+ * (bytecodePC lineNumber)
+ * according to the table of start line indexes and the pcToSourceMap table
+ * contained into the codestream
+ */
+ int lineNumberNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
+ this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 6;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 1;
+ if (problemLine == 0) {
+ problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
+ }
+ // first entry at pc = 0
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
+ this.contents[localContentsOffset++] = (byte) problemLine;
+ // now we change the size of the line number attribute
+ attributeNumber++;
+ }
+
+ // then we do the local variable attribute
+ // update the number of attributes// ensure first that there is enough space available inside the localContents array
+ if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
+ resizeContents(2);
+ }
+ this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
+ this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
+ // update the attribute length
+ int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
+ this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
+ this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
+ this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
+ this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
+ contentsOffset = localContentsOffset;
+ }
+
+ /**
* INTERNAL USE-ONLY
* That method completes the creation of the code attribute by setting
* - the attribute_length
AbstractMethodDeclaration method,
MethodBinding binding,
int codeAttributeOffset,
- int[] startLineIndexes) {
+ int[] startLineIndexes,
+ int problemLine) {
// reinitialize the localContents with the byte modified by the code stream
this.contents = codeStream.bCodeStream;
int localContentsOffset = codeStream.classFileOffset;
localContentsOffset += 6;
// leave space for attribute_length and local_variable_table_length
int descriptorIndex;
- if (!codeStream.methodDeclaration.isStatic()) {
+ int nameIndex;
+ SourceTypeBinding declaringClassBinding = null;
+ final boolean methodDeclarationIsStatic = codeStream.methodDeclaration.isStatic();
+ if (!methodDeclarationIsStatic) {
numberOfEntries++;
if (localContentsOffset + 10 >= this.contents.length) {
resizeContents(10);
this.contents[localContentsOffset++] = 0;
this.contents[localContentsOffset++] = (byte) (code_length >> 8);
this.contents[localContentsOffset++] = (byte) code_length;
- int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
+ nameIndex = constantPool.literalIndex(ConstantPool.This);
this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
this.contents[localContentsOffset++] = (byte) nameIndex;
+ declaringClassBinding = (SourceTypeBinding) codeStream.methodDeclaration.binding.declaringClass;
descriptorIndex =
- constantPool.literalIndex(
- codeStream.methodDeclaration.binding.declaringClass.signature());
+ constantPool.literalIndex(declaringClassBinding.signature());
this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
this.contents[localContentsOffset++] = (byte) descriptorIndex;
// the resolved position for this is always 0
this.contents[localContentsOffset++] = 0;
this.contents[localContentsOffset++] = 0;
}
+ // used to remember the local variable with a generic type
+ int genericLocalVariablesCounter = 0;
+ LocalVariableBinding[] genericLocalVariables = null;
+ int numberOfGenericEntries = 0;
+
if (binding.isConstructor()) {
ReferenceBinding declaringClass = binding.declaringClass;
if (declaringClass.isNestedType()) {
NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass;
argSize = methodDeclaringClass.enclosingInstancesSlotSize;
SyntheticArgumentBinding[] syntheticArguments;
- if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances())
- != null) {
+ if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances()) != null) {
for (int i = 0, max = syntheticArguments.length; i < max; i++) {
LocalVariableBinding localVariable = syntheticArguments[i];
+ final TypeBinding localVariableTypeBinding = localVariable.type;
+ if (localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable()) {
+ if (genericLocalVariables == null) {
+ // we cannot have more than max locals
+ genericLocalVariables = new LocalVariableBinding[max];
+ }
+ genericLocalVariables[genericLocalVariablesCounter++] = localVariable;
+ numberOfGenericEntries++;
+ }
if (localContentsOffset + 10 >= this.contents.length) {
resizeContents(10);
}
this.contents[localContentsOffset++] = 0;
this.contents[localContentsOffset++] = (byte) (code_length >> 8);
this.contents[localContentsOffset++] = (byte) code_length;
- int nameIndex = constantPool.literalIndex(localVariable.name);
+ nameIndex = constantPool.literalIndex(localVariable.name);
this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
+ descriptorIndex = constantPool.literalIndex(localVariableTypeBinding.signature());
this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
this.contents[localContentsOffset++] = (byte) descriptorIndex;
int resolvedPosition = localVariable.resolvedPosition;
} else {
argSize = binding.isStatic() ? 0 : 1;
}
+
+ int genericArgumentsCounter = 0;
+ int[] genericArgumentsNameIndexes = null;
+ int[] genericArgumentsResolvedPositions = null;
+ TypeBinding[] genericArgumentsTypeBindings = null;
+
if (method.binding != null) {
TypeBinding[] parameters = method.binding.parameters;
Argument[] arguments = method.arguments;
this.contents[localContentsOffset++] = 0;
this.contents[localContentsOffset++] = (byte) (code_length >> 8);
this.contents[localContentsOffset++] = (byte) code_length;
- int nameIndex = constantPool.literalIndex(arguments[i].name);
+ nameIndex = constantPool.literalIndex(arguments[i].name);
this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
this.contents[localContentsOffset++] = (byte) nameIndex;
+ int resolvedPosition = argSize;
+ if (argumentBinding.isParameterizedType() || argumentBinding.isTypeVariable()) {
+ if (genericArgumentsCounter == 0) {
+ // we cannot have more than max locals
+ genericArgumentsNameIndexes = new int[max];
+ genericArgumentsResolvedPositions = new int[max];
+ genericArgumentsTypeBindings = new TypeBinding[max];
+ }
+ genericArgumentsNameIndexes[genericArgumentsCounter] = nameIndex;
+ genericArgumentsResolvedPositions[genericArgumentsCounter] = resolvedPosition;
+ genericArgumentsTypeBindings[genericArgumentsCounter++] = argumentBinding;
+ }
descriptorIndex = constantPool.literalIndex(argumentBinding.signature());
this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
this.contents[localContentsOffset++] = (byte) descriptorIndex;
- int resolvedPosition = argSize;
if ((argumentBinding == BaseTypes.LongBinding)
|| (argumentBinding == BaseTypes.DoubleBinding))
argSize += 2;
this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
this.contents[localVariableTableOffset] = (byte) numberOfEntries;
attributeNumber++;
+
+ final boolean currentInstanceIsGeneric =
+ !methodDeclarationIsStatic
+ && declaringClassBinding != null
+ && declaringClassBinding.typeVariables != NoTypeVariables;
+ if (genericLocalVariablesCounter != 0 || genericArgumentsCounter != 0 || currentInstanceIsGeneric) {
+ // add the local variable type table attribute
+ numberOfEntries = numberOfGenericEntries + genericArgumentsCounter + (currentInstanceIsGeneric ? 1 : 0);
+ // reserve enough space
+ int maxOfEntries = 8 + numberOfEntries * 10;
+ if (localContentsOffset + maxOfEntries >= this.contents.length) {
+ resizeContents(maxOfEntries);
+ }
+ int localVariableTypeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName);
+ this.contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) localVariableTypeNameIndex;
+ value = numberOfEntries * 10 + 2;
+ this.contents[localContentsOffset++] = (byte) (value >> 24);
+ this.contents[localContentsOffset++] = (byte) (value >> 16);
+ this.contents[localContentsOffset++] = (byte) (value >> 8);
+ this.contents[localContentsOffset++] = (byte) value;
+ this.contents[localContentsOffset++] = (byte) (numberOfEntries >> 8);
+ this.contents[localContentsOffset++] = (byte) numberOfEntries;
+ if (currentInstanceIsGeneric) {
+ numberOfEntries++;
+ this.contents[localContentsOffset++] = 0; // the startPC for this is always 0
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = (byte) (code_length >> 8);
+ this.contents[localContentsOffset++] = (byte) code_length;
+ nameIndex = constantPool.literalIndex(ConstantPool.This);
+ this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(declaringClassBinding.genericTypeSignature());
+ this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) descriptorIndex;
+ this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0
+ this.contents[localContentsOffset++] = 0;
+ }
+
+ for (int i = 0; i < genericLocalVariablesCounter; i++) {
+ LocalVariableBinding localVariable = genericLocalVariables[i];
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = (byte) (code_length >> 8);
+ this.contents[localContentsOffset++] = (byte) code_length;
+ nameIndex = constantPool.literalIndex(localVariable.name);
+ this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(localVariable.type.genericTypeSignature());
+ this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = localVariable.resolvedPosition;
+ this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ this.contents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ for (int i = 0; i < genericArgumentsCounter; i++) {
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = (byte) (code_length >> 8);
+ this.contents[localContentsOffset++] = (byte) code_length;
+ nameIndex = genericArgumentsNameIndexes[i];
+ this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(genericArgumentsTypeBindings[i].genericTypeSignature());
+ this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = genericArgumentsResolvedPositions[i];
+ this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ this.contents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ attributeNumber++;
+ }
}
// update the number of attributes// ensure first that there is enough space available inside the localContents array
if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
* @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
* @param codeAttributeOffset <CODE>int</CODE>
*/
- public void completeCodeAttributeForSyntheticAccessMethod(
- SyntheticAccessMethodBinding binding,
+ public void completeCodeAttributeForSyntheticMethod(
+ SyntheticMethodBinding binding,
int codeAttributeOffset,
int[] startLineIndexes) {
// reinitialize the contents with the byte modified by the code stream
// leave space for attribute_length and local_variable_table_length
int nameIndex;
int descriptorIndex;
- for (int i = 0; i < codeStream.allLocalsCounter; i++) {
+
+ // used to remember the local variable with a generic type
+ int genericLocalVariablesCounter = 0;
+ LocalVariableBinding[] genericLocalVariables = null;
+ int numberOfGenericEntries = 0;
+
+ for (int i = 0, max = codeStream.allLocalsCounter; i < max; i++) {
LocalVariableBinding localVariable = codeStream.locals[i];
+ final TypeBinding localVariableTypeBinding = localVariable.type;
+ boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
+ if (localVariable.initializationCount != 0 && isParameterizedType) {
+ if (genericLocalVariables == null) {
+ // we cannot have more than max locals
+ genericLocalVariables = new LocalVariableBinding[max];
+ }
+ genericLocalVariables[genericLocalVariablesCounter++] = localVariable;
+ }
for (int j = 0; j < localVariable.initializationCount; j++) {
int startPC = localVariable.initializationPCs[j << 1];
int endPC = localVariable.initializationPCs[(j << 1) + 1];
}
// now we can safely add the local entry
numberOfEntries++;
+ if (isParameterizedType) {
+ numberOfGenericEntries++;
+ }
contents[localContentsOffset++] = (byte) (startPC >> 8);
contents[localContentsOffset++] = (byte) startPC;
int length = endPC - startPC;
nameIndex = constantPool.literalIndex(localVariable.name);
contents[localContentsOffset++] = (byte) (nameIndex >> 8);
contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
+ descriptorIndex = constantPool.literalIndex(localVariableTypeBinding.signature());
contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
contents[localContentsOffset++] = (byte) descriptorIndex;
int resolvedPosition = localVariable.resolvedPosition;
contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
contents[localVariableTableOffset] = (byte) numberOfEntries;
attributeNumber++;
+
+ if (genericLocalVariablesCounter != 0) {
+ // add the local variable type table attribute
+ int maxOfEntries = 8 + numberOfGenericEntries * 10;
+ // reserve enough space
+ if (localContentsOffset + maxOfEntries >= this.contents.length) {
+ resizeContents(maxOfEntries);
+ }
+ int localVariableTypeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName);
+ contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8);
+ contents[localContentsOffset++] = (byte) localVariableTypeNameIndex;
+ value = numberOfGenericEntries * 10 + 2;
+ contents[localContentsOffset++] = (byte) (value >> 24);
+ contents[localContentsOffset++] = (byte) (value >> 16);
+ contents[localContentsOffset++] = (byte) (value >> 8);
+ contents[localContentsOffset++] = (byte) value;
+ contents[localContentsOffset++] = (byte) (numberOfGenericEntries >> 8);
+ contents[localContentsOffset++] = (byte) numberOfGenericEntries;
+
+ for (int i = 0; i < genericLocalVariablesCounter; i++) {
+ LocalVariableBinding localVariable = genericLocalVariables[i];
+ for (int j = 0; j < localVariable.initializationCount; j++) {
+ int startPC = localVariable.initializationPCs[j << 1];
+ int endPC = localVariable.initializationPCs[(j << 1) + 1];
+ if (startPC != endPC) { // only entries for non zero length
+ // now we can safely add the local entry
+ contents[localContentsOffset++] = (byte) (startPC >> 8);
+ contents[localContentsOffset++] = (byte) startPC;
+ int length = endPC - startPC;
+ contents[localContentsOffset++] = (byte) (length >> 8);
+ contents[localContentsOffset++] = (byte) length;
+ nameIndex = constantPool.literalIndex(localVariable.name);
+ contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ contents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(localVariable.type.genericTypeSignature());
+ contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ contents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = localVariable.resolvedPosition;
+ contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ contents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ }
+ }
+ attributeNumber++;
+ }
}
// update the number of attributes
// ensure first that there is enough space available inside the contents array
/**
* INTERNAL USE-ONLY
- * Request the creation of a ClassFile compatible representation of a problematic type
+ * This methods returns a char[] representing the file name of the receiver
*
- * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
- * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
+ * @return char[]
*/
- public static void createProblemType(
- TypeDeclaration typeDeclaration,
- CompilationResult unitResult) {
- SourceTypeBinding typeBinding = typeDeclaration.binding;
- ClassFile classFile = new ClassFile(typeBinding, null, true);
-
- // TODO (olivier) handle cases where a field cannot be generated (name too long)
- // TODO (olivier) handle too many methods
- // inner attributes
- if (typeBinding.isMemberType())
- classFile.recordEnclosingTypeAttributes(typeBinding);
+ public char[] fileName() {
+ return constantPool.UTF8Cache.returnKeyFor(1);
+ }
- // add its fields
- FieldBinding[] fields = typeBinding.fields;
- if ((fields != null) && (fields != NoFields)) {
- for (int i = 0, max = fields.length; i < max; i++) {
- if (fields[i].constant == null) {
- FieldReference.getConstantFor(fields[i], null, false, null);
- }
- }
- classFile.addFieldInfos();
- } else {
- // we have to set the number of fields to be equals to 0
- classFile.contents[classFile.contentsOffset++] = 0;
- classFile.contents[classFile.contentsOffset++] = 0;
- }
- // leave some space for the methodCount
- classFile.setForMethodInfos();
- // add its user defined methods
- MethodBinding[] methods = typeBinding.methods;
- AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
- int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
- int problemsLength;
- IProblem[] problems = unitResult.getErrors();
- if (problems == null) {
- problems = new IProblem[0];
- }
- IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
- System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
- if (methods != null) {
- if (typeBinding.isInterface()) {
- // we cannot create problem methods for an interface. So we have to generate a clinit
- // which should contain all the problem
- classFile.addProblemClinit(problemsCopy);
- for (int i = 0, max = methods.length; i < max; i++) {
- MethodBinding methodBinding;
- if ((methodBinding = methods[i]) != null) {
- // find the corresponding method declaration
- for (int j = 0; j < maxMethodDecl; j++) {
- if ((methodDeclarations[j] != null)
- && (methodDeclarations[j].binding == methods[i])) {
- if (!methodBinding.isConstructor()) {
- classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
- }
- break;
- }
- }
+ private void generateAnnotation(Annotation annotation, int attributeOffset) {
+ if (contentsOffset + 4 >= this.contents.length) {
+ resizeContents(4);
+ }
+ TypeBinding annotationTypeBinding = annotation.resolvedType;
+ if (annotationTypeBinding == null) {
+ this.contentsOffset = attributeOffset;
+ return;
+ }
+ final int typeIndex = constantPool.literalIndex(annotationTypeBinding.signature());
+ contents[contentsOffset++] = (byte) (typeIndex >> 8);
+ contents[contentsOffset++] = (byte) typeIndex;
+ if (annotation instanceof NormalAnnotation) {
+ NormalAnnotation normalAnnotation = (NormalAnnotation) annotation;
+ MemberValuePair[] memberValuePairs = normalAnnotation.memberValuePairs;
+ if (memberValuePairs != null) {
+ final int memberValuePairsLength = memberValuePairs.length;
+ contents[contentsOffset++] = (byte) (memberValuePairsLength >> 8);
+ contents[contentsOffset++] = (byte) memberValuePairsLength;
+ for (int i = 0; i < memberValuePairsLength; i++) {
+ MemberValuePair memberValuePair = memberValuePairs[i];
+ if (contentsOffset + 2 >= this.contents.length) {
+ resizeContents(2);
}
- }
- } else {
- for (int i = 0, max = methods.length; i < max; i++) {
- MethodBinding methodBinding;
- if ((methodBinding = methods[i]) != null) {
- // find the corresponding method declaration
- for (int j = 0; j < maxMethodDecl; j++) {
- if ((methodDeclarations[j] != null)
- && (methodDeclarations[j].binding == methods[i])) {
- AbstractMethodDeclaration methodDecl;
- if ((methodDecl = methodDeclarations[j]).isConstructor()) {
- classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
- } else {
- classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
- }
- break;
- }
- }
+ final int elementNameIndex = constantPool.literalIndex(memberValuePair.name);
+ contents[contentsOffset++] = (byte) (elementNameIndex >> 8);
+ contents[contentsOffset++] = (byte) elementNameIndex;
+ MethodBinding methodBinding = memberValuePair.binding;
+ if (methodBinding == null) {
+ contentsOffset = attributeOffset;
+ } else {
+ generateElementValue(memberValuePair.value, methodBinding.returnType, attributeOffset);
}
}
+ } else {
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
}
- // add abstract methods
- classFile.addDefaultAbstractMethods();
- }
- // propagate generation of (problem) member types
- if (typeDeclaration.memberTypes != null) {
- for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
- TypeDeclaration memberType = typeDeclaration.memberTypes[i];
- if (memberType.binding != null) {
- classFile.recordNestedMemberAttribute(memberType.binding);
- ClassFile.createProblemType(memberType, unitResult);
- }
- }
- }
- classFile.addAttributes();
- unitResult.record(typeBinding.constantPoolName(), classFile);
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods returns a char[] representing the file name of the receiver
- *
- * @return char[]
- */
- public char[] fileName() {
- return constantPool.UTF8Cache.returnKeyFor(1);
+ } else if (annotation instanceof SingleMemberAnnotation) {
+ SingleMemberAnnotation singleMemberAnnotation = (SingleMemberAnnotation) annotation;
+ // this is a single member annotation (one member value)
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 1;
+ if (contentsOffset + 2 >= this.contents.length) {
+ resizeContents(2);
+ }
+ final int elementNameIndex = constantPool.literalIndex(VALUE);
+ contents[contentsOffset++] = (byte) (elementNameIndex >> 8);
+ contents[contentsOffset++] = (byte) elementNameIndex;
+ MethodBinding methodBinding = singleMemberAnnotation.singlePair.binding;
+ if (methodBinding == null) {
+ contentsOffset = attributeOffset;
+ } else {
+ generateElementValue(singleMemberAnnotation.memberValue, methodBinding.returnType, attributeOffset);
+ }
+ } else {
+ // this is a marker annotation (no member value pairs)
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ }
}
/**
contentsOffset += 12;
}
+ private void generateElementValue(
+ Expression defaultValue,
+ TypeBinding memberValuePairReturnType,
+ int attributeOffset) {
+ Constant constant = defaultValue.constant;
+ TypeBinding defaultValueBinding = defaultValue.resolvedType;
+ if (defaultValueBinding == null) {
+ contentsOffset = attributeOffset;
+ } else {
+ if (memberValuePairReturnType.isArrayType() && !defaultValueBinding.isArrayType()) {
+ // automatic wrapping
+ if (contentsOffset + 3 >= this.contents.length) {
+ resizeContents(3);
+ }
+ contents[contentsOffset++] = (byte) '[';
+ contents[contentsOffset++] = (byte) 0;
+ contents[contentsOffset++] = (byte) 1;
+ }
+ if (constant != null && constant != Constant.NotAConstant) {
+ generateElementValue(attributeOffset, defaultValue, constant, memberValuePairReturnType.leafComponentType());
+ } else {
+ generateElementValueForNonConstantExpression(defaultValue, attributeOffset, defaultValueBinding);
+ }
+ }
+ }
+
+ /**
+ * @param attributeOffset
+ */
+ private void generateElementValue(int attributeOffset, Expression defaultValue, Constant constant, TypeBinding binding) {
+ if (contentsOffset + 3 >= this.contents.length) {
+ resizeContents(3);
+ }
+ switch (binding.id) {
+ case T_boolean :
+ contents[contentsOffset++] = (byte) 'Z';
+ int booleanValueIndex =
+ constantPool.literalIndex(constant.booleanValue() ? 1 : 0);
+ contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
+ contents[contentsOffset++] = (byte) booleanValueIndex;
+ break;
+ case T_byte :
+ contents[contentsOffset++] = (byte) 'B';
+ int integerValueIndex =
+ constantPool.literalIndex(constant.intValue());
+ contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
+ contents[contentsOffset++] = (byte) integerValueIndex;
+ break;
+ case T_char :
+ contents[contentsOffset++] = (byte) 'C';
+ integerValueIndex =
+ constantPool.literalIndex(constant.intValue());
+ contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
+ contents[contentsOffset++] = (byte) integerValueIndex;
+ break;
+ case T_int :
+ contents[contentsOffset++] = (byte) 'I';
+ integerValueIndex =
+ constantPool.literalIndex(constant.intValue());
+ contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
+ contents[contentsOffset++] = (byte) integerValueIndex;
+ break;
+ case T_short :
+ contents[contentsOffset++] = (byte) 'S';
+ integerValueIndex =
+ constantPool.literalIndex(constant.intValue());
+ contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
+ contents[contentsOffset++] = (byte) integerValueIndex;
+ break;
+ case T_float :
+ contents[contentsOffset++] = (byte) 'F';
+ int floatValueIndex =
+ constantPool.literalIndex(constant.floatValue());
+ contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
+ contents[contentsOffset++] = (byte) floatValueIndex;
+ break;
+ case T_double :
+ contents[contentsOffset++] = (byte) 'D';
+ int doubleValueIndex =
+ constantPool.literalIndex(constant.doubleValue());
+ contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
+ contents[contentsOffset++] = (byte) doubleValueIndex;
+ break;
+ case T_long :
+ contents[contentsOffset++] = (byte) 'J';
+ int longValueIndex =
+ constantPool.literalIndex(constant.longValue());
+ contents[contentsOffset++] = (byte) (longValueIndex >> 8);
+ contents[contentsOffset++] = (byte) longValueIndex;
+ break;
+ case T_JavaLangString :
+ contents[contentsOffset++] = (byte) 's';
+ int stringValueIndex =
+ constantPool.literalIndex(((StringConstant) constant).stringValue().toCharArray());
+ if (stringValueIndex == -1) {
+ if (!creatingProblemType) {
+ // report an error and abort: will lead to a problem type classfile creation
+ TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
+ typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(defaultValue);
+ } else {
+ // already inside a problem type creation : no attribute
+ contentsOffset = attributeOffset;
+ }
+ } else {
+ contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
+ contents[contentsOffset++] = (byte) stringValueIndex;
+ }
+ }
+ }
+
+ private void generateElementValueForNonConstantExpression(Expression defaultValue, int attributeOffset, TypeBinding defaultValueBinding) {
+ if (defaultValueBinding != null) {
+ if (defaultValueBinding.isEnum()) {
+ if (contentsOffset + 5 >= this.contents.length) {
+ resizeContents(5);
+ }
+ contents[contentsOffset++] = (byte) 'e';
+ FieldBinding fieldBinding = null;
+ if (defaultValue instanceof QualifiedNameReference) {
+ QualifiedNameReference nameReference = (QualifiedNameReference) defaultValue;
+ fieldBinding = (FieldBinding) nameReference.binding;
+ } else if (defaultValue instanceof SingleNameReference) {
+ SingleNameReference nameReference = (SingleNameReference) defaultValue;
+ fieldBinding = (FieldBinding) nameReference.binding;
+ } else {
+ contentsOffset = attributeOffset;
+ }
+ if (fieldBinding != null) {
+ final int enumConstantTypeNameIndex = constantPool.literalIndex(fieldBinding.type.signature());
+ final int enumConstantNameIndex = constantPool.literalIndex(fieldBinding.name);
+ contents[contentsOffset++] = (byte) (enumConstantTypeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) enumConstantTypeNameIndex;
+ contents[contentsOffset++] = (byte) (enumConstantNameIndex >> 8);
+ contents[contentsOffset++] = (byte) enumConstantNameIndex;
+ }
+ } else if (defaultValueBinding.isAnnotationType()) {
+ if (contentsOffset + 1 >= this.contents.length) {
+ resizeContents(1);
+ }
+ contents[contentsOffset++] = (byte) '@';
+ generateAnnotation((Annotation) defaultValue, attributeOffset);
+ } else if (defaultValueBinding.isArrayType()) {
+ // array type
+ if (contentsOffset + 3 >= this.contents.length) {
+ resizeContents(3);
+ }
+ contents[contentsOffset++] = (byte) '[';
+ if (defaultValue instanceof ArrayInitializer) {
+ ArrayInitializer arrayInitializer = (ArrayInitializer) defaultValue;
+ int arrayLength = arrayInitializer.expressions != null ? arrayInitializer.expressions.length : 0;
+ contents[contentsOffset++] = (byte) (arrayLength >> 8);
+ contents[contentsOffset++] = (byte) arrayLength;
+ for (int i = 0; i < arrayLength; i++) {
+ generateElementValue(arrayInitializer.expressions[i], defaultValueBinding.leafComponentType(), attributeOffset);
+ }
+ } else {
+ contentsOffset = attributeOffset;
+ }
+ } else {
+ // class type
+ if (contentsOffset + 3 >= this.contents.length) {
+ resizeContents(3);
+ }
+ contents[contentsOffset++] = (byte) 'c';
+ if (defaultValue instanceof ClassLiteralAccess) {
+ ClassLiteralAccess classLiteralAccess = (ClassLiteralAccess) defaultValue;
+ final int classInfoIndex = constantPool.literalIndex(classLiteralAccess.targetType.signature());
+ contents[contentsOffset++] = (byte) (classInfoIndex >> 8);
+ contents[contentsOffset++] = (byte) classInfoIndex;
+ } else {
+ contentsOffset = attributeOffset;
+ }
+ }
+ } else {
+ contentsOffset = attributeOffset;
+ }
+ }
+
+ public int generateMethodInfoAttribute(MethodBinding methodBinding) {
+ return generateMethodInfoAttribute(methodBinding, false);
+ }
/**
* INTERNAL USE-ONLY
* That method generates the attributes of a code attribute.
* @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
* @return <CODE>int</CODE>
*/
- public int generateMethodInfoAttribute(MethodBinding methodBinding) {
+ public int generateMethodInfoAttribute(MethodBinding methodBinding, boolean createProblemMethod) {
// leave two bytes for the attribute_number
contentsOffset += 2;
// now we can handle all the attribute for that method info:
contents[contentsOffset++] = (byte) (length >> 8);
contents[contentsOffset++] = (byte) length;
for (int i = 0; i < length; i++) {
- int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]);
+ int exceptionIndex = constantPool.literalIndexForType(thrownsExceptions[i].constantPoolName());
contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
contents[contentsOffset++] = (byte) exceptionIndex;
}
attributeNumber++;
}
+ // add signature attribute
+ char[] genericSignature = methodBinding.genericSignature();
+ if (genericSignature != null) {
+ // check that there is enough space to write all the bytes for the field info corresponding
+ // to the @fieldBinding
+ if (contentsOffset + 8 >= this.contents.length) {
+ resizeContents(8);
+ }
+ int signatureAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SignatureName);
+ contents[contentsOffset++] = (byte) (signatureAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) signatureAttributeNameIndex;
+ // the length of a signature attribute is equals to 2
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ int signatureIndex =
+ constantPool.literalIndex(genericSignature);
+ contents[contentsOffset++] = (byte) (signatureIndex >> 8);
+ contents[contentsOffset++] = (byte) signatureIndex;
+ attributeNumber++;
+ }
+ if (this.targetJDK >= ClassFileConstants.JDK1_5 && !this.creatingProblemType && !createProblemMethod) {
+ AbstractMethodDeclaration methodDeclaration = methodBinding.sourceMethod();
+ if (methodDeclaration != null) {
+ Annotation[] annotations = methodDeclaration.annotations;
+ if (annotations != null) {
+ attributeNumber += generateRuntimeAnnotations(annotations);
+ }
+ if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) {
+ Argument[] arguments = methodDeclaration.arguments;
+ if (arguments != null) {
+ attributeNumber += generateRuntimeAnnotationsForParameters(arguments);
+ }
+ }
+ }
+ }
return attributeNumber;
}
+ public int generateMethodInfoAttribute(MethodBinding methodBinding, AnnotationMethodDeclaration declaration) {
+ int attributesNumber = generateMethodInfoAttribute(methodBinding);
+ int attributeOffset = contentsOffset;
+ if ((declaration.modifiers & AccAnnotationDefault) != 0) {
+ // add an annotation default attribute
+ int annotationDefaultNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.AnnotationDefaultName);
+ contents[contentsOffset++] = (byte) (annotationDefaultNameIndex >> 8);
+ contents[contentsOffset++] = (byte) annotationDefaultNameIndex;
+ int attributeLengthOffset = contentsOffset;
+ contentsOffset += 4;
+
+ generateElementValue(declaration.defaultValue, declaration.binding.returnType, attributeOffset);
+ if (contentsOffset != attributeOffset) {
+ int attributeLength = contentsOffset - attributeLengthOffset - 4;
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
+ contents[attributeLengthOffset++] = (byte) attributeLength;
+ attributesNumber++;
+ }
+ }
+ return attributesNumber;
+ }
+
/**
* INTERNAL USE-ONLY
* That method generates the header of a method info:
}
contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8);
contents[contentsOffset++] = (byte) (AccDefault | AccStatic);
- int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit);
+ int nameIndex = constantPool.literalIndex(ConstantPool.Clinit);
contents[contentsOffset++] = (byte) (nameIndex >> 8);
contents[contentsOffset++] = (byte) nameIndex;
int descriptorIndex =
- constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature);
+ constantPool.literalIndex(ConstantPool.ClinitSignature);
contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
contents[contentsOffset++] = (byte) descriptorIndex;
// We know that we won't get more than 1 attribute: the code attribute
}
/**
+ * INTERNAL USE-ONLY
+ * Generate the byte for problem method infos that correspond to missing abstract methods.
+ * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
+ *
+ * @param methodDeclarations Array of all missing abstract methods
+ */
+ public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) {
+ if (methodDeclarations != null) {
+ for (int i = 0, max = methodDeclarations.length; i < max; i++) {
+ MethodDeclaration methodDeclaration = methodDeclarations[i];
+ MethodBinding methodBinding = methodDeclaration.binding;
+ String readableName = new String(methodBinding.readableName());
+ IProblem[] problems = compilationResult.problems;
+ int problemsCount = compilationResult.problemCount;
+ for (int j = 0; j < problemsCount; j++) {
+ IProblem problem = problems[j];
+ if (problem != null
+ && problem.getID() == IProblem.AbstractMethodMustBeImplemented
+ && problem.getMessage().indexOf(readableName) != -1) {
+ // we found a match
+ addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param annotations
+ * @return the number of attributes created while dumping the annotations in the .class file
+ */
+ private int generateRuntimeAnnotations(final Annotation[] annotations) {
+ int attributesNumber = 0;
+ final int length = annotations.length;
+ int visibleAnnotationsCounter = 0;
+ int invisibleAnnotationsCounter = 0;
+
+ for (int i = 0; i < length; i++) {
+ Annotation annotation = annotations[i];
+ if (isRuntimeInvisible(annotation)) {
+ invisibleAnnotationsCounter++;
+ } else if (isRuntimeVisible(annotation)) {
+ visibleAnnotationsCounter++;
+ }
+ }
+
+ if (invisibleAnnotationsCounter != 0) {
+ int annotationAttributeOffset = contentsOffset;
+ if (contentsOffset + 10 >= contents.length) {
+ resizeContents(10);
+ }
+ int runtimeInvisibleAnnotationsAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleAnnotationsName);
+ contents[contentsOffset++] = (byte) (runtimeInvisibleAnnotationsAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) runtimeInvisibleAnnotationsAttributeNameIndex;
+ int attributeLengthOffset = contentsOffset;
+ contentsOffset += 4; // leave space for the attribute length
+
+ int annotationsLengthOffset = contentsOffset;
+ contentsOffset += 2; // leave space for the annotations length
+
+ contents[annotationsLengthOffset++] = (byte) (invisibleAnnotationsCounter >> 8);
+ contents[annotationsLengthOffset++] = (byte) invisibleAnnotationsCounter;
+
+ loop: for (int i = 0; i < length; i++) {
+ if (invisibleAnnotationsCounter == 0) break loop;
+ Annotation annotation = annotations[i];
+ if (isRuntimeInvisible(annotation)) {
+ generateAnnotation(annotation, annotationAttributeOffset);
+ invisibleAnnotationsCounter--;
+ if (this.contentsOffset == annotationAttributeOffset) {
+ break loop;
+ }
+ }
+ }
+ if (contentsOffset != annotationAttributeOffset) {
+ int attributeLength = contentsOffset - attributeLengthOffset - 4;
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
+ contents[attributeLengthOffset++] = (byte) attributeLength;
+ attributesNumber++;
+ } else {
+ contentsOffset = annotationAttributeOffset;
+ }
+ }
+
+ if (visibleAnnotationsCounter != 0) {
+ int annotationAttributeOffset = contentsOffset;
+ if (contentsOffset + 10 >= contents.length) {
+ resizeContents(10);
+ }
+ int runtimeVisibleAnnotationsAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleAnnotationsName);
+ contents[contentsOffset++] = (byte) (runtimeVisibleAnnotationsAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) runtimeVisibleAnnotationsAttributeNameIndex;
+ int attributeLengthOffset = contentsOffset;
+ contentsOffset += 4; // leave space for the attribute length
+
+ int annotationsLengthOffset = contentsOffset;
+ contentsOffset += 2; // leave space for the annotations length
+
+ contents[annotationsLengthOffset++] = (byte) (visibleAnnotationsCounter >> 8);
+ contents[annotationsLengthOffset++] = (byte) visibleAnnotationsCounter;
+
+ loop: for (int i = 0; i < length; i++) {
+ if (visibleAnnotationsCounter == 0) break loop;
+ Annotation annotation = annotations[i];
+ if (isRuntimeVisible(annotation)) {
+ visibleAnnotationsCounter--;
+ generateAnnotation(annotation, annotationAttributeOffset);
+ if (this.contentsOffset == annotationAttributeOffset) {
+ break loop;
+ }
+ }
+ }
+ if (contentsOffset != annotationAttributeOffset) {
+ int attributeLength = contentsOffset - attributeLengthOffset - 4;
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
+ contents[attributeLengthOffset++] = (byte) attributeLength;
+ attributesNumber++;
+ } else {
+ contentsOffset = annotationAttributeOffset;
+ }
+ }
+ return attributesNumber;
+ }
+
+ private int generateRuntimeAnnotationsForParameters(Argument[] arguments) {
+ final int argumentsLength = arguments.length;
+ final int VISIBLE_INDEX = 0;
+ final int INVISIBLE_INDEX = 1;
+ int invisibleParametersAnnotationsCounter = 0;
+ int visibleParametersAnnotationsCounter = 0;
+ int[][] annotationsCounters = new int[argumentsLength][2];
+ for (int i = 0; i < argumentsLength; i++) {
+ Argument argument = arguments[i];
+ Annotation[] annotations = argument.annotations;
+ if (annotations != null) {
+ for (int j = 0, max2 = annotations.length; j < max2; j++) {
+ Annotation annotation = annotations[j];
+ if (isRuntimeInvisible(annotation)) {
+ annotationsCounters[i][INVISIBLE_INDEX]++;
+ invisibleParametersAnnotationsCounter++;
+ } else if (isRuntimeVisible(annotation)) {
+ annotationsCounters[i][VISIBLE_INDEX]++;
+ visibleParametersAnnotationsCounter++;
+ }
+ }
+ }
+ }
+ int attributesNumber = 0;
+ int annotationAttributeOffset = contentsOffset;
+ if (invisibleParametersAnnotationsCounter != 0) {
+ if (contentsOffset + 7 >= contents.length) {
+ resizeContents(7);
+ }
+ int attributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleParameterAnnotationsName);
+ contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) attributeNameIndex;
+ int attributeLengthOffset = contentsOffset;
+ contentsOffset += 4; // leave space for the attribute length
+
+ contents[contentsOffset++] = (byte) argumentsLength;
+ invisibleLoop: for (int i = 0; i < argumentsLength; i++) {
+ if (contentsOffset + 2 >= contents.length) {
+ resizeContents(2);
+ }
+ if (invisibleParametersAnnotationsCounter == 0) {
+ contents[contentsOffset++] = (byte) 0;
+ contents[contentsOffset++] = (byte) 0;
+ } else {
+ final int numberOfInvisibleAnnotations = annotationsCounters[i][INVISIBLE_INDEX];
+ contents[contentsOffset++] = (byte) (numberOfInvisibleAnnotations >> 8);
+ contents[contentsOffset++] = (byte) numberOfInvisibleAnnotations;
+ if (numberOfInvisibleAnnotations != 0) {
+ Argument argument = arguments[i];
+ Annotation[] annotations = argument.annotations;
+ for (int j = 0, max = annotations.length; j < max; j++) {
+ Annotation annotation = annotations[j];
+ if (isRuntimeInvisible(annotation)) {
+ generateAnnotation(annotation, annotationAttributeOffset);
+ if (contentsOffset == annotationAttributeOffset) {
+ break invisibleLoop;
+ }
+ invisibleParametersAnnotationsCounter--;
+ }
+ }
+ }
+ }
+ }
+ if (contentsOffset != annotationAttributeOffset) {
+ int attributeLength = contentsOffset - attributeLengthOffset - 4;
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
+ contents[attributeLengthOffset++] = (byte) attributeLength;
+ attributesNumber++;
+ } else {
+ contentsOffset = annotationAttributeOffset;
+ }
+ }
+ if (visibleParametersAnnotationsCounter != 0) {
+ if (contentsOffset + 7 >= contents.length) {
+ resizeContents(7);
+ }
+ int attributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleParameterAnnotationsName);
+ contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) attributeNameIndex;
+ int attributeLengthOffset = contentsOffset;
+ contentsOffset += 4; // leave space for the attribute length
+
+ contents[contentsOffset++] = (byte) argumentsLength;
+ visibleLoop: for (int i = 0; i < argumentsLength; i++) {
+ if (contentsOffset + 2 >= contents.length) {
+ resizeContents(2);
+ }
+ if (visibleParametersAnnotationsCounter == 0) {
+ contents[contentsOffset++] = (byte) 0;
+ contents[contentsOffset++] = (byte) 0;
+ } else {
+ final int numberOfVisibleAnnotations = annotationsCounters[i][VISIBLE_INDEX];
+ contents[contentsOffset++] = (byte) (numberOfVisibleAnnotations >> 8);
+ contents[contentsOffset++] = (byte) numberOfVisibleAnnotations;
+ if (numberOfVisibleAnnotations != 0) {
+ Argument argument = arguments[i];
+ Annotation[] annotations = argument.annotations;
+ for (int j = 0, max = annotations.length; j < max; j++) {
+ Annotation annotation = annotations[j];
+ if (isRuntimeVisible(annotation)) {
+ generateAnnotation(annotation, annotationAttributeOffset);
+ if (contentsOffset == annotationAttributeOffset) {
+ break visibleLoop;
+ }
+ visibleParametersAnnotationsCounter--;
+ }
+ }
+ }
+ }
+ }
+ if (contentsOffset != annotationAttributeOffset) {
+ int attributeLength = contentsOffset - attributeLengthOffset - 4;
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
+ contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
+ contents[attributeLengthOffset++] = (byte) attributeLength;
+ attributesNumber++;
+ } else {
+ contentsOffset = annotationAttributeOffset;
+ }
+ }
+ return attributesNumber;
+ }
+ /**
* EXTERNAL API
* Answer the actual bytes of the class file
*
}
}
+
+ private boolean isRuntimeInvisible(Annotation annotation) {
+ final TypeBinding annotationBinding = annotation.resolvedType;
+ if (annotationBinding == null) {
+ return false;
+ }
+ long metaTagBits = annotationBinding.getAnnotationTagBits();
+ if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
+ return true; // by default the retention is CLASS
+
+ return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationClassRetention;
+ }
+
+ private boolean isRuntimeVisible(Annotation annotation) {
+ final TypeBinding annotationBinding = annotation.resolvedType;
+ if (annotationBinding == null) {
+ return false;
+ }
+ long metaTagBits = annotationBinding.tagBits;
+ if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
+ return false; // by default the retention is CLASS
+
+ return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationRuntimeRetention;
+ }
+
/**
* INTERNAL USE-ONLY
* Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name
/**
* INTERNAL USE-ONLY
- * Search the line number corresponding to a specific position
- */
- public static final int searchLineNumber(
- int[] startLineIndexes,
- int position) {
- // this code is completely useless, but it is the same implementation than
- // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
- // if (startLineIndexes == null)
- // return 1;
- int length = startLineIndexes.length;
- if (length == 0)
- return 1;
- int g = 0, d = length - 1;
- int m = 0;
- while (g <= d) {
- m = (g + d) / 2;
- if (position < startLineIndexes[m]) {
- d = m - 1;
- } else
- if (position > startLineIndexes[m]) {
- g = m + 1;
- } else {
- return m + 1;
- }
- }
- if (position < startLineIndexes[m]) {
- return m + 1;
- }
- return m + 2;
- }
-
- /**
- * INTERNAL USE-ONLY
* This methods leaves the space for method counts recording.
*/
public void setForMethodInfos() {
methodCountOffset = contentsOffset;
contentsOffset += 2;
}
-
- /**
- * INTERNAL USE-ONLY
- * outputPath is formed like:
- * c:\temp\ the last character is a file separator
- * relativeFileName is formed like:
- * java\lang\String.class
- * @param generatePackagesStructure a flag to know if the packages structure has to be generated.
- * @param outputPath the output directory
- * @param relativeFileName java.lang.String
- * @param contents byte[]
- *
- */
- public static void writeToDisk(
- boolean generatePackagesStructure,
- String outputPath,
- String relativeFileName,
- byte[] contents)
- throws IOException {
-
- BufferedOutputStream output = null;
- if (generatePackagesStructure) {
- output = new BufferedOutputStream(
- new FileOutputStream(
- new File(buildAllDirectoriesInto(outputPath, relativeFileName))));
- } else {
- String fileName = null;
- char fileSeparatorChar = File.separatorChar;
- String fileSeparator = File.separator;
- // First we ensure that the outputPath exists
- outputPath = outputPath.replace('/', fileSeparatorChar);
- // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
- int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
- if (indexOfPackageSeparator == -1) {
- if (outputPath.endsWith(fileSeparator)) {
- fileName = outputPath + relativeFileName;
- } else {
- fileName = outputPath + fileSeparator + relativeFileName;
- }
- } else {
- int length = relativeFileName.length();
- if (outputPath.endsWith(fileSeparator)) {
- fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
- } else {
- fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
- }
- }
- output = new BufferedOutputStream(
- new FileOutputStream(
- new File(fileName)));
- }
- try {
- output.write(contents);
- } finally {
- output.flush();
- output.close();
- }
- }
}