/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.eval; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.internal.compiler.ClassFile; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; import org.eclipse.jdt.internal.compiler.util.Util; public class CodeSnippetClassFile extends ClassFile { /** * CodeSnippetClassFile constructor comment. * * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile * @param creatingProblemType boolean */ public CodeSnippetClassFile( org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding aType, org.eclipse.jdt.internal.compiler.ClassFile enclosingClassFile, boolean creatingProblemType) { /** * INTERNAL USE-ONLY This methods creates a new instance of the receiver. * * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding * @param enclosingClassFile org.eclipse.jdt.internal.compiler.codegen.ClassFile * @param creatingProblemType <CODE>boolean</CODE> */ this.referenceBinding= aType; initByteArrays(); // generate the magic numbers inside the header this.header[this.headerOffset++]= (byte)(0xCAFEBABEL >> 24); this.header[this.headerOffset++]= (byte)(0xCAFEBABEL >> 16); this.header[this.headerOffset++]= (byte)(0xCAFEBABEL >> 8); this.header[this.headerOffset++]= (byte)(0xCAFEBABEL >> 0); long targetVersion= this.targetJDK= this.referenceBinding.scope.compilerOptions().targetJDK; this.header[this.headerOffset++]= (byte)(targetVersion >> 8); // minor high this.header[this.headerOffset++]= (byte)(targetVersion >> 0); // minor low this.header[this.headerOffset++]= (byte)(targetVersion >> 24); // major high this.header[this.headerOffset++]= (byte)(targetVersion >> 16); // major low this.constantPoolOffset= this.headerOffset; this.headerOffset+= 2; this.constantPool= new ConstantPool(this); int accessFlags= aType.getAccessFlags(); if (!aType.isInterface()) { // class or enum accessFlags|= ClassFileConstants.AccSuper; } if (aType.isNestedType()) { if (aType.isStatic()) { // clear Acc_Static accessFlags&= ~ClassFileConstants.AccStatic; } if (aType.isPrivate()) { // clear Acc_Private and Acc_Public accessFlags&= ~(ClassFileConstants.AccPrivate | ClassFileConstants.AccPublic); } if (aType.isProtected()) { // clear Acc_Protected and set Acc_Public accessFlags&= ~ClassFileConstants.AccProtected; accessFlags|= ClassFileConstants.AccPublic; } } // clear Acc_Strictfp accessFlags&= ~ClassFileConstants.AccStrictfp; this.enclosingClassFile= enclosingClassFile; // now we continue to generate the bytes inside the contents array this.contents[this.contentsOffset++]= (byte)(accessFlags >> 8); this.contents[this.contentsOffset++]= (byte)accessFlags; int classNameIndex= this.constantPool.literalIndexForType(aType); this.contents[this.contentsOffset++]= (byte)(classNameIndex >> 8); this.contents[this.contentsOffset++]= (byte)classNameIndex; int superclassNameIndex; if (aType.isInterface()) { superclassNameIndex= this.constantPool.literalIndexForType(ConstantPool.JavaLangObjectConstantPoolName); } else { superclassNameIndex= (aType.superclass == null ? 0 : this.constantPool.literalIndexForType(aType.superclass)); } this.contents[this.contentsOffset++]= (byte)(superclassNameIndex >> 8); this.contents[this.contentsOffset++]= (byte)superclassNameIndex; ReferenceBinding[] superInterfacesBinding= aType.superInterfaces(); int interfacesCount= superInterfacesBinding.length; this.contents[this.contentsOffset++]= (byte)(interfacesCount >> 8); this.contents[this.contentsOffset++]= (byte)interfacesCount; for (int i= 0; i < interfacesCount; i++) { int interfaceIndex= this.constantPool.literalIndexForType(superInterfacesBinding[i]); this.contents[this.contentsOffset++]= (byte)(interfaceIndex >> 8); this.contents[this.contentsOffset++]= (byte)interfaceIndex; } this.produceAttributes= this.referenceBinding.scope.compilerOptions().produceDebugAttributes; this.creatingProblemType= creatingProblemType; if (this.targetJDK >= ClassFileConstants.JDK1_6) { this.codeStream= new StackMapFrameCodeStream(this); this.produceAttributes|= ClassFileConstants.ATTR_STACK_MAP_TABLE; } else if (this.targetJDK == ClassFileConstants.CLDC_1_1) { this.targetJDK= ClassFileConstants.JDK1_1; // put back 45.3 this.produceAttributes|= ClassFileConstants.ATTR_STACK_MAP; this.codeStream= new StackMapFrameCodeStream(this); } else { this.codeStream= new CodeStream(this); } // retrieve the enclosing one guaranteed to be the one matching the propagated flow info // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check) this.codeStream.maxFieldCount= aType.scope.outerMostClassScope().referenceType().maxFieldCount; } /** * 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 CodeSnippetClassFile(typeBinding, null, true); // inner attributes if (typeBinding.hasMemberTypes()) { // see bug 180109 ReferenceBinding[] members= typeBinding.memberTypes; for (int i= 0, l= members.length; i < l; i++) classFile.recordInnerClasses(members[i]); } // TODO (olivier) handle cases where a field cannot be generated (name too long) // TODO (olivier) handle too many methods // inner attributes if (typeBinding.isNestedType()) { classFile.recordInnerClasses(typeBinding); } TypeVariableBinding[] typeVariables= typeBinding.typeVariables(); for (int i= 0, max= typeVariables.length; i < max; i++) { TypeVariableBinding typeVariableBinding= typeVariables[i]; if ((typeVariableBinding.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { Util.recordNestedType(classFile, typeVariableBinding); } } // add its fields FieldBinding[] fields= typeBinding.fields(); if ((fields != null) && (fields != Binding.NO_FIELDS)) { 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 int problemsLength; CategorizedProblem[] problems= unitResult.getErrors(); if (problems == null) { problems= new CategorizedProblem[0]; } CategorizedProblem[] problemsCopy= new CategorizedProblem[problemsLength= problems.length]; System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); AbstractMethodDeclaration[] methodDecls= typeDeclaration.methods; if (methodDecls != 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, length= methodDecls.length; i < length; i++) { AbstractMethodDeclaration methodDecl= methodDecls[i]; MethodBinding method= methodDecl.binding; if (method == null || method.isConstructor()) continue; method.modifiers= ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract; classFile.addAbstractMethod(methodDecl, method); } } else { for (int i= 0, length= methodDecls.length; i < length; i++) { AbstractMethodDeclaration methodDecl= methodDecls[i]; MethodBinding method= methodDecl.binding; if (method == null) continue; if (method.isConstructor()) { classFile.addProblemConstructor(methodDecl, method, problemsCopy); } else if (method.isAbstract()) { classFile.addAbstractMethod(methodDecl, method); } else { classFile.addProblemMethod(methodDecl, method, problemsCopy); } } } // 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.createProblemType(memberType, unitResult); } } } classFile.addAttributes(); unitResult.record(typeBinding.constantPoolName(), classFile); } }